mirror of
https://github.com/wassname/talk.git
synced 2026-07-18 12:40:13 +08:00
replaced localStorage state events with postMessage
This commit is contained in:
@@ -1,14 +1,29 @@
|
||||
import { HANDLE_SUCCESSFUL_LOGIN } from 'coral-framework/constants/auth';
|
||||
import sendMessage from 'coral-framework/services/messages/sendMessage';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Get the auth element and parse it as JSON by decoding it.
|
||||
const auth = document.getElementById('auth');
|
||||
const doc = document.implementation.createHTMLDocument('');
|
||||
doc.body.innerHTML = auth.innerText;
|
||||
try {
|
||||
// Get the auth element and parse it as JSON by decoding it.
|
||||
const auth = document.getElementById('auth');
|
||||
const doc = document.implementation.createHTMLDocument('');
|
||||
doc.body.innerHTML = auth.innerText;
|
||||
|
||||
// Set the item in localStorage.
|
||||
localStorage.setItem('auth', doc.body.textContent);
|
||||
// Auth state is contained within the node.
|
||||
const { err, data } = JSON.parse(doc.body.textContent);
|
||||
if (err) {
|
||||
// TODO: send back the error message.
|
||||
console.error(err);
|
||||
} else {
|
||||
// The data will contain a user and a token.
|
||||
const { user, token } = data;
|
||||
|
||||
// Close the window.
|
||||
setTimeout(() => {
|
||||
window.close();
|
||||
}, 50);
|
||||
// Send the state back.
|
||||
sendMessage(HANDLE_SUCCESSFUL_LOGIN, { user, token });
|
||||
}
|
||||
} finally {
|
||||
// Always close the window.
|
||||
setTimeout(() => {
|
||||
window.close();
|
||||
}, 50);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import * as actions from '../constants/login';
|
||||
import { checkLogin } from 'coral-framework/actions/auth';
|
||||
|
||||
export const showSignInDialog = () => ({
|
||||
type: actions.SHOW_SIGNIN_DIALOG,
|
||||
});
|
||||
|
||||
export const hideSignInDialog = () => dispatch => {
|
||||
dispatch(checkLogin());
|
||||
dispatch({ type: actions.HIDE_SIGNIN_DIALOG });
|
||||
};
|
||||
export const hideSignInDialog = () => ({ type: actions.HIDE_SIGNIN_DIALOG });
|
||||
|
||||
export const focusSignInDialog = () => ({
|
||||
type: actions.FOCUS_SIGNIN_DIALOG,
|
||||
|
||||
@@ -29,6 +29,17 @@ import t from 'coral-framework/services/i18n';
|
||||
import PropTypes from 'prop-types';
|
||||
import { setActiveTab } from '../actions/embed';
|
||||
|
||||
// TODO: refactor out to a HOC
|
||||
import { HANDLE_SUCCESSFUL_LOGIN } from 'coral-framework/constants/auth';
|
||||
import {
|
||||
handleSuccessfulLogin,
|
||||
checkLogin,
|
||||
} from 'coral-framework/actions/auth';
|
||||
import {
|
||||
subscribeToMessages,
|
||||
unsubscribeFromMessages,
|
||||
} from 'coral-framework/services/messages';
|
||||
|
||||
class EmbedContainer extends React.Component {
|
||||
static contextTypes = {
|
||||
pym: PropTypes.object,
|
||||
@@ -37,6 +48,8 @@ class EmbedContainer extends React.Component {
|
||||
subscriptions = [];
|
||||
|
||||
subscribeToUpdates(props = this.props) {
|
||||
subscribeToMessages(this.handleAuth);
|
||||
|
||||
if (props.currentUser) {
|
||||
const newSubscriptions = [
|
||||
{
|
||||
@@ -86,8 +99,23 @@ class EmbedContainer extends React.Component {
|
||||
unsubscribe() {
|
||||
this.subscriptions.forEach(unsubscribe => unsubscribe());
|
||||
this.subscriptions = [];
|
||||
unsubscribeFromMessages(this.handleAuth);
|
||||
}
|
||||
|
||||
// TODO: refactor out to a HOC
|
||||
handleAuth = ({ name, data }) => {
|
||||
if (name !== HANDLE_SUCCESSFUL_LOGIN) {
|
||||
return;
|
||||
}
|
||||
|
||||
// data will contain the user and token.
|
||||
const { user, token } = data;
|
||||
const { handleSuccessfulLogin, checkLogin } = this.props;
|
||||
|
||||
handleSuccessfulLogin(user, token);
|
||||
checkLogin();
|
||||
};
|
||||
|
||||
resubscribe(props) {
|
||||
this.unsubscribe();
|
||||
this.subscribeToUpdates(props);
|
||||
@@ -301,6 +329,8 @@ EmbedContainer.propTypes = {
|
||||
fetchAssetSuccess: PropTypes.func,
|
||||
showSignInDialog: PropTypes.bool,
|
||||
signInDialogFocus: PropTypes.bool,
|
||||
handleSuccessfulLogin: PropTypes.func.isRequired,
|
||||
checkLogin: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
@@ -328,6 +358,8 @@ const mapDispatchToProps = dispatch =>
|
||||
blurSignInDialog,
|
||||
hideSignInDialog,
|
||||
updateStatus,
|
||||
handleSuccessfulLogin,
|
||||
checkLogin,
|
||||
},
|
||||
dispatch
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as actions from '../constants/auth';
|
||||
import jwtDecode from 'jwt-decode';
|
||||
import { sendMessage } from '../services/messages';
|
||||
|
||||
function cleanAuthData(localStorage) {
|
||||
localStorage.removeItem('token');
|
||||
@@ -65,11 +66,23 @@ export const handleSuccessfulLogin = (user, token) => (
|
||||
_,
|
||||
{ client, localStorage }
|
||||
) => {
|
||||
const { exp } = jwtDecode(token);
|
||||
|
||||
if (localStorage) {
|
||||
localStorage.setItem('exp', jwtDecode(token).exp);
|
||||
localStorage.setItem('exp', exp);
|
||||
localStorage.setItem('token', token);
|
||||
}
|
||||
|
||||
// Send the message via the messages service to the window.opener if it
|
||||
// exists.
|
||||
if (window.opener) {
|
||||
sendMessage(
|
||||
actions.HANDLE_SUCCESSFUL_LOGIN,
|
||||
{ user, token },
|
||||
window.opener
|
||||
);
|
||||
}
|
||||
|
||||
client.resetWebsocket();
|
||||
|
||||
dispatch({
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { getStaticConfiguration } from 'coral-framework/services/staticConfiguration';
|
||||
|
||||
// Load the static url from the static configuration, we'll use it to formulate
|
||||
// the authorized domain to allow the message to be sent to.
|
||||
const { STATIC_ORIGIN } = getStaticConfiguration();
|
||||
|
||||
// Export the origin that will be sent.
|
||||
export { STATIC_ORIGIN as ORIGIN };
|
||||
|
||||
// Scope all the requests made via the messages service.
|
||||
export const SCOPE = 'client';
|
||||
@@ -0,0 +1,2 @@
|
||||
export { default as sendMessage } from './sendMessage';
|
||||
export { subscribeToMessages, unsubscribeFromMessages } from './subscriptions';
|
||||
@@ -0,0 +1,13 @@
|
||||
import { SCOPE, ORIGIN } from './constants';
|
||||
|
||||
export default (name, data, target = window.opener) => {
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Serialize the message to be sent via postMessage.
|
||||
const msg = { name, data, scope: SCOPE };
|
||||
|
||||
// Send the message.
|
||||
target.postMessage(msg, ORIGIN);
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
import { SCOPE, ORIGIN } from './constants';
|
||||
|
||||
import set from 'lodash/set';
|
||||
import has from 'lodash/has';
|
||||
import get from 'lodash/get';
|
||||
import remove from 'lodash/remove';
|
||||
|
||||
// withOriginCheck wraps a given handler for a messages event with a check to
|
||||
// see if the origin matches.
|
||||
const withOriginCheck = handler => {
|
||||
return event => {
|
||||
const origin = get(event, 'origin');
|
||||
if (origin !== ORIGIN) {
|
||||
return;
|
||||
}
|
||||
|
||||
const scope = get(event, 'data.scope');
|
||||
if (scope !== SCOPE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Pass the handler the event details.
|
||||
handler(event);
|
||||
};
|
||||
};
|
||||
|
||||
// withParseData will parse the data.
|
||||
const withParseData = handler => {
|
||||
return event => {
|
||||
const data = get(event, 'data.data');
|
||||
const name = get(event, 'data.name');
|
||||
if (!data || !name) {
|
||||
return;
|
||||
}
|
||||
|
||||
handler({ data, name, event });
|
||||
};
|
||||
};
|
||||
|
||||
// Store a reference to each listener added.
|
||||
const listeners = {};
|
||||
|
||||
export const subscribeToMessages = (handler, target = window) => {
|
||||
// If this handler is already attached to the target, detach it.
|
||||
if (has(listeners, [target, handler])) {
|
||||
unsubscribeFromMessages(handler, target);
|
||||
}
|
||||
|
||||
// Wrap the listener with a origin check.
|
||||
const listener = withOriginCheck(withParseData(handler));
|
||||
|
||||
// Save a reference to the compiled listener.
|
||||
set(listeners, [target, handler], listener);
|
||||
|
||||
// Attach the listener to the target.
|
||||
target.addEventListener('message', listener);
|
||||
};
|
||||
|
||||
export const unsubscribeFromMessages = (handler, target = window) => {
|
||||
if (!has(listeners, [target, handler])) {
|
||||
return;
|
||||
}
|
||||
|
||||
const listener = get(listeners, [target, handler]);
|
||||
|
||||
// Remove the listener from the target.
|
||||
target.removeEventListener('message', listener);
|
||||
|
||||
remove(listeners, [target, handler]);
|
||||
};
|
||||
@@ -1,6 +1,12 @@
|
||||
const SettingsService = require('../services/settings');
|
||||
|
||||
const { BASE_URL, BASE_PATH, MOUNT_PATH, STATIC_URL } = require('../url');
|
||||
const {
|
||||
BASE_URL,
|
||||
BASE_PATH,
|
||||
MOUNT_PATH,
|
||||
STATIC_URL,
|
||||
STATIC_ORIGIN,
|
||||
} = require('../url');
|
||||
|
||||
const { RECAPTCHA_PUBLIC, WEBSOCKET_LIVE_URI } = require('../config');
|
||||
|
||||
@@ -15,6 +21,7 @@ const TEMPLATE_LOCALS = {
|
||||
TALK_RECAPTCHA_PUBLIC: RECAPTCHA_PUBLIC,
|
||||
LIVE_URI: WEBSOCKET_LIVE_URI,
|
||||
STATIC_URL,
|
||||
STATIC_ORIGIN,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
export const loginWithFacebook = () => (dispatch, _, { rest }) => {
|
||||
window.open(
|
||||
`${rest.uri}/auth/facebook`,
|
||||
'Continue with Facebook',
|
||||
'menubar=0,resizable=0,width=500,height=500,top=200,left=500'
|
||||
);
|
||||
window.location = `${rest.uri}/auth/facebook`;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
export const loginWithGoogle = () => (dispatch, _, { rest }) => {
|
||||
window.open(
|
||||
`${rest.uri}/auth/google`,
|
||||
'Continue with Google',
|
||||
'menubar=0,resizable=0,width=500,height=500,top=200,left=500'
|
||||
);
|
||||
window.location = `${rest.uri}/auth/google`;
|
||||
};
|
||||
|
||||
@@ -18,9 +18,12 @@ const MOUNT_PATH = ROOT_URL_MOUNT_PATH ? BASE_PATH : '/';
|
||||
// The STATIC_URL is the url where static assets should be loaded from.
|
||||
const STATIC_URL = trailingSlash(STATIC_URI);
|
||||
|
||||
const STATIC_ORIGIN = new URL(STATIC_URI).origin;
|
||||
|
||||
module.exports = {
|
||||
BASE_URL,
|
||||
BASE_PATH,
|
||||
MOUNT_PATH,
|
||||
STATIC_URL,
|
||||
STATIC_ORIGIN,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<%- include partials/data %>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/json" id="auth"><%- encodeJSONForHTML(auth) %></script>
|
||||
<script type="text/javascript" src="<%= STATIC_URL %>static/coral-auth-callback/bundle.js"></script>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<%_ if (data != null) { _%>
|
||||
<script id="data" type="application/json"><%- JSON.stringify(data) %></script>
|
||||
<%_ } _%>
|
||||
@@ -18,7 +18,5 @@
|
||||
<%_ if (locals.customCssUrl) { _%>
|
||||
<link href="<%= customCssUrl %>" rel="stylesheet" type="text/css">
|
||||
<%_ } _%>
|
||||
<%_ if (data != null) { _%>
|
||||
<script id="data" type="application/json"><%- JSON.stringify(data) %></script>
|
||||
<%_ } _%>
|
||||
<%- include data %>
|
||||
<base href="<%= BASE_URL %>"/>
|
||||
Reference in New Issue
Block a user