diff --git a/src/node/utils/Minify.js b/src/node/utils/Minify.js index e94d34b04..750aac007 100644 --- a/src/node/utils/Minify.js +++ b/src/node/utils/Minify.js @@ -44,12 +44,13 @@ var threadsPool = Threads.Pool(function () { }, 2) var LIBRARY_WHITELIST = [ - 'async' - , 'security' - , 'tinycon' - , 'underscore' - , 'unorm' - ]; + 'async', + 'js-cookie', + 'security', + 'tinycon', + 'underscore', + 'unorm', +]; // Rewrite tar to include modules with no extensions and proper rooted paths. var LIBRARY_PREFIX = 'ep_etherpad-lite/static/js'; diff --git a/src/node/utils/tar.json b/src/node/utils/tar.json index 80d645dd0..7d0913425 100644 --- a/src/node/utils/tar.json +++ b/src/node/utils/tar.json @@ -17,6 +17,7 @@ , "pad_connectionstatus.js" , "chat.js" , "gritter.js" + , "$js-cookie/src/js.cookie.js" , "$tinycon/tinycon.js" , "excanvas.js" , "farbtastic.js" diff --git a/src/package-lock.json b/src/package-lock.json index 356b7455e..60ec0887f 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -2656,6 +2656,11 @@ "istanbul-lib-report": "^3.0.0" } }, + "js-cookie": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", + "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", diff --git a/src/package.json b/src/package.json index 18f42c395..155638161 100644 --- a/src/package.json +++ b/src/package.json @@ -46,6 +46,7 @@ "formidable": "1.2.1", "graceful-fs": "4.2.4", "http-errors": "1.7.3", + "js-cookie": "^2.2.1", "jsonminify": "0.4.1", "languages4translatewiki": "0.1.3", "lodash.clonedeep": "4.5.0", diff --git a/src/static/js/pad.js b/src/static/js/pad.js index 37bc0e009..416d7897e 100644 --- a/src/static/js/pad.js +++ b/src/static/js/pad.js @@ -30,6 +30,7 @@ require('./jquery'); require('./farbtastic'); require('./excanvas'); +const Cookies = require('./pad_utils').Cookies; var chat = require('./chat').chat; var getCollabClient = require('./collab_client').getCollabClient; var padconnectionstatus = require('./pad_connectionstatus').padconnectionstatus; @@ -42,8 +43,6 @@ var padsavedrevs = require('./pad_savedrevs'); var paduserlist = require('./pad_userlist').paduserlist; var padutils = require('./pad_utils').padutils; var colorutils = require('./colorutils').colorutils; -var createCookie = require('./pad_utils').createCookie; -var readCookie = require('./pad_utils').readCookie; var randomString = require('./pad_utils').randomString; var gritter = require('./gritter').gritter; @@ -83,7 +82,7 @@ var getParameters = [ { name: "rtl", checkVal: "true", callback: function(val) { settings.rtlIsTrue = true } }, { name: "alwaysShowChat", checkVal: "true", callback: function(val) { if(!settings.hideChat) chat.stickToScreen(); } }, { name: "chatAndUsers", checkVal: "true", callback: function(val) { chat.chatAndUsers(); } }, - { name: "lang", checkVal: null, callback: function(val) { window.html10n.localize([val, 'en']); createCookie('language', val); } } + { name: "lang", checkVal: null, callback: function(val) { window.html10n.localize([val, 'en']); Cookies.set('language', val); } }, ]; function getParams() @@ -130,7 +129,7 @@ function getUrlVars() function savePassword() { //set the password cookie - createCookie("password",$("#passwordinput").val(),null,document.location.pathname); + Cookies.set('password', $('#passwordinput').val(), {path: document.location.pathname}); //reload document.location=document.location; return false; @@ -149,25 +148,21 @@ function sendClientReady(isReconnect, messageType) document.title = padId.replace(/_+/g, ' ') + " | " + title; } - var token = readCookie("token"); + let token = Cookies.get('token'); if (token == null) { token = "t." + randomString(); - createCookie("token", token, 60); + Cookies.set('token', token, {expires: 60}); } - var encodedSessionID = readCookie('sessionID'); - var sessionID = encodedSessionID == null ? null : decodeURIComponent(encodedSessionID); - var password = readCookie("password"); - - var msg = { - "component": "pad", - "type": messageType, - "padId": padId, - "sessionID": sessionID, - "password": password, - "token": token, - "protocolVersion": 2 + const msg = { + component: 'pad', + type: messageType, + padId: padId, + sessionID: Cookies.get('sessionID'), + password: Cookies.get('password'), + token: token, + protocolVersion: 2 }; // this is a reconnect, lets tell the server our revisionnumber @@ -456,7 +451,6 @@ var pad = { { pad.collabClient.sendClientMessage(msg); }, - createCookie: createCookie, init: function() { @@ -957,8 +951,6 @@ var settings = { pad.settings = settings; exports.baseURL = ''; exports.settings = settings; -exports.createCookie = createCookie; -exports.readCookie = readCookie; exports.randomString = randomString; exports.getParams = getParams; exports.getUrlVars = getUrlVars; diff --git a/src/static/js/pad_cookie.js b/src/static/js/pad_cookie.js index 0075691f6..f3dedf03c 100644 --- a/src/static/js/pad_cookie.js +++ b/src/static/js/pad_cookie.js @@ -14,8 +14,7 @@ * limitations under the License. */ -const createCookie = require('./pad_utils').createCookie; -const readCookie = require('./pad_utils').readCookie; +const Cookies = require('./pad_utils').Cookies; exports.padcookie = new class { constructor() { @@ -40,17 +39,17 @@ exports.padcookie = new class { } readPrefs_() { - const jsonEsc = readCookie(this.cookieName_); - if (jsonEsc == null) return null; try { - return JSON.parse(unescape(jsonEsc)); + const json = Cookies.get(this.cookieName_); + if (json == null) return null; + return JSON.parse(json); } catch (e) { return null; } } savePrefs_() { - createCookie(this.cookieName_, escape(JSON.stringify(this.prefs_)), 365 * 100); + Cookies.set(this.cookieName_, JSON.stringify(this.prefs_), {expires: 365 * 100}); } getPref(prefName) { diff --git a/src/static/js/pad_editor.js b/src/static/js/pad_editor.js index 6c53e4014..edd394064 100644 --- a/src/static/js/pad_editor.js +++ b/src/static/js/pad_editor.js @@ -20,6 +20,7 @@ * limitations under the License. */ +const Cookies = require('./pad_utils').Cookies; var padcookie = require('./pad_cookie').padcookie; var padutils = require('./pad_utils').padutils; @@ -108,7 +109,7 @@ var padeditor = (function() }) $("#languagemenu").val(html10n.getLanguage()); $("#languagemenu").change(function() { - pad.createCookie("language",$("#languagemenu").val(),null,'/'); + Cookies.set('language', $('#languagemenu').val()); window.html10n.localize([$("#languagemenu").val(), 'en']); }); }, diff --git a/src/static/js/pad_utils.js b/src/static/js/pad_utils.js index a7feb59ae..e9bc58cb4 100644 --- a/src/static/js/pad_utils.js +++ b/src/static/js/pad_utils.js @@ -39,49 +39,6 @@ function randomString(len) return randomstring; } -function createCookie(name, value, days, path){ /* Used by IE */ - if (days) - { - var date = new Date(); - date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); - var expires = "; expires=" + date.toGMTString(); - } - else{ - var expires = ""; - } - - if(!path){ // IF the Path of the cookie isn't set then just create it on root - path = "/"; - } - - //Check if we accessed the pad over https - var secure = window.location.protocol == "https:" ? ";secure" : ""; - var isHttpsScheme = window.location.protocol === "https:"; - var sameSite = isHttpsScheme ? ";sameSite=Strict": ";sameSite=Lax"; - - //Check if the browser is IE and if so make sure the full path is set in the cookie - if((navigator.appName == 'Microsoft Internet Explorer') || ((navigator.appName == 'Netscape') && (new RegExp("Trident/.*rv:([0-9]{1,}[\.0-9]{0,})").exec(navigator.userAgent) != null))){ - document.cookie = name + "=" + value + expires + "; path=/" + secure + sameSite; /* Note this bodge fix for IE is temporary until auth is rewritten */ - } - else{ - document.cookie = name + "=" + value + expires + "; path=" + path + secure + sameSite; - } - -} - -function readCookie(name) -{ - var nameEQ = name + "="; - var ca = document.cookie.split(';'); - for (var i = 0; i < ca.length; i++) - { - var 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; -} - var padutils = { escapeHtml: function(x) { @@ -571,7 +528,12 @@ padutils.setupGlobalExceptionHandler = setupGlobalExceptionHandler; padutils.binarySearch = require('./ace2_common').binarySearch; +// This file is included from Node so that it can reuse randomString, but Node doesn't have a global +// window object. +if (typeof window !== 'undefined') { + exports.Cookies = require('js-cookie/src/js.cookie'); + exports.Cookies.defaults.sameSite = window.location.protocol === 'https:' ? 'Strict' : 'Lax'; + exports.Cookies.defaults.secure = window.location.protocol === 'https:'; +} exports.randomString = randomString; -exports.createCookie = createCookie; -exports.readCookie = readCookie; exports.padutils = padutils; diff --git a/src/static/js/timeslider.js b/src/static/js/timeslider.js index d8d3e5964..2721bd0e5 100644 --- a/src/static/js/timeslider.js +++ b/src/static/js/timeslider.js @@ -24,8 +24,7 @@ // assigns to the global `$` and augments it with plugins. require('./jquery'); -var createCookie = require('./pad_utils').createCookie; -var readCookie = require('./pad_utils').readCookie; +const Cookies = require('./pad_utils').Cookies; var randomString = require('./pad_utils').randomString; var hooks = require('./pluginfw/hooks'); @@ -45,11 +44,11 @@ function init() { document.title = padId.replace(/_+/g, ' ') + " | " + document.title; //ensure we have a token - token = readCookie("token"); + token = Cookies.get('token'); if(token == null) { token = "t." + randomString(); - createCookie("token", token, 60); + Cookies.set('token', token, {expires: 60}); } var loc = document.location; @@ -107,19 +106,16 @@ function init() { //sends a message over the socket function sendSocketMsg(type, data) { - var sessionID = decodeURIComponent(readCookie("sessionID")); - var password = readCookie("password"); - - var msg = { "component" : "pad", // FIXME: Remove this stupidity! - "type": type, - "data": data, - "padId": padId, - "token": token, - "sessionID": sessionID, - "password": password, - "protocolVersion": 2}; - - socket.json.send(msg); + socket.json.send({ + component: 'pad', // FIXME: Remove this stupidity! + type, + data, + padId, + token, + sessionID: Cookies.get('sessionID'), + password: Cookies.get('password'), + protocolVersion: 2, + }); } var fireWhenAllScriptsAreLoaded = [];