From e20edbcedeebc3c48a911c231d4dd5fa219d3bdb Mon Sep 17 00:00:00 2001 From: MichaelJenny Date: Sun, 2 Jul 2017 14:58:04 +0200 Subject: [PATCH 1/3] Fix for #1993 --- client/modules/core/startup.js | 56 ++++++++++++++++++++++++++++- server/methods/accounts/accounts.js | 19 +++++++++- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/client/modules/core/startup.js b/client/modules/core/startup.js index d0649c6e22a..424c8ccce39 100644 --- a/client/modules/core/startup.js +++ b/client/modules/core/startup.js @@ -2,7 +2,12 @@ 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 Logger from "/client/modules/logger"; + + +const cookieName = "_RcFallbackLoginToken"; /** * Startup Reaction @@ -14,6 +19,20 @@ Meteor.startup(function () { // initialize anonymous guest users return Tracker.autorun(function () { const userId = Meteor.userId(); + + if (userId && !isLocalStorageAvailable() && !readCookie(cookieName)) { + Logger.info("No local storage available. About to set up fall-back 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; @@ -21,10 +40,45 @@ Meteor.startup(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=/"; +} diff --git a/server/methods/accounts/accounts.js b/server/methods/accounts/accounts.js index 83b51fd928a..1867b1d1aa7 100644 --- a/server/methods/accounts/accounts.js +++ b/server/methods/accounts/accounts.js @@ -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 */ @@ -775,5 +791,6 @@ Meteor.methods({ "accounts/sendWelcomeEmail": sendWelcomeEmail, "accounts/addUserPermissions": addUserPermissions, "accounts/removeUserPermissions": removeUserPermissions, - "accounts/setUserPermissions": setUserPermissions + "accounts/setUserPermissions": setUserPermissions, + "accounts/createFallbackLoginToken": createFallbackLoginToken }); From 85810252adf695471a5e694e9f0d16f70bcb9fa5 Mon Sep 17 00:00:00 2001 From: MichaelJenny Date: Sun, 2 Jul 2017 15:38:12 +0200 Subject: [PATCH 2/3] Fix linter errors. --- client/modules/core/startup.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/modules/core/startup.js b/client/modules/core/startup.js index 424c8ccce39..8ce571059a0 100644 --- a/client/modules/core/startup.js +++ b/client/modules/core/startup.js @@ -68,10 +68,10 @@ function isLocalStorageAvailable() { function readCookie(name) { const nameEq = name + "="; - const ca = document.cookie.split(';'); + 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); + while (c.charAt(0) === " ") c = c.substring(1, c.length); if (c.indexOf(nameEq) === 0) { return c.substring(nameEq.length, c.length); } From f46ead0c7f8eb49df9af2e132f03c2d7c7881899 Mon Sep 17 00:00:00 2001 From: MichaelJenny Date: Wed, 5 Jul 2017 22:38:20 +0200 Subject: [PATCH 3/3] Cleanup. --- client/modules/core/startup.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/client/modules/core/startup.js b/client/modules/core/startup.js index 8ce571059a0..5558ad21ea0 100644 --- a/client/modules/core/startup.js +++ b/client/modules/core/startup.js @@ -3,8 +3,7 @@ import { Meteor } from "meteor/meteor"; import { Tracker } from "meteor/tracker"; import { Accounts } from "meteor/accounts-base"; -import Reaction from "./main"; -import Logger from "/client/modules/logger"; +import { Reaction, Logger } from "/client/api"; const cookieName = "_RcFallbackLoginToken"; @@ -21,7 +20,7 @@ Meteor.startup(function () { const userId = Meteor.userId(); if (userId && !isLocalStorageAvailable() && !readCookie(cookieName)) { - Logger.info("No local storage available. About to set up fall-back login " + + 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) {