From ebd344bd47dfdbde9a9c5768580d3d3e266f502d Mon Sep 17 00:00:00 2001 From: Andrew Nesbitt Date: Thu, 25 Nov 2021 14:24:20 +0000 Subject: [PATCH 1/4] WIP new login flow --- manifest.json | 5 ++- octobox.css | 18 +++++++++ octobox.js | 108 ++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 108 insertions(+), 23 deletions(-) diff --git a/manifest.json b/manifest.json index 83ab3f4..0bf1e47 100644 --- a/manifest.json +++ b/manifest.json @@ -15,13 +15,14 @@ "content_scripts": [ { - "matches": ["*://*.github.com/*"], + "matches": ["*://*.github.com/*", "*://octobox.io/*"], "js": ["octobox.js"], "css": ["octobox.css"] } ], "permissions": [ - "*://octobox.io/*" + "*://octobox.io/*", + "storage" ] } diff --git a/octobox.css b/octobox.css index 7065048..7b6427f 100644 --- a/octobox.css +++ b/octobox.css @@ -1,3 +1,21 @@ +#octobox-login{ + background-color: var(--color-canvas-default); + border-top: solid 1px var(--color-border-muted); + bottom: 0; + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); + display: block; + padding: 10px 20px 10px 48px; + position: fixed; + left: 10px; + text-align: center; + z-index: 99999; + border-top-right-radius: 5px; + border-top-left-radius: 5px; + background-image: url(icons/infinitacle.svg); + background-repeat: no-repeat; + background-position: center left 10px; +} + .octobox { background-color: var(--color-canvas-default); border-top: solid 1px var(--color-border-muted); diff --git a/octobox.js b/octobox.js index 02825fd..9a5f426 100644 --- a/octobox.js +++ b/octobox.js @@ -1,6 +1,8 @@ // TODO support github enterprise // TODO support self-hosted octobox instances +var api_token + function isActionablePage() { // check if loaded on an individual issue or pull request page // *owner*/*name*/issues/*number* @@ -10,35 +12,71 @@ function isActionablePage() { return parts.length > 4 && ['issues', 'pull'].includes(parts[3]) } +function loginPage() { + // is current page octobox.io/extension + window.location.host == 'octobox.io' && window.location.pathname == '/extension' +} + function activate() { - if(isActionablePage()){ - authenticate() - lookup() + if(loginPage()){ + console.log('logging in') + // grab token from page and save in storage + } else {if(isActionablePage()){ + var loggedin = authenticate() + console.log('loggedin', loggedin) + if(loggedin){ + var octoboxlogin = document.getElementById('octobox-login'); + + if(octoboxlogin){ + octoboxlogin.remove() + } + lookup() + } else { + renderLoginBtn() + } } else { var octoboxRoot = document.getElementById('octobox-root'); if(octoboxRoot){ octoboxRoot.remove() } - } + }} } function authenticate() { - // TODO handle failure properly - fetch('https://octobox.io/users/profile.json') - .then(resp => resp.json()) - .then( json => console.log('Octobox login:',json)) - .catch( error => console.error(error)) + // load token from storage + var api_token = chrome.storage.local.get('apiToken'); + + if(api_token != null){ + // prompt for login + return false + } else { + try{ + fetch('https://octobox.io/api/users/profile.json', { + headers:{ + 'Authorization': `Bearer ${api_token}` + } + }) + .then(resp => resp.json()) + .then( json => console.log('Octobox login:',json)) + .catch( error => console.error(error)) + // return true + } catch { + // prompt for login + return false + } + } } function markAsRead(notification) { if(!notification.unread){ return } - fetch('https://octobox.io/notifications/mark_read_selected.json?id='+notification.id, { + fetch('https://octobox.io/api/notifications/mark_read_selected.json?id='+notification.id, { method: "POST", headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', - 'X-Octobox-API': 'true' + 'X-Octobox-API': 'true', + 'Authorization': `Bearer ${api_token}` } }) .then( resp => console.log('notification marked as read', resp)) @@ -46,7 +84,10 @@ function markAsRead(notification) { } function lookup() { - fetch('https://octobox.io/notifications/lookup?url='+window.location) + fetch('https://octobox.io/api/notifications/lookup?url='+window.location, { + headers:{ + 'Authorization': `Bearer ${api_token}` + }}) .then(resp => resp.json()) .then(async json => { render(json) @@ -72,7 +113,10 @@ async function loadNext(notification) { params = { per_page: 1 } } - var response = await fetch('https://octobox.io/notifications.json?'+ new URLSearchParams(params)) + var response = await fetch('https://octobox.io/api/notifications.json?'+ new URLSearchParams(params), { + headers:{ + 'Authorization': `Bearer ${api_token}` + }}) var json = await response.json() var res = { @@ -104,12 +148,13 @@ async function loadNext(notification) { function toggleStar(notification) { // TODO allow starring even if notification is null - fetch('https://octobox.io/notifications/'+notification.id+'/star', { + fetch('https://octobox.io/api/notifications/'+notification.id+'/star', { method: "POST", headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', - 'X-Octobox-API': 'true' + 'X-Octobox-API': 'true', + 'Authorization': `Bearer ${api_token}` } }) .then( resp => { @@ -120,12 +165,13 @@ function toggleStar(notification) { } function archive(notification) { - fetch('https://octobox.io/notifications/archive_selected.json?id='+notification.id, { + fetch('https://octobox.io/api/notifications/archive_selected.json?id='+notification.id, { method: "POST", headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', - 'X-Octobox-API': 'true' + 'X-Octobox-API': 'true', + 'Authorization': `Bearer ${api_token}` } }) .then( resp => { @@ -141,12 +187,13 @@ function archive(notification) { } function unarchive(notification) { - fetch('https://octobox.io/notifications/archive_selected.json?value=false&id='+notification.id, { + fetch('https://octobox.io/api/notifications/archive_selected.json?value=false&id='+notification.id, { method: "POST", headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', - 'X-Octobox-API': 'true' + 'X-Octobox-API': 'true', + 'Authorization': `Bearer ${api_token}` } }) .then( resp => { @@ -157,12 +204,13 @@ function unarchive(notification) { } function mute(notification) { - fetch('https://octobox.io/notifications/mute_selected.json?id='+notification.id, { + fetch('https://octobox.io/api/notifications/mute_selected.json?id='+notification.id, { method: "POST", headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', - 'X-Octobox-API': 'true' + 'X-Octobox-API': 'true', + 'Authorization': `Bearer ${api_token}` } }) .then( resp => { @@ -180,6 +228,24 @@ function subscribe(notification) { // TODO octobox.io doesn't know how to subscribe to something yet } +function renderLoginBtn() { + var octoboxlogin = document.getElementById('octobox-login'); + if(octoboxlogin){ + // already there + // TODO update link return_to param with current page + } else { + var octoboxlogin = document.createElement("div"); + octoboxlogin.setAttribute("id", "octobox-login"); + document.body.appendChild(octoboxlogin); + + var link = document.createElement("a") + link.innerText = 'Log into Octobox' + link.setAttribute("href", `https://octobox.io/extension?return_to=${window.location}`); + + octoboxlogin.append(link) + } +} + async function render(notification) { var nextNotification = await loadNext(notification) From c5cfb344429c8470257ec9f6975ee6458df12109 Mon Sep 17 00:00:00 2001 From: Andrew Nesbitt Date: Thu, 25 Nov 2021 16:47:11 +0000 Subject: [PATCH 2/4] Working login for chrome+ff --- octobox.js | 68 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/octobox.js b/octobox.js index 9a5f426..64a3c90 100644 --- a/octobox.js +++ b/octobox.js @@ -12,60 +12,59 @@ function isActionablePage() { return parts.length > 4 && ['issues', 'pull'].includes(parts[3]) } -function loginPage() { +function isloginPage() { // is current page octobox.io/extension window.location.host == 'octobox.io' && window.location.pathname == '/extension' } -function activate() { - if(loginPage()){ - console.log('logging in') - // grab token from page and save in storage - } else {if(isActionablePage()){ - var loggedin = authenticate() - console.log('loggedin', loggedin) - if(loggedin){ - var octoboxlogin = document.getElementById('octobox-login'); - - if(octoboxlogin){ - octoboxlogin.remove() +async function activate() { + if(isActionablePage()){ + authenticate(function(loggedin) { + console.log('loggedin', loggedin) + if(loggedin){ + var octoboxlogin = document.getElementById('octobox-login'); + + if(octoboxlogin){ + octoboxlogin.remove() + } + lookup() + } else { + renderLoginBtn() } - lookup() - } else { - renderLoginBtn() - } + }) } else { var octoboxRoot = document.getElementById('octobox-root'); if(octoboxRoot){ octoboxRoot.remove() } - }} + } + // TODO toggle display of sections on extension page } -function authenticate() { +async function authenticate(cb) { // load token from storage - var api_token = chrome.storage.local.get('apiToken'); - - if(api_token != null){ + chrome.storage.local.get('apiToken', async function(data) { + api_token = data.apiToken + console.log(api_token) + if(api_token == null){ // prompt for login - return false + cb(false) } else { try{ - fetch('https://octobox.io/api/users/profile.json', { + var resp = await fetch('https://octobox.io/api/users/profile.json', { headers:{ 'Authorization': `Bearer ${api_token}` } }) - .then(resp => resp.json()) - .then( json => console.log('Octobox login:',json)) - .catch( error => console.error(error)) - // return true + var json = await resp.json() + console.log('Octobox login:',json) + cb(true) } catch { - // prompt for login - return false + cb(false) } } + }) } function markAsRead(notification) { @@ -401,3 +400,12 @@ document.addEventListener('pjax:end', () => { document.addEventListener('pjax:popstate', () => { activate() }); + +document.addEventListener('octobox:enable', (event) => { + console.log('octobox', event.detail) + chrome.storage.local.set({ + apiToken: event.detail.api_token + }, function() { + window.location.replace(event.detail.return_to) + }) +}); From 17a203d92784f986ade79fd7a6447972498a441d Mon Sep 17 00:00:00 2001 From: Andrew Nesbitt Date: Thu, 25 Nov 2021 16:58:08 +0000 Subject: [PATCH 3/4] add todo --- octobox.js | 1 + 1 file changed, 1 insertion(+) diff --git a/octobox.js b/octobox.js index 64a3c90..af7bed9 100644 --- a/octobox.js +++ b/octobox.js @@ -58,6 +58,7 @@ async function authenticate(cb) { } }) var json = await resp.json() + // TODO if unauthorized, clear apiToken from storage console.log('Octobox login:',json) cb(true) } catch { From fc439df8164623e8abf83dfc6505c20231028317 Mon Sep 17 00:00:00 2001 From: Andrew Nesbitt Date: Fri, 26 Nov 2021 11:38:47 +0000 Subject: [PATCH 4/4] clear stored api token if it's invalid --- octobox.js | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/octobox.js b/octobox.js index af7bed9..450aa55 100644 --- a/octobox.js +++ b/octobox.js @@ -1,6 +1,3 @@ -// TODO support github enterprise -// TODO support self-hosted octobox instances - var api_token function isActionablePage() { @@ -14,13 +11,12 @@ function isActionablePage() { function isloginPage() { // is current page octobox.io/extension - window.location.host == 'octobox.io' && window.location.pathname == '/extension' + return window.location.host == 'octobox.io' && window.location.pathname == '/extension' } async function activate() { if(isActionablePage()){ authenticate(function(loggedin) { - console.log('loggedin', loggedin) if(loggedin){ var octoboxlogin = document.getElementById('octobox-login'); @@ -38,17 +34,27 @@ async function activate() { if(octoboxRoot){ octoboxRoot.remove() } + + if(isloginPage()){ + authenticate(function(loggedin) { + var installbox = document.getElementById('install-extension'); + installbox.classList.add('d-none') + if(loggedin){ + var installedbox = document.getElementById('installed-extension'); + installedbox.classList.remove('d-none') + } else { + var loginbox = document.getElementById('login-extension'); + loginbox.classList.remove('d-none') + } + }) + } } - // TODO toggle display of sections on extension page } async function authenticate(cb) { - // load token from storage - chrome.storage.local.get('apiToken', async function(data) { + chrome.storage.local.get('apiToken', async function(data) { api_token = data.apiToken - console.log(api_token) if(api_token == null){ - // prompt for login cb(false) } else { try{ @@ -58,9 +64,13 @@ async function authenticate(cb) { } }) var json = await resp.json() - // TODO if unauthorized, clear apiToken from storage - console.log('Octobox login:',json) - cb(true) + if (json.error){ + chrome.storage.local.remove('apiToken', function() { + cb(false) + }) + } else { + cb(true) + } } catch { cb(false) } @@ -403,7 +413,6 @@ document.addEventListener('pjax:popstate', () => { }); document.addEventListener('octobox:enable', (event) => { - console.log('octobox', event.detail) chrome.storage.local.set({ apiToken: event.detail.api_token }, function() {