lavender/test-client/pop2.js

179 lines
6.8 KiB
JavaScript

/* Simple OAuth 2.0 Client flow library
Author: MrMelon54, timdream
Usage:
POP2.init(client_id, scope)
Initialize the library.
redirect_uri is the current page (window.location.href).
This function should be put before Analytics so that the second click won't result a page view register.
POP2.getToken(callback)
Send access token to the callback function as the first argument.
If not logged in this triggers login popup and execute login after logged in.
Be sure to call this function in user-triggered event (such as click) to prevent popup blocker.
If not sure do use isLoggedIn() below to check first.
POP2.isLoggedIn()
boolean
*/
"use strict";
(function (w) {
const windowName = 'pop2_oauth2_login_popup';
if (window.name === windowName) {
if (
window.opener &&
window.opener.POP2
) {
if (window.location.hash.indexOf('access_token') !== -1) {
window.opener.POP2.receiveToken(
window.location.hash.replace(/^.*access_token=([^&]+).*$/, '$1'),
parseInt(window.location.hash.replace(/^.*expires_in=([^&]+).*$/, '$1'))
);
}
if (window.location.search.indexOf('error=')) {
window.opener.POP2.receiveToken('ERROR');
}
}
window.close();
}
function popupCenterScreen(url, title, w, h) {
const top = (screen.availHeight - h) / 4, left = (screen.availWidth - w) / 2;
return openWindow(url, title, `scrollbars=yes,width=${w},height=${h},top=${top},left=${left}`);
}
function openWindow(url, winnm, options) {
const wTop = firstAvailableValue([window.screen.availTop, window.screenY, window.screenTop, 0]);
const wLeft = firstAvailableValue([window.screen.availLeft, window.screenX, window.screenLeft, 0]);
let top = "0",
left = "0",
result;
if ((result = /top=(\d+)/g.exec(options))) top = parseInt(result[1]);
if ((result = /left=(\d+)/g.exec(options))) left = parseInt(result[1]);
if (options) {
options = options.replace("top=" + top, "top=" + (parseInt(top) + wTop));
options = options.replace("left=" + left, "left=" + (parseInt(left) + wLeft));
w = window.open(url, winnm, options);
} else w = window.open(url, winnm);
return w;
}
function firstAvailableValue(arr) {
for (let i = 0; i < arr.length; i++)
if (typeof arr[i] != 'undefined')
return arr[i];
}
let client_endpoint,
client_id,
scope = '',
redirect_uri = window.location.href.substr(0, window.location.href.length - window.location.hash.length).replace(/#$/, ''),
access_token = localStorage.getItem("pop2_access_token"),
callbackWaitForToken,
w_width = 400,
w_height = 360;
w.POP2 = {
// init
init: function (f_client_endpoint, f_client_id, f_scope, width, height) {
if (!f_client_endpoint) return false;
if (!f_client_id) return false;
client_endpoint = f_client_endpoint;
client_id = f_client_id;
if (f_scope) scope = f_scope;
if (width) w_width = width;
if (height) w_height = height;
},
// receive token from popup
receiveToken: function (token, expires_in) {
if (token !== 'ERROR') {
access_token = token;
localStorage.setItem("pop2_access_token", access_token);
if (callbackWaitForToken) callbackWaitForToken(access_token);
setTimeout(
function () {
access_token = undefined;
localStorage.removeItem("pop2_access_token");
},
expires_in * 1000
);
} else if (token === false) {
callbackWaitForToken = undefined;
}
},
// boolean, indicate logged in or not
isLoggedIn: function () {
return !!access_token;
},
// pass the access token to callback
// if not logged in this triggers login popup;
// use isLoggedIn to check login first to prevent popup blocker
getToken: function (callback) {
if (!client_id || !redirect_uri || !scope) {
alert('You need init() first. Check the program flow.');
return false;
}
if (!access_token) {
callbackWaitForToken = callback;
popupCenterScreen(
client_endpoint
+ '?response_type=token'
+ '&redirect_uri=' + encodeURIComponent(redirect_uri)
+ '&scope=' + encodeURIComponent(scope)
+ '&client_id=' + encodeURIComponent(client_id),
windowName,
w_width,
w_height
);
} else {
return callback(access_token);
}
},
clientRequest: function (resource, options, refresh = false) {
const sendRequest = function () {
options.credentials = 'include';
if (!options.headers) options.headers = {};
options.headers['Authorization'] = 'Bearer ' + access_token;
return new Promise(function (res, rej) {
fetch(resource, options).then(function (x) {
if (x.status >= 200 && x.status < 300) res(x);
else rej(x);
}).catch(function (x) {
rej(["failed to send request", x]);
});
});
};
const resendRequest = function () {
return new Promise(function (res, rej) {
access_token = undefined;
w.POP2.getToken(function () {
sendRequest().then(function (x) {
res(x);
}).catch(function (x) {
rej(["failed to resend request", x]);
});
});
});
};
if (!refresh) return sendRequest();
else {
return new Promise(function (res, rej) {
sendRequest().then(function (x) {
res(x);
}).catch(function () {
resendRequest().then(function (x) {
res(x);
}).catch(function (x) {
rej(x);
});
});
});
}
}
};
})(window);