VulpesOS/assets/webapps/email.gaiamobile.org/js/cards/oauth2/fetch.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

136 lines
No EOL
5.1 KiB
JavaScript

define([
'require',
'query_string',
'services',
'cards'
], function (require) {
var queryString = require('query_string');
var services = require('services');
var cards = require('cards');
var oauthSecrets = services.oauth2;
var curOauthSecrets;
var redeemingCode = false;
var TIMEOUT_MS = 30 * 1000;
var redirectUri = 'http://localhost';
var deferred, p, oauthSettings;
function onBrowserComplete(message) {
var data = message.data;
if (message.type === 'oauth2Complete') {
if (!data.code) {
reset('reject', new Error('no code returned'));
return;
}
console.log('oauth redirect returned with code');
redeemingCode = true;
redeemCode(data.code).then(function (redeemed) {
var expiresInMS = parseInt(redeemed.expires_in, 10) * 1000;
var expireTimeMS = Date.now() + Math.max(0, expiresInMS - TIMEOUT_MS);
var result = {
status: 'success',
tokens: {
accessToken: redeemed.access_token,
refreshToken: redeemed.refresh_token,
expireTimeMS: expireTimeMS
},
secrets: curOauthSecrets
};
reset('resolve', result);
}, function (err) {
reset('reject', err);
});
} else {
reset('resolve', { status: 'cancel' });
}
}
function redeemCode(code) {
console.log('redeeming oauth code');
return new Promise(function (xhrResolve, xhrReject) {
var xhr = new XMLHttpRequest({ mozSystem: true });
xhr.open('POST', oauthSettings.tokenEndpoint, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.timeout = TIMEOUT_MS;
xhr.onload = function () {
if (xhr.status < 200 || xhr.status >= 300) {
console.error('token redemption failed', xhr.status, xhr.responseText);
xhrReject('status' + xhr.status);
} else {
try {
var data = JSON.parse(xhr.responseText);
console.log('oauth code redeemed. access_token? ' + !!data.access_token + ', refresh_token? ' + !!data.refresh_token);
xhrResolve(data);
} catch (ex) {
console.error('badly formed JSON response for token redemption:', xhr.responseText);
xhrReject(ex);
}
}
};
xhr.onerror = function (err) {
console.error('token redemption weird error:', err);
xhrReject(err);
};
xhr.ontimeout = function () {
console.error('token redemption timeout');
xhrReject('timeout');
};
var redemptionArgs = {
code: code,
client_id: curOauthSecrets.clientId,
client_secret: curOauthSecrets.clientSecret,
redirect_uri: redirectUri,
grant_type: 'authorization_code'
};
xhr.send(queryString.fromObject(redemptionArgs));
});
}
function reset(actionName, value) {
console.log('oauth2 fetch reset with action: ' + actionName);
var action = deferred[actionName];
deferred = p = null;
redeemingCode = false;
action(value);
}
return function oauth2Fetch(o2Settings, extraQueryObject) {
if (deferred) {
reset('reject', new Error('Multiple oauth calls, starting new one'));
}
p = new Promise(function (res, rej) {
deferred = {
resolve: res,
reject: rej
};
});
oauthSettings = o2Settings;
curOauthSecrets = undefined;
if (o2Settings.clientId && o2Settings.clientSecret) {
curOauthSecrets = {
clientId: o2Settings.clientId,
clientSecret: o2Settings.clientSecret
};
} else if (o2Settings.secretGroup) {
curOauthSecrets = oauthSecrets[o2Settings.secretGroup];
}
if (!curOauthSecrets) {
reset('reject', new Error('no secrets for group: ' + o2Settings.secretGroup));
return p;
}
var authEndpointQuery = {
client_id: curOauthSecrets.clientId,
redirect_uri: redirectUri,
response_type: 'code',
scope: o2Settings.scope,
max_auth_age: 0
};
var url = o2Settings.authEndpoint + '?' + queryString.fromObject(authEndpointQuery);
if (extraQueryObject) {
var extraArgs = queryString.fromObject(extraQueryObject);
if (extraArgs) {
url += '&' + extraArgs;
}
}
cards.pushCard('setup_oauth2', 'animate', {
url: url,
onBrowserComplete: onBrowserComplete
});
return p;
};
});