Improve implementation of Dropbox by using identity.launchWebAuthFlow api and get rid of web_accessible_resources
This commit is contained in:
parent
f926e16636
commit
0de1afcf98
|
@ -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>
|
|
|
@ -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';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Loading…
Reference in New Issue
Block a user