Add: token flow

This commit is contained in:
eight 2019-09-28 00:07:58 +08:00
parent bd6dd4b917
commit b4f0ca1549
2 changed files with 47 additions and 25 deletions

View File

@ -5,8 +5,8 @@
const tokenManager = (() => { const tokenManager = (() => {
const launchWebAuthFlow = promisify(chrome.identity.launchWebAuthFlow.bind(chrome.identity)); const launchWebAuthFlow = promisify(chrome.identity.launchWebAuthFlow.bind(chrome.identity));
const AUTH = { const AUTH = {
// always use code flow?
dropbox: { dropbox: {
flow: 'token',
clientId: 'zg52vphuapvpng9', clientId: 'zg52vphuapvpng9',
authURL: 'https://www.dropbox.com/oauth2/authorize', authURL: 'https://www.dropbox.com/oauth2/authorize',
tokenURL: 'https://api.dropboxapi.com/oauth2/token' tokenURL: 'https://api.dropboxapi.com/oauth2/token'
@ -15,12 +15,6 @@ const tokenManager = (() => {
return {getToken, revokeToken, getClientId}; return {getToken, revokeToken, getClientId};
function parseSearchParams(url) {
// TODO: remove .replace(/^\?/, '') when minimum_chrome_version >= 52 (https://crbug.com/601425)
const search = new URL(url).search;
return new URLSearchParams(search[0] === '?' ? search.slice(1) : search);
}
function getClientId(name) { function getClientId(name) {
return AUTH[name].clientId; return AUTH[name].clientId;
} }
@ -59,37 +53,65 @@ const tokenManager = (() => {
return Promise.reject(new Error('not implemented yet')); return Promise.reject(new Error('not implemented yet'));
} }
function stringifyQuery(obj) {
const search = new URLSearchParams();
for (const key of Object.keys(obj)) {
search.set(key, obj[key]);
}
return search.toString();
}
function authUser(name, k) { function authUser(name, k) {
const provider = AUTH[name]; const provider = AUTH[name];
const state = Math.random().toFixed(8).slice(2); const state = Math.random().toFixed(8).slice(2);
const query = {
response_type: provider.flow,
client_id: provider.clientId,
redirect_uri: chrome.identity.getRedirectURL(),
state
};
const url = `${provider.authURL}?${stringifyQuery(query)}`;
return launchWebAuthFlow({ return launchWebAuthFlow({
url: url,
`${provider.authURL}?response_type=code&redirect_uri=${chrome.identity.getRedirectURL()}` +
`&state=${state}&client_id=${provider.clientId}`,
interactive: true interactive: true
}) })
.then(url => { .then(url => {
const params = parseSearchParams(url); const params = new URLSearchParams(
provider.flow === 'token' ?
new URL(url).hash.slice(1) :
new URL(url).search.slice(1)
);
if (params.get('state') !== state) { if (params.get('state') !== state) {
throw new Error(`unexpected state: ${params.get('state')}, expected: ${state}`); throw new Error(`unexpected state: ${params.get('state')}, expected: ${state}`);
} }
if (provider.flow === 'token') {
const obj = {};
for (const [key, value] of params.entries()) {
obj[key] = value;
}
return obj;
}
const code = params.get('code'); const code = params.get('code');
return fetch(provider.tokenURL, { return fetch(provider.tokenURL, {
method: 'POST',
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded' 'Content-Type': 'application/json'
}, },
body: body: JSON.stringify({
`code=${code}&grant_type=authorization_code&client_id=${provider.clientId}` + code,
`&redirect_uri=${chrome.identity.getRedirectURL()}` grant_type: 'authorization_code',
}); client_id: provider.clientId,
}) redirect_uri: chrome.identity.getRedirectURL()
.then(r => { })
if (r.ok) { })
return r.json(); .then(r => {
} if (r.ok) {
return r.text() return r.json();
.then(body => { }
throw new Error(`failed to fetch (${r.status}): ${body}`); return r.text()
.then(body => {
throw new Error(`failed to fetch (${r.status}): ${body}`);
});
}); });
}) })
.then(result => .then(result =>

File diff suppressed because one or more lines are too long