Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for issue #1993 #2518

Merged
merged 9 commits into from
Jul 6, 2017
57 changes: 55 additions & 2 deletions client/modules/core/startup.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import store from "amplify-store";
import { Meteor } from "meteor/meteor";
import { Tracker } from "meteor/tracker";
import { Accounts } from "meteor/accounts-base";
import Reaction from "./main";

import { Reaction, Logger } from "/client/api";


const cookieName = "_RcFallbackLoginToken";

/**
* Startup Reaction
Expand All @@ -14,17 +18,66 @@ Meteor.startup(function () {
// initialize anonymous guest users
return Tracker.autorun(function () {
const userId = Meteor.userId();

if (userId && !isLocalStorageAvailable() && !readCookie(cookieName)) {
Logger.debug("No local storage available. About to set up fallback login " +
"mechanism with cookie login token.");
Meteor.call("accounts/createFallbackLoginToken", (err, token) => {
if (!err && token) {
window.onbeforeunload = () => createSessionCookie(cookieName, token);
return;
}
// Can't set login cookie. Fail silently.
Logger.error("Setting up fallback login mechanism failed!");
});
}

// TODO: maybe `visibilityState` will be better here
let loggingIn;
let sessionId;
Tracker.nonreactive(function () {
loggingIn = Accounts.loggingIn();
sessionId = store("Reaction.session");
});

if (!userId) {
if (!loggingIn || typeof sessionId !== "string") {
Accounts.loginWithAnonymous();
if (!isLocalStorageAvailable() && readCookie(cookieName)) {
// If re-login through local storage fails, RC falls back
// to cookie-based login. E.g. Applies for Safari browser in
// incognito mode.
Accounts.loginWithToken(readCookie(cookieName));
} else {
Accounts.loginWithAnonymous();
}
}
}
});
});

function isLocalStorageAvailable() {
try {
localStorage.testKey = "testValue";
} catch (e) {
return false;
}
delete localStorage.testKey;
return true;
}

function readCookie(name) {
const nameEq = name + "=";
const ca = document.cookie.split(";");
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) === " ") c = c.substring(1, c.length);
if (c.indexOf(nameEq) === 0) {
return c.substring(nameEq.length, c.length);
}
}
return null;
}

function createSessionCookie(name, value) {
document.cookie = name + "=" + value + "; path=/";
}
19 changes: 18 additions & 1 deletion server/methods/accounts/accounts.js
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,22 @@ export function setUserPermissions(userId, permissions, group) {
}
}

/**
* accounts/createFallbackLoginToken
* @returns {String} returns a new loginToken for current user,
* that can be used for special login scenarios - e.g. store the
* newly created token as cookie on the browser, if the client
* does not offer local storage.
*/
export function createFallbackLoginToken() {
if (this.userId) {
const stampedLoginToken = MeteorAccounts._generateStampedLoginToken();
const loginToken = stampedLoginToken.token;
MeteorAccounts._insertLoginToken(this.userId, stampedLoginToken);
return loginToken;
}
}

/**
* Reaction Account Methods
*/
Expand All @@ -775,5 +791,6 @@ Meteor.methods({
"accounts/sendWelcomeEmail": sendWelcomeEmail,
"accounts/addUserPermissions": addUserPermissions,
"accounts/removeUserPermissions": removeUserPermissions,
"accounts/setUserPermissions": setUserPermissions
"accounts/setUserPermissions": setUserPermissions,
"accounts/createFallbackLoginToken": createFallbackLoginToken
});