From f2766b994cadc7c2e790ed8eb5830ce51ec7cb1d Mon Sep 17 00:00:00 2001 From: msramalho <19508417+msramalho@users.noreply.github.com> Date: Tue, 7 Mar 2023 22:29:32 +0000 Subject: [PATCH] fixing authentication + minor issues --- README.md | 4 +- source/html/options.html | 36 ----------------- source/js/background.js | 58 +++++++++++++++------------ source/js/options-storage.js | 2 +- source/js/options.js | 29 -------------- source/js/popup.js | 10 ----- source/js/utils.js | 19 --------- source/manifest.json | 6 +-- source/vue/Popup.vue | 78 ++++++++++++++++++------------------ source/vue/TaskItem.vue | 2 +- 10 files changed, 77 insertions(+), 167 deletions(-) delete mode 100644 source/html/options.html delete mode 100644 source/js/options.js delete mode 100644 source/js/utils.js diff --git a/README.md b/README.md index b33e44d..53ac8d4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Auto Archiver Extension -Chromium browser extension that connects to an API that calls [Belligncat's auto-archiver](https://github.com/bellingcat/auto-archiver). +Chromium browser extension that connects to an API that calls [Bellingcat's auto-archiver](https://github.com/bellingcat/auto-archiver). > Beta deployment: only authorized emails can use it. Available on [chrome web store](https://chrome.google.com/webstore/detail/auto-archiver-extension/ojcimmjndnlmmlgnjaeojoebaceokpdp) @@ -21,7 +21,7 @@ Using [web-ext](https://extensionworkshop.com/documentation/develop/getting-star 1. Run `npm run watch` to watch for file changes and build continuously 1. Run `npm install --global web-ext` (only only for the first time) 1. In another terminal, run `web-ext run -t chromium` -1. Check that the extension is loaded by opening the extension options ([in Firefox](media/extension_options_firefox.png) or [in Chrome](media/extension_options_chrome.png)). +1. Check that the extension is loaded by opening the extension options. diff --git a/source/html/options.html b/source/html/options.html deleted file mode 100644 index 03bdc70..0000000 --- a/source/html/options.html +++ /dev/null @@ -1,36 +0,0 @@ - diff --git a/source/js/background.js b/source/js/background.js index 5dc853d..eac21a3 100644 --- a/source/js/background.js +++ b/source/js/background.js @@ -1,18 +1,15 @@ -// Import './options-storage.js'; import optionsStorage from './options-storage.js'; import { getReasonPhrase } from 'http-status-codes'; -// const API_ENDPOINT = process.env.API_ENDPOINT || 'http://134.122.58.133:8004/tasks'; const API_ENDPOINT = process.env.API_ENDPOINT || 'http://localhost:8004/tasks'; console.log(`using API_ENDPOINT=${API_ENDPOINT}`) -const LOGIN_FAILED = `Could not login, make sure your google account email has been granted access by the developers.`; +const LOGIN_FAILED = `Please login before using this feature.`; chrome.runtime.onMessage.addListener(((r, s, sendResponse) => { processMessages(r, s) - //TODO: improve body .then(response => { console.log(`SUCCESS (${r.action}): ${JSON.stringify(response)}`) sendResponse({ status: "success", result: response }) @@ -74,12 +71,12 @@ function processMessages(request, sender) { getUrl(resolve, reject); break; } - case 'getProfileEmail': { - getProfileEmail(resolve, reject); + case 'oauthLogin': { + oauthLogin(resolve, reject, request.interactive); break; } - case 'oauthLogin': { - oauthLogin(resolve, reject); + case 'logout': { + logout(resolve, reject); break; } // No default @@ -99,28 +96,32 @@ function getUrl(resolve, reject) { }); } -function getProfileEmail(resolve, reject) { - chrome.identity.getProfileUserInfo({ accountStatus: 'ANY' }, async userInfo => { - resolve(userInfo); - //TODO: reject if bad user info? - }); -} -function oauthLogin(resolve, reject) { +function oauthLogin(resolve, reject, interactive) { try { - chrome.identity.getAuthToken({ interactive: true }, async accessToken => { - console.error(`GOT token ${accessToken}`); - resolve(true); + // force re-auth if interactive is needed + if (interactive) { + chrome.identity.clearAllCachedAuthTokens(); + } + chrome.identity.getAuthToken({ interactive: interactive }, async accessToken => { + console.warn(`GOT token ${accessToken}`); + if (accessToken === undefined) { resolve({ success: false, message: "Could not get access token." }); } + resolve({ success: true }); }); } catch (e) { - // reject(new Error(`LOGIN FAILED: ${e}`)); console.error(`LOGIN FAILED: ${e}`); - resolve(false); + resolve({ success: false, message: `Login failed: ${e}` }); } } + +function logout(resolve, reject) { + chrome.identity.clearAllCachedAuthTokens(); + resolve(true); +} + function archiveUrl(resolve, reject, optionalUrl) { - chrome.identity.getAuthToken({ interactive: true }, async accessToken => { + chrome.identity.getAuthToken({ interactive: false }, async accessToken => { if (accessToken == undefined) { reject(new Error(LOGIN_FAILED)); return; @@ -148,6 +149,7 @@ function submitUrlArchive(url, accessToken) { method: 'POST', headers: { 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}` }, body: JSON.stringify({ url, access_token: accessToken }), }) @@ -160,7 +162,7 @@ function submitUrlArchive(url, accessToken) { function checkTaskStatus(resolve, reject, task) { console.log('API: STATUS'); return new Promise((InnerResolve, innerReject) => { - chrome.identity.getAuthToken({ interactive: true }, async accessToken => { + chrome.identity.getAuthToken({ interactive: false }, async accessToken => { if (accessToken == undefined) { reject(new Error(LOGIN_FAILED)); return; @@ -169,6 +171,7 @@ function checkTaskStatus(resolve, reject, task) { method: 'GET', headers: { 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}` }, }) .then(getJsonOrError) @@ -192,7 +195,7 @@ function checkTaskStatus(resolve, reject, task) { function search(resolve, reject, url) { console.log('API: SEARCH'); - chrome.identity.getAuthToken({ interactive: true }, async accessToken => { + chrome.identity.getAuthToken({ interactive: false }, async accessToken => { if (accessToken == undefined) { reject(new Error(LOGIN_FAILED)); return; @@ -201,6 +204,7 @@ function search(resolve, reject, url) { method: 'GET', headers: { 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}` }, }) .then(getJsonOrError) @@ -211,7 +215,7 @@ function search(resolve, reject, url) { async function syncLocalTasks(resolve, reject) { console.log('API: SYNC'); - chrome.identity.getAuthToken({ interactive: true }, async accessToken => { + chrome.identity.getAuthToken({ interactive: false }, async accessToken => { if (accessToken == undefined) { reject(new Error(LOGIN_FAILED)); return; @@ -220,6 +224,7 @@ async function syncLocalTasks(resolve, reject) { method: 'GET', headers: { 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}` }, }) .then(getJsonOrError) @@ -242,7 +247,7 @@ async function syncLocalTasks(resolve, reject) { async function deleteTask(resolve, reject, taskId) { console.log('API: DELETE TASK'); - chrome.identity.getAuthToken({ interactive: true }, async accessToken => { + chrome.identity.getAuthToken({ interactive: false }, async accessToken => { if (accessToken == undefined) { reject(new Error(LOGIN_FAILED)); return; @@ -251,11 +256,12 @@ async function deleteTask(resolve, reject, taskId) { method: 'DELETE', headers: { 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}` }, }) .then(getJsonOrError) .then(async deleteOp => { - if(deleteOp.deleted){ + if (deleteOp.deleted) { const storage = await optionsStorage.getAll(); delete storage.archivedUrls[taskId]; await optionsStorage.set(storage); diff --git a/source/js/options-storage.js b/source/js/options-storage.js index 33d654c..0c99938 100644 --- a/source/js/options-storage.js +++ b/source/js/options-storage.js @@ -6,7 +6,7 @@ export default new OptionsSync({ errorMessage: "" }, migrations: [ - // OptionsSync.migrations.removeUnused, + OptionsSync.migrations.removeUnused, ], logging: true, storageType: "local" diff --git a/source/js/options.js b/source/js/options.js deleted file mode 100644 index 267b69c..0000000 --- a/source/js/options.js +++ /dev/null @@ -1,29 +0,0 @@ -// eslint-disable-next-line import/no-unassigned-import -// import 'webext-base-css'; -// import '../css/options.css'; - -// import optionsStorage from './options-storage.js'; - -// const rangeInputs = [...document.querySelectorAll('input[type="range"][name^="color"]')]; -// const numberInputs = [...document.querySelectorAll('input[type="number"][name^="color"]')]; -// const output = document.querySelector('.color-output'); - -// function updateOutputColor() { -// output.style.backgroundColor = `rgb(${rangeInputs[0].value}, ${rangeInputs[1].value}, ${rangeInputs[2].value})`; -// } - -// function updateInputField(event) { -// numberInputs[rangeInputs.indexOf(event.currentTarget)].value = event.currentTarget.value; -// } - -// for (const input of rangeInputs) { -// input.addEventListener('input', updateOutputColor); -// input.addEventListener('input', updateInputField); -// } - -// async function init() { -// await optionsStorage.syncForm('#options-form'); -// updateOutputColor(); -// } - -// init(); diff --git a/source/js/popup.js b/source/js/popup.js index 4876e29..b4a0cb0 100644 --- a/source/js/popup.js +++ b/source/js/popup.js @@ -6,17 +6,7 @@ import 'material-design-icons/iconfont/material-icons.css'; const app = createApp(Popup); app.mount('#app'); -// Import browser from 'webextension-polyfill'; -// import optionsStorage from './options-storage.js'; - document.addEventListener('DOMContentLoaded', async () => { - // TODO: uncomment if using options - // listenForOptionsClick(); M.Tooltip.init(document.querySelectorAll('.tooltipped'), { enterDelay: 500 }); // enable tooltips }); -// Function listenForOptionsClick() { -// document.querySelector('#optionsBtn').addEventListener('click', () => { -// browser.runtime.openOptionsPage(); -// }); -// } diff --git a/source/js/utils.js b/source/js/utils.js deleted file mode 100644 index 4257e2e..0000000 --- a/source/js/utils.js +++ /dev/null @@ -1,19 +0,0 @@ -// /** -// * -// * -// */ -// export async function callBackground(parameters) { -// try { -// const answer = await chrome.runtime.sendMessage(parameters); -// if (answer.status == "error") { -// console.error(`error: ${answer.result}`) -// //TODO: modal/errors -// return null; -// } else { -// return answer.result; -// } -// } catch (e) { -// console.error(e); -// return null; -// } -// } \ No newline at end of file diff --git a/source/manifest.json b/source/manifest.json index 86ee9e9..962079a 100644 --- a/source/manifest.json +++ b/source/manifest.json @@ -1,6 +1,6 @@ { "name": "Auto-archiver extension", - "version": "0.0.7", + "version": "0.0.8", "description": "A gateway to effective archiving of online content, including behind private platforms. ", "homepage_url": "https://github.com/bellingcat/auto-archiver-extension", "manifest_version": 3, @@ -27,10 +27,6 @@ "default_popup": "html/popup.html" }, "content_scripts": [], - "options_ui": { - "browser_style": true, - "page": "html/options.html" - }, "oauth2": { "client_id": "572076445849-4cb2a8be1nfi46l80jm741k56s7cjkd0.apps.googleusercontent.com", "scopes": ["https://www.googleapis.com/auth/userinfo.email"] diff --git a/source/vue/Popup.vue b/source/vue/Popup.vue index 67fe0ac..9159673 100644 --- a/source/vue/Popup.vue +++ b/source/vue/Popup.vue @@ -1,5 +1,5 @@