diff --git a/client/coral-embed-stream/src/containers/Comment.js b/client/coral-embed-stream/src/containers/Comment.js index 733708a97..bd3160643 100644 --- a/client/coral-embed-stream/src/containers/Comment.js +++ b/client/coral-embed-stream/src/containers/Comment.js @@ -92,12 +92,6 @@ const singleCommentFragment = gql` const withCommentFragments = withFragments({ root: gql` fragment CoralEmbedStream_Comment_root on RootQuery { - me { - ignoredUsers { - id - } - } - __typename me { ignoredUsers { id diff --git a/client/coral-embed/src/Stream.js b/client/coral-embed/src/Stream.js index b81964529..cb8bb5bca 100644 --- a/client/coral-embed/src/Stream.js +++ b/client/coral-embed/src/Stream.js @@ -3,6 +3,7 @@ import pym from 'pym.js'; import EventEmitter from 'eventemitter2'; import {buildUrl} from 'coral-framework/utils/url'; import Snackbar from './Snackbar'; +import {createStorage, connectStorageToPym} from 'coral-framework/services/storage'; const NOTIFICATION_OFFSET = 200; @@ -134,6 +135,9 @@ export default class Stream { // If the user clicks outside the embed, then tell the embed. document.addEventListener('click', this.handleClick.bind(this), true); + + // Listens to storage requests on pym and relay it to local storage. + connectStorageToPym(createStorage(), this.pym); } login(token) { diff --git a/client/coral-embed/src/index.js b/client/coral-embed/src/index.js index 2b17ed465..34bee1797 100644 --- a/client/coral-embed/src/index.js +++ b/client/coral-embed/src/index.js @@ -83,7 +83,7 @@ Talk.render = (el, opts) => { console.warn( 'This page does not include a canonical link tag. Talk has inferred this asset_url from the window object. Query params have been stripped, which may cause a single thread to be present across multiple pages.' ); - + if (!window.location.origin) { window.location.origin = `${window.location.protocol}//${window.location.hostname}${window.location.port ? `:${window.location.port}` : ''}`; } diff --git a/client/coral-framework/services/bootstrap.js b/client/coral-framework/services/bootstrap.js index 5b627125e..492f6cc40 100644 --- a/client/coral-framework/services/bootstrap.js +++ b/client/coral-framework/services/bootstrap.js @@ -12,7 +12,7 @@ import {createPluginsService} from './plugins'; import {createNotificationService} from './notification'; import {createGraphQLRegistry} from './graphqlRegistry'; import globalFragments from 'coral-framework/graphql/fragments'; -import {createStorage} from 'coral-framework/services/storage'; +import {createStorage, createPymStorage} from 'coral-framework/services/storage'; import {createHistory} from 'coral-framework/services/history'; import {createIntrospection} from 'coral-framework/services/introspection'; import introspectionData from 'coral-framework/graphql/introspection.json'; @@ -81,6 +81,7 @@ export async function createContext({ } = {}) { const eventEmitter = new EventEmitter({wildcard: true}); const storage = createStorage(); + const pymStorage = createPymStorage(pym); const history = createHistory(BASE_PATH); const introspection = createIntrospection(introspectionData); let store = null; @@ -137,6 +138,7 @@ export async function createContext({ storage, history, introspection, + pymStorage, }; // Load framework fragments. diff --git a/client/coral-framework/services/storage.js b/client/coral-framework/services/storage.js index 9f06595fa..91ff10680 100644 --- a/client/coral-framework/services/storage.js +++ b/client/coral-framework/services/storage.js @@ -1,3 +1,4 @@ +import uuid from 'uuid/v4'; function getStorage(type) { let storage = window[type], x = '__storage_test__'; @@ -41,3 +42,90 @@ function getStorage(type) { export function createStorage() { return getStorage('localStorage'); } + +/** + * Creates a storage that relay requests over to pym. + * This is the counterpart of `connectStorageToPym`. + * @param {string} pym pym + * @return {Object} storage + */ +export function createPymStorage(pym) { + + // A Map of requestID => {resolve, reject} + const requests = {}; + + // Requests method with parameters over pym. + const call = (method, parameters) => { + const id = uuid(); + return new Promise((resolve, reject) => { + requests[id] = {resolve, reject}; + pym.sendMessage('pymStorage.request', JSON.stringify({id, method, parameters})); + }); + }; + + // Receive successful responses. + pym.onMessage('pymStorage.response', (msg) => { + const {id, result} = JSON.parse(msg); + requests[id].resolve(result); + delete requests[id]; + }); + + // Receive error responses. + pym.onMessage('pymStorage.error', (msg) => { + const {id, error} = JSON.parse(msg); + requests[id].reject(error); + delete requests[id]; + }); + + return { + setItem: (key, value) => call('setItem', {key, value}), + getItem: (key, value) => call('getItem', {key, value}), + removeItem: (key) => call('removeItem', {key}), + }; +} + +/** + * Listens to `pym` and relay storage requests to `storage`. + * This is the counterpart of `createPymStorage`. + * @param {string} pym pym + * @return {Object} storage + */ +export function connectStorageToPym(storage, pym) { + pym.onMessage('pymStorage.request', (msg) => { + const {id, method, parameters} = JSON.parse(msg); + const {key, value} = parameters; + const prefixedKey = `talkPymStorage:${key}`; + + // Variable for the method return value. + let result; + + const sendError = (error) => { + console.error(error); + pym.sendMessage('pymStorage.error', JSON.stringify({id, error})); + }; + + try { + switch(method) { + case 'setItem': + result = storage.setItem(prefixedKey, value); + break; + case 'getItem': + result = storage.getItem(prefixedKey); + break; + case 'removeItem': + result = storage.removeItem(prefixedKey); + break; + default: + sendError(`Unknown method ${method}`); + return; + } + } + catch(err) { + sendError(err.toString()); + return; + } + + pym.sendMessage('pymStorage.response', JSON.stringify({id, result})); + }); +} + diff --git a/plugins/talk-plugin-remember-sort/client/index.js b/plugins/talk-plugin-remember-sort/client/index.js index 4f1850b3f..061f71809 100644 --- a/plugins/talk-plugin-remember-sort/client/index.js +++ b/plugins/talk-plugin-remember-sort/client/index.js @@ -4,7 +4,7 @@ import {sortOrderSelector, sortBySelector} from 'plugin-api/beta/client/selector const STORAGE_PATH = 'talkPluginRememberSort'; export default { - init: ({store, storage, introspection}) => { + init: async ({store, pymStorage, introspection}) => { // TODO: workaround as this plugin is included in any target and // embeds (e.g. admin), but should only be included inside the stream. @@ -14,7 +14,10 @@ export default { return; } - let sort = JSON.parse(storage.getItem(STORAGE_PATH)); + // We use pymStorage instead to persist the data directly on the parent page, + // in order to mitigate strict cross domain security settings. + + let sort = JSON.parse(await pymStorage.getItem(STORAGE_PATH)); if ( sort && introspection.isValidEnumValue('SORT_ORDER', sort.sortOrder) && @@ -30,7 +33,7 @@ export default { // Save sorting choice to storage if it has changed. if (!sort || sort.sortOrder !== sortOrder || sort.sortBy !== sortBy) { sort = {sortOrder, sortBy}; - storage.setItem(STORAGE_PATH, JSON.stringify(sort)); + pymStorage.setItem(STORAGE_PATH, JSON.stringify(sort)); } }); }