Improve implementation of Dropbox by using identity.launchWebAuthFlow api and get rid of web_accessible_resources

This commit is contained in:
Matheus Faustino 2018-06-09 12:49:14 -03:00
parent f926e16636
commit 0de1afcf98
4 changed files with 100 additions and 189 deletions

View File

@ -1,13 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OAuth Receiver</title>
<script src="/vendor/dropbox/dropbox.min.js"></script>
<script src="/js/dropbox-auth-receiver.js"></script>
</head>
<body>
</body>
</html>

View File

@ -1,61 +0,0 @@
'use strict';
/**
got from the old api
@see: https://github.com/dropbox/dropbox-sdk-js/blob/a88a138c0c3260c3537f30f94b003c1cf64f2fbd/examples/javascript/utils.js
*/
function parseQueryString(str) {
let ret = Object.create(null);
if (typeof str !== 'string') {
return ret;
}
str = str.trim().replace(/^(\?|#|&)/, '');
if (!str) {
return ret;
}
str.split('&').forEach(function (param) {
let parts = param.replace(/\+/g, ' ').split('=');
// Firefox (pre 40) decodes `%3D` to `=`
// https://github.com/sindresorhus/query-string/pull/37
let key = parts.shift();
let val = parts.length > 0 ? parts.join('=') : undefined;
key = decodeURIComponent(key);
// missing `=` should be `null`:
// http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
val = val === undefined ? null : decodeURIComponent(val);
if (ret[key] === undefined) {
ret[key] = val;
} else if (Array.isArray(ret[key])) {
ret[key].push(val);
} else {
ret[key] = [ret[key], val];
}
});
return ret;
}
window.onload = () => {
let data = {'dropbox_access_token': parseQueryString(location.hash).access_token};
/* this was the only way that worked in keeping a value from page to page with location.href */
/* tried localStorage, but didn't work :/ */
if (typeof browser !== 'undefined') {
browser.storage.local.set(data)
.then(() => {
window.location.href = '/manage.html';
});
} else if (chrome.storage) {
chrome.storage.local.set(data, () => {
window.location.href = '/manage.html';
});
}
}

View File

@ -11,142 +11,129 @@ const HTTP_STATUS_CANCEL = 499;
* tried localStorage, but didn't work :/ * tried localStorage, but didn't work :/
*/ */
function hasDropboxAccessToken() { function hasDropboxAccessToken() {
if (typeof browser !== 'undefined') { /* firefox */ return chromeLocal.getValue('dropbox_access_token');
return browser.storage.local.get('dropbox_access_token')
.then(item => {
return item.dropbox_access_token;
});
} else { /* chrome */
return new Promise((resolve, reject) => {
chrome.storage.local.get(['dropbox_access_token'], result => {
resolve(result.dropbox_access_token);
});
});
}
} }
function openDropboxOauthPage() { function requestDropboxAccessToken() {
let client = new Dropbox.Dropbox({clientId: DROPBOX_API_KEY}); const browserApi = typeof browser === 'undefined' ? chrome : browser;
let authUrl = client.getAuthenticationUrl(window.location.origin + DROPBOX_RECEIVER_HTML); const client = new Dropbox.Dropbox({clientId: DROPBOX_API_KEY});
const authUrl = client.getAuthenticationUrl(browserApi.identity.getRedirectURL());
window.location.href = authUrl; return browserApi.identity.launchWebAuthFlow({url: authUrl, interactive: true})
.then(urlReturned => {
const params = new URLSearchParams(new URL(urlReturned).hash.replace('#', '?'));
chromeLocal.setValue('dropbox_access_token', params.get('access_token'));
return params.get('access_token');
});
} }
function uploadFileDropbox(client, stylesText) { function uploadFileDropbox(client, stylesText) {
return client.filesUpload({path: '/' + FILENAME, contents: stylesText}); return client.filesUpload({path: '/' + FILENAME, contents: stylesText});
} }
$('#sync-dropbox-export').onclick = () => {
$('#sync-dropbox-export').onclick = async () => { hasDropboxAccessToken().then(token => {
let accessToken = await hasDropboxAccessToken(); if (typeof token === 'undefined') {
if (!accessToken) { return requestDropboxAccessToken();
openDropboxOauthPage();
return;
}
let client = new Dropbox.Dropbox({
clientId: DROPBOX_API_KEY,
accessToken: accessToken
});
/**
* check if the file exists, if exists, delete it before upload another
*/
client.filesDownload({path: '/' + FILENAME})
.then(responseGet => {
/** deletes file if user want to */
if (!confirm(t('overwriteFileExport'))) {
return Promise.reject({status: HTTP_STATUS_CANCEL});
} }
return client.filesDelete({path: '/' + FILENAME}); return token;
}) })
.then(responseDelete => { .then(token => {
const client = new Dropbox.Dropbox({
clientId: DROPBOX_API_KEY,
accessToken: token
});
return client.filesDownload({path: '/' + FILENAME})
.then(_ => {
/** deletes file if user want to */
if (!confirm(t('overwriteFileExport'))) {
return Promise.reject({status: HTTP_STATUS_CANCEL});
}
return client.filesDelete({path: '/' + FILENAME});
})
/** file deleted with success, get styles and create a file */ /** file deleted with success, get styles and create a file */
return API.getStyles().then(styles => JSON.stringify(styles, null, '\t')) .then(_ => API.getStyles().then(styles => JSON.stringify(styles, null, '\t')))
})
.then(stylesText => {
/** create file dropbox */ /** create file dropbox */
return uploadFileDropbox(client, stylesText); .then(stylesText => uploadFileDropbox(client, stylesText))
}) /** gives feedback to user */
.then(responseSave => { .then(_ => alert(t('exportSavedSuccess')))
alert(t('exportSavedSuccess')); /* handle not found cases and cancel action */
}) .catch(error => {
.catch(async error => { /* saving file first time */
/* saving file first time */ if (error.status === API_ERROR_STATUS_FILE_NOT_FOUND) {
if (error.status === API_ERROR_STATUS_FILE_NOT_FOUND) {
let stylesText = await API.getStyles().then(styles => JSON.stringify(styles, null, '\t'));
uploadFileDropbox(client, stylesText) API.getStyles()
.then(response => { .then(styles => JSON.stringify(styles, null, '\t'))
alert(t('exportSavedSuccess')); .then(stylesText => uploadFileDropbox(client, stylesText))
}) .then(_ => alert(t('exportSavedSuccess')))
.catch(err => { .catch(err => console.error(err));
console.error(error);
});
return; return;
} }
/* user cancelled the flow */ /* user cancelled the flow */
if (error.status === HTTP_STATUS_CANCEL) { if (error.status === HTTP_STATUS_CANCEL) {
return; return;
} }
console.error(error); console.error(error);
});
return;
}); });
}; };
$('#sync-dropbox-import').onclick = async () => { $('#sync-dropbox-import').onclick = () => {
let accessToken = await hasDropboxAccessToken(); hasDropboxAccessToken().then(token => {
if (!accessToken) { if (typeof token === 'undefined') {
openDropboxOauthPage(); return requestDropboxAccessToken();
return;
}
let client = new Dropbox.Dropbox({
clientId: DROPBOX_API_KEY,
accessToken: accessToken
});
client.filesDownload({path: '/' + FILENAME})
.then(response => {
let fileBlob = response.fileBlob;
/* it's based on the import-export.js */
const fReader = new FileReader();
fReader.onloadend = event => {
const text = event.target.result;
const maybeUsercss = !/^[\s\r\n]*\[/.test(text) &&
(text.includes('==UserStyle==') || /==UserStyle==/i.test(text));
(!maybeUsercss ?
importFromString(text) :
getOwnTab().then(tab => {
tab.url = URL.createObjectURL(new Blob([text], {type: 'text/css'}));
return API.installUsercss({direct: true, tab})
.then(() => URL.revokeObjectURL(tab.url));
})
);
};
fReader.readAsText(fileBlob, 'utf-8');
})
.catch(error => {
/* no file */
if (error.status === API_ERROR_STATUS_FILE_NOT_FOUND) {
alert(t('noFileToImport'));
return;
} }
console.error(err); return token;
}); })
.then(token => {
return; const client = new Dropbox.Dropbox({
clientId: DROPBOX_API_KEY,
accessToken: token
});
return client.filesDownload({path: '/' + FILENAME})
.then(response => {
const fileBlob = response.fileBlob;
/* it's based on the import-export.js */
const fReader = new FileReader();
fReader.onloadend = event => {
const text = event.target.result;
const maybeUsercss = !/^[\s\r\n]*\[/.test(text) &&
(text.includes('==UserStyle==') || /==UserStyle==/i.test(text));
(!maybeUsercss ?
importFromString(text) :
getOwnTab().then(tab => {
tab.url = URL.createObjectURL(new Blob([text], {type: 'text/css'}));
return API.installUsercss({direct: true, tab})
.then(() => URL.revokeObjectURL(tab.url));
})
);
};
fReader.readAsText(fileBlob, 'utf-8');
})
.catch(error => {
/* no file */
if (error.status === API_ERROR_STATUS_FILE_NOT_FOUND) {
alert(t('noFileToImport'));
return;
}
console.error(error);
});
});
}; };

View File

@ -17,6 +17,7 @@
"contextMenus", "contextMenus",
"storage", "storage",
"alarms", "alarms",
"identity",
"<all_urls>" "<all_urls>"
], ],
"background": { "background": {
@ -77,9 +78,6 @@
"js": ["content/install-hook-usercss.js"] "js": ["content/install-hook-usercss.js"]
} }
], ],
"web_accessible_resources": [
"/dropbox-oauth.html"
],
"browser_action": { "browser_action": {
"default_icon": { "default_icon": {
"16": "/images/icon/16w.png", "16": "/images/icon/16w.png",