Skip to content

Commit

Permalink
Inline panda session (#181)
Browse files Browse the repository at this point in the history
* panda-session has been archived, but we are still using it, so bringing that code into the repo

* linting

* import local panda session

* correct panda import please!
  • Loading branch information
alinaboghiu authored Jul 5, 2023
1 parent da6ce1a commit 159eddb
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 18 deletions.
28 changes: 14 additions & 14 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
"jquery-ui": "github:jquery/jquery-ui@1.11.4",
"knockout": "npm:knockout@3.4.0",
"numeral": "npm:numeral@1.5.3",
"panda-session": "github:guardian/panda-session@0.1.6",
"raven-js": "npm:raven-js@2.3.0",
"text": "github:systemjs/plugin-text@0.0.7",
"underscore": "npm:underscore@1.8.3"
Expand Down
1 change: 0 additions & 1 deletion public/src/js/jspm-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ System.config({
"jquery-ui": "github:jquery/jquery-ui@1.11.4",
"knockout": "npm:knockout@3.4.0",
"numeral": "npm:numeral@1.5.3",
"panda-session": "github:guardian/panda-session@0.1.6",
"raven-js": "npm:raven-js@2.3.0",
"text": "github:systemjs/plugin-text@0.0.7",
"underscore": "npm:underscore@1.8.3",
Expand Down
2 changes: 1 addition & 1 deletion public/src/js/utils/oauth-session.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {CONST} from 'modules/vars';
import * as panda from 'panda-session';
import * as panda from './panda-session';

function locationRedirect() {
window.location = '/logout';
Expand Down
115 changes: 115 additions & 0 deletions public/src/js/utils/panda-session.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
export class ReEstablishTimeout extends Error {}
export class GoogleAuthException extends Error {}

class NotReadyException extends Error {}

export const reEstablishSession = oneAtATime(reEstablishSessionImpl);


function reEstablishSessionImpl(loginUrl, maxWait) {
var iframe = createIframe(loginUrl);
var timeout = delay(maxWait).then(() => { throw new ReEstablishTimeout; });
var reEstablished = waitForIframe(iframe, timeout);

loadIframe(iframe);
return Promise.race([reEstablished, timeout]).then(
() => { unloadIframe(iframe); },
e => { unloadIframe(iframe); throw e; }
);
}


/* Helpers to observe the iframe */

function waitForIframe(iframe, timeout) {
return new Promise((resolve) => {
iframe.addEventListener('load', resolve);
}).then(() => {
return waitForLocation(iframe, timeout);
});
}

function waitForLocation(iframe, timeout) {
var throttleDelay = 50; // ms

return tryReadingIframeLocation(iframe).
catch(error => {
if (error instanceof NotReadyException) {
// Race with timeout which rejects the promise and breaks the
// infinite loop
return Promise.race([delay(throttleDelay), timeout]).
then(() => waitForLocation(iframe, timeout));
} else {
return Promise.reject(error);
}
});
}

function tryReadingIframeLocation(iframe) {
return new Promise((resolve, reject) => {
try {
// When logged out, google auth refuses to load in an iframe by setting the X-Frame-Options header
// we can sort of detect this by checking the location of the iframe
// if the contentDocument object cannot be accessed, its due to a security error.
// security error will occur when the frame is on a different origin

// Heuristic to detect google auth error in the iframe document
const textContent = iframe.contentDocument.body.textContent;
if (textContent.indexOf('google-auth-exception') !== -1) {
reject(new GoogleAuthException(textContent));
} else {
resolve(iframe.contentDocument.location);
}
} catch (e) {
reject(new NotReadyException);
}
});
}


/* Helpers to manage the lifecycle of the iframe in the DOM */

function createIframe(loginUrl) {
var iframe = document.createElement('iframe');
iframe.classList.add('panda-session-iframe');
// The re-auth iframe should not be shown
iframe.style.display = 'none';

iframe.src = loginUrl;
return iframe;
}

function loadIframe(iframe) {
document.body.appendChild(iframe);
}

function unloadIframe(iframe) {
document.body.removeChild(iframe);
}


/* Generic helpers */

// Returns a promise that resolves with undefined after a delay
function delay(duration) {
return new Promise((resolve) => {
setTimeout(resolve, duration);
});
}

// Takes a function that returns a Promise and
function oneAtATime(func) {
let currentExecution;

const reset = () => currentExecution = undefined;

return (...args) => {
if (currentExecution) {
return currentExecution;
} else {
currentExecution = func.apply(null, args);
currentExecution.then(reset, reset);
return currentExecution;
}
};
}
2 changes: 1 addition & 1 deletion public/test/spec/authed.ajax.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as ajax from 'modules/authed-ajax';
import * as mockjax from 'test/utils/mockjax';
import $ from 'jquery';
import * as panda from 'panda-session';
import * as panda from 'utils/panda-session';
import {CONST} from 'modules/vars';

describe('Authed Ajax', function () {
Expand Down

0 comments on commit 159eddb

Please sign in to comment.