Skip to content

Commit

Permalink
Merge pull request #2 from Gaurav0/use_postmessage_instead_of_storage…
Browse files Browse the repository at this point in the history
…_event_embedded_case

[TP-179336] Use postmessage instead of storage event for embedded case
  • Loading branch information
Gaurav0 authored Sep 23, 2024
2 parents 24705d0 + 154ec01 commit 1ec0dde
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 6 deletions.
29 changes: 29 additions & 0 deletions addon/mixins/ui-service-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ var ServicesMixin = Mixin.create({
let service = this;
let lastRemote = this.remote;
let storageToriiEventHandler;
let messageToriiEventHandler;

return new EmberPromise(function (resolve, reject) {
if (lastRemote) {
Expand All @@ -55,7 +56,34 @@ var ServicesMixin = Mixin.create({
});
}
};

// Using postMessage as an alternative to localStorage/storageEvent
// for case of web site embedded in iframe
messageToriiEventHandler = function (messageEvent) {
if (messageEvent.data === 'getPendingRequestKey') {
messageEvent.source.postMessage(
JSON.stringify({ pendingRequestKey: service.pendingRequestKey }),
window.location.origin
);
} else {
const msg = JSON.parse(messageEvent.data);
const key = Object.keys(msg)[0];
var remoteIdFromEvent = PopupIdSerializer.deserialize(
decodeURIComponent(key)
);
if (remoteId === remoteIdFromEvent) {
var data = parseMessage(msg[key], keys);
localStorage.removeItem(key);
run(function () {
resolve(data);
});
}
}
};
window.addEventListener('message', messageToriiEventHandler);

var pendingRequestKey = PopupIdSerializer.serialize(remoteId);
service.pendingRequestKey = pendingRequestKey;
localStorage.setItem(CURRENT_REQUEST_KEY, pendingRequestKey);
localStorage.removeItem(WARNING_KEY);

Expand Down Expand Up @@ -115,6 +143,7 @@ var ServicesMixin = Mixin.create({
}).finally(function () {
// didClose will reject this same promise, but it has already resolved.
service.close();
window.removeEventListener('message', messageToriiEventHandler);
window.removeEventListener('storage', storageToriiEventHandler);
});
},
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "torii",
"version": "1.0.0-beta.2",
"version": "1.0.0-beta.3",
"description": "A set of clean abstractions for authentication in Ember.js",
"keywords": [
"authentication",
Expand Down
43 changes: 38 additions & 5 deletions public/redirect.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,49 @@
<meta charset="UTF-8">
<title>Torii OAuth Redirect</title>
<script>
var CURRENT_REQUEST_KEY = '__torii_request';
var pendingRequestKey = window.localStorage.getItem(CURRENT_REQUEST_KEY);
const CURRENT_REQUEST_KEY = '__torii_request';
let pendingRequestKey = window.localStorage.getItem(CURRENT_REQUEST_KEY);
const origin = window.location.origin;
let opener = window.opener;
try {
if (opener && opener.parent && opener.parent.origin === origin) {
opener = opener.parent;
}
} catch {}

if (pendingRequestKey) {
window.localStorage.removeItem(CURRENT_REQUEST_KEY);
var url = window.location.toString();
const url = window.location.toString();
window.localStorage.setItem(pendingRequestKey, url);
}
const obj = {};
obj[pendingRequestKey] = url;
opener?.postMessage(
JSON.stringify(obj),
origin
);

window.close();
} else {
// localStorage not shared with opener due to browser restrictions
opener?.postMessage('getPendingRequestKey', origin);
window.addEventListener('message', function(messageEvent) {
if (messageEvent.source === opener) {
const msg = JSON.parse(messageEvent.data);
if (msg.pendingRequestKey) {
pendingRequestKey = msg.pendingRequestKey;
url = window.location.toString();
const obj = {};
obj[pendingRequestKey] = url;
opener.postMessage(
JSON.stringify(obj),
origin
);

window.close();
window.close();
}
}
});
}
</script>
</head>
</html>
129 changes: 129 additions & 0 deletions tests/unit/mixins/ui-service-mixin-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/* eslint-disable ember/no-mixins, ember/no-new-mixins, ember/no-classic-classes */

import EmberObject from '@ember/object';
import Evented from '@ember/object/evented';
import UiServiceMixin, {
CURRENT_REQUEST_KEY,
} from 'torii/mixins/ui-service-mixin';
import PopupIdSerializer from 'torii/lib/popup-id-serializer';
import { module, test } from 'qunit';

module('Unit | Mixin | ui-service-mixin', function (hooks) {
const originalWindowOpen = window.open;

const popupId = '09123-asdf';
const expectedUrl = 'http://authServer';
const expectedRedirectUrl = 'http://localserver?code=fr';
const expectedMessage = 'getPendingRequestKey';

const mockWindowListener = (event) => {
let msg;
try {
msg = JSON.parse(event.data);
} catch {
// allow
}
if (msg && Object.keys(msg)[0] === 'pendingRequestKey') {
const obj = {};
const key = PopupIdSerializer.serialize(encodeURIComponent(popupId));
obj[key] = `${expectedUrl}?redirect_url=${expectedRedirectUrl}`;
window.dispatchEvent(
new MessageEvent('message', {
data: JSON.stringify(obj),
source: window,
})
);
}
};

const buildMockWindow = function (windowName) {
windowName = windowName || '';
window.addEventListener('message', mockWindowListener);
return {
name: windowName,
focus() {},
close() {},
open() {
this.postMessage(expectedMessage);
},
postMessage(msg) {
window.dispatchEvent(
new MessageEvent('message', { data: msg, source: window })
);
},
};
};

const buildPopupIdGenerator = function (popupId) {
return {
generate() {
return popupId;
},
};
};

let Popup = EmberObject.extend(Evented, UiServiceMixin, {
// Open a popup window.
openRemote(_url, pendingRequestKey) {
this.remote = buildMockWindow(pendingRequestKey);
this.remote.open();
},

closeRemote() {
this.remote.closed = true;
},

pollRemote() {
if (!this.remote) {
return;
}
},
});

let popup;

hooks.beforeEach(function () {
popup = Popup.create({ remoteIdGenerator: buildPopupIdGenerator(popupId) });
localStorage.removeItem(CURRENT_REQUEST_KEY);
});

hooks.afterEach(async function () {
localStorage.removeItem(CURRENT_REQUEST_KEY);
window.open = originalWindowOpen;
window.removeEventListener('message', mockWindowListener);
popup.destroy();
});

test('requests pending request key', function (assert) {
assert.expect(1);

let resultMessage;
const resultMessageListener = (event) => {
resultMessage = event.data;
};
try {
window.addEventListener('message', resultMessageListener);

popup.openRemote(expectedUrl, CURRENT_REQUEST_KEY);

assert.strictEqual(
resultMessage,
expectedMessage,
'requests pendingRequestKey'
);
} finally {
window.removeEventListener('message', resultMessageListener);
}
});

test('returns data after receiving key', async function (assert) {
const keys = ['redirect_url'];
const result = await popup.open(expectedUrl, keys);

assert.strictEqual(
result.redirect_url,
expectedRedirectUrl,
'returns data successfully'
);
});
});

0 comments on commit 1ec0dde

Please sign in to comment.