75 lines
2.5 KiB
JavaScript
75 lines
2.5 KiB
JavaScript
|
import { Map } from 'immutable';
|
||
|
import { trim, trimEnd } from 'lodash';
|
||
|
import { randomStr } from 'Lib/randomGenerator';
|
||
|
import history from 'Routing/history';
|
||
|
|
||
|
function createNonce() {
|
||
|
const nonce = randomStr();
|
||
|
window.sessionStorage.setItem("netlify-cms-auth", JSON.stringify({ nonce }));
|
||
|
return nonce;
|
||
|
}
|
||
|
|
||
|
function validateNonce(check) {
|
||
|
const auth = window.sessionStorage.getItem("netlify-cms-auth");
|
||
|
const valid = auth && JSON.parse(auth).nonce;
|
||
|
window.localStorage.removeItem("netlify-cms-auth");
|
||
|
return (check === valid);
|
||
|
}
|
||
|
|
||
|
export default class ImplicitAuthenticator {
|
||
|
constructor(config = {}) {
|
||
|
const baseURL = trimEnd(config.base_url, '/');
|
||
|
const authEndpoint = trim(config.auth_endpoint, '/');
|
||
|
this.auth_url = `${ baseURL }/${ authEndpoint }`;
|
||
|
this.appID = config.app_id;
|
||
|
}
|
||
|
|
||
|
authenticate(options, cb) {
|
||
|
if (
|
||
|
document.location.protocol !== "https:"
|
||
|
// TODO: Is insecure localhost a bad idea as well? I don't think it is, since you are not actually
|
||
|
// sending the token over the internet in this case, assuming the auth URL is secure.
|
||
|
&& (document.location.hostname !== "localhost" && document.location.hostname !== "127.0.0.1")
|
||
|
) {
|
||
|
return cb(new Error("Cannot authenticate over insecure protocol!"));
|
||
|
}
|
||
|
|
||
|
const authURL = new URL(this.auth_url);
|
||
|
authURL.searchParams.set('client_id', this.appID);
|
||
|
authURL.searchParams.set('redirect_uri', document.location.origin + document.location.pathname);
|
||
|
authURL.searchParams.set('response_type', 'token');
|
||
|
authURL.searchParams.set('scope', options.scope);
|
||
|
authURL.searchParams.set('state', createNonce());
|
||
|
|
||
|
document.location.assign(authURL.href);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Complete authentication if we were redirected back to from the provider.
|
||
|
*/
|
||
|
completeAuth(cb) {
|
||
|
const hashParams = new URLSearchParams(document.location.hash.replace(/^#?\/?/, ''));
|
||
|
if (!hashParams.has("access_token") && !hashParams.has("error")) {
|
||
|
return;
|
||
|
}
|
||
|
// Remove tokens from hash so that token does not remain in browser history.
|
||
|
history.replace('/');
|
||
|
|
||
|
const params = Map(hashParams.entries());
|
||
|
|
||
|
const validNonce = validateNonce(params.get('state'));
|
||
|
if (!validNonce) {
|
||
|
return cb(new Error("Invalid nonce"));
|
||
|
}
|
||
|
|
||
|
if (params.has('error')) {
|
||
|
return cb(new Error(`${ params.get('error') }: ${ params.get('error_description') }`));
|
||
|
}
|
||
|
|
||
|
if (params.has('access_token')) {
|
||
|
const { access_token: token, ...data } = params.toJS();
|
||
|
cb(null, { token, ...data });
|
||
|
}
|
||
|
}
|
||
|
}
|