From 43778c9f19a129b7eaf5e7099d9d24f8ecc457e7 Mon Sep 17 00:00:00 2001 From: Clark Boylan Date: Fri, 17 Jul 2020 10:46:38 -0700 Subject: [PATCH] Patch etherpad console logging to fix cross origin error Etherpad 1.8.4 added console logging that breaks iframes like those used by meetpad when logging. THis means many etherpads work fine and only have an issue when logging is tripped. We fix this by adding patch files based on the upstream fix, https://github.com/ether/etherpad-lite/commit/00b6a1d9feae2399c08b42b7a3d711aed2d87a73, cherrypicked to 1.8.4 and then diffed. The reason we don't just use git is that while the installation in the upstream image is a git repo there is not git installation and adding in patch keeps our image small. We also convert the existing css fix to using patch for consistency. Change-Id: I7eed0d74c40141255cbff62069a83144feef6b61 --- docker/etherpad/Dockerfile | 17 +- docker/etherpad/patches/ace.js.patch | 11 + docker/etherpad/patches/ace2_inner.js.patch | 247 ++++++++++++++++++ .../etherpad/patches/iframe_editor.css.patch | 11 + 4 files changed, 282 insertions(+), 4 deletions(-) create mode 100644 docker/etherpad/patches/ace.js.patch create mode 100644 docker/etherpad/patches/ace2_inner.js.patch create mode 100644 docker/etherpad/patches/iframe_editor.css.patch diff --git a/docker/etherpad/Dockerfile b/docker/etherpad/Dockerfile index 111b1dc5c5..4d2ac7d0d7 100644 --- a/docker/etherpad/Dockerfile +++ b/docker/etherpad/Dockerfile @@ -17,8 +17,17 @@ FROM docker.io/etherpad/etherpad:1.8.4 LABEL maintainer="infra-root@openstack.org" -# Install the headings plugin and fix css on 1.8.4. -# Newer etherpad shouldn't need the css fix. +USER root +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y patch && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* +USER etherpad +# Install the headings plugin and fix css and console logging on 1.8.4. +# Newer etherpad shouldn't need the css or console fixes. +COPY patches/ /patches/ RUN cd /opt/etherpad-lite && npm install ep_headings \ - && sed -i -e 's/padding: 6px 0 !important;/padding: 0 0 !important;/' \ - /opt/etherpad-lite/src/static/css/iframe_editor.css + && patch /opt/etherpad-lite/src/static/css/iframe_editor.css /patches/iframe_editor.css.patch \ + && patch /opt/etherpad-lite/src/static/js/ace.js /patches/ace.js.patch \ + && patch /opt/etherpad-lite/src/static/js/ace2_inner.js /patches/ace2_inner.js.patch diff --git a/docker/etherpad/patches/ace.js.patch b/docker/etherpad/patches/ace.js.patch new file mode 100644 index 0000000000..26ac5dd160 --- /dev/null +++ b/docker/etherpad/patches/ace.js.patch @@ -0,0 +1,11 @@ +--- a/src/static/js/ace.js ++++ b/src/static/js/ace.js +@@ -104,7 +104,7 @@ function Ace2Editor() + editor[fnName] = pendingInit(function(){ + if(fnName === "setAuthorInfo"){ + if(!arguments[0]){ +- top.console.warn("setAuthorInfo AuthorId not set for some reason", arguments); ++ // setAuthorInfo AuthorId not set for some reason + }else{ + info[prefix + fnName].apply(this, arguments); + } diff --git a/docker/etherpad/patches/ace2_inner.js.patch b/docker/etherpad/patches/ace2_inner.js.patch new file mode 100644 index 0000000000..e5acdf07a8 --- /dev/null +++ b/docker/etherpad/patches/ace2_inner.js.patch @@ -0,0 +1,247 @@ +--- a/src/static/js/ace2_inner.js ++++ b/src/static/js/ace2_inner.js +@@ -130,7 +130,6 @@ function Ace2Inner(){ + console = {}; + for (var i = 0; i < names.length; ++i) + console[names[i]] = noop; +- //top.console.error = function(str) { alert(str); }; + } + + var PROFILER = window.PROFILER; +@@ -265,7 +264,7 @@ function Ace2Inner(){ + { + if ((typeof author) != "string") + { +- top.console.error("Going to throw new error, potentially caused by: https://github.com/ether/etherpad-lite/issues/2802"); ++ // Potentially caused by: https://github.com/ether/etherpad-lite/issues/2802"); + throw new Error("setAuthorInfo: author (" + author + ") is not a string"); + } + if (!info) +@@ -370,7 +369,8 @@ function Ace2Inner(){ + + if (currentCallStack) + { +- top.console.error("Can't enter callstack " + type + ", already in " + currentCallStack.type); ++ // Do not uncomment this in production. It will break Etherpad being provided in iFrames. I'm leaving this in for testing usefulness. ++ // top.console.error("Can't enter callstack " + type + ", already in " + currentCallStack.type); + } + + var profiling = false; +@@ -378,7 +378,6 @@ function Ace2Inner(){ + function profileRest() + { + profiling = true; +- top.console.profile(); + } + + function newEditEvent(eventType) +@@ -468,7 +467,6 @@ function Ace2Inner(){ + documentAttributeManager: documentAttributeManager + }); + +- //top.console.log("Just did action for: "+type); + cleanExit = true; + } + catch (e) +@@ -484,7 +482,6 @@ function Ace2Inner(){ + finally + { + var cs = currentCallStack; +- //top.console.log("Finished action for: "+type); + if (cleanExit) + { + submitOldEvent(cs.editEvent); +@@ -518,7 +515,6 @@ function Ace2Inner(){ + } + } + currentCallStack = null; +- if (profiling) top.console.profileEnd(); + } + return result; + } +@@ -740,7 +736,6 @@ function Ace2Inner(){ + * See for reference: + * - https://github.com/ether/etherpad-lite/issues/3861 + */ +- top.console.warn('atext.text is an empty string(""). Replacing with "\\n". See issue #3861.'); + atext.text = "\n"; + } + +@@ -1056,7 +1051,6 @@ function Ace2Inner(){ + + function newTimeLimit(ms) + { +- //top.console.debug("new time limit"); + var startTime = now(); + var lastElapsed = 0; + var exceededAlready = false; +@@ -1067,7 +1061,6 @@ function Ace2Inner(){ + { + if ((!printedTrace)) + { // && now() - startTime - ms > 300) { +- //top.console.trace(); + printedTrace = true; + } + return true; +@@ -1076,8 +1069,6 @@ function Ace2Inner(){ + if (elapsed > ms) + { + exceededAlready = true; +- //top.console.debug("time limit hit, before was %d/%d", lastElapsed, ms); +- //top.console.trace(); + return true; + } + else +@@ -1176,7 +1167,6 @@ function Ace2Inner(){ + + var isTimeUp = newTimeLimit(250); + +- //top.console.time("idlework"); + var finishedImportantWork = false; + var finishedWork = false; + +@@ -1195,13 +1185,11 @@ function Ace2Inner(){ + + var visibleRange = scroll.getVisibleCharRange(rep); + var docRange = [0, rep.lines.totalWidth()]; +- //top.console.log("%o %o", docRange, visibleRange); + finishedImportantWork = true; + finishedWork = true; + } + finally + { +- //top.console.timeEnd("idlework"); + if (finishedWork) + { + idleWorkTimer.atMost(1000); +@@ -1284,7 +1272,6 @@ function Ace2Inner(){ + selectionNeedsResetting = true; + } + +- //if (timer()) top.console.dirxml(lineEntry.lineNode.dom); + if (firstLine === null) firstLine = lineIndex; + lastLine = lineIndex; + lineStart = lineEnd; +@@ -1295,7 +1282,6 @@ function Ace2Inner(){ + { + currentCallStack.selectionAffected = true; + } +- //top.console.debug("Recolored line range %d-%d", firstLine, lastLine); + } + + // like getSpansForRange, but for a line, and the func takes (text,class) +@@ -1364,7 +1350,6 @@ function Ace2Inner(){ + // (from how it looks in our representation) and record them in a way + // that can be used to "normalize" the document (apply the changes to our + // representation, and put the DOM in a canonical form). +- // top.console.log("observeChangesAroundNode(%o)", node); + var cleanNode; + var hasAdjacentDirtyness; + if (!isNodeDirty(node)) +@@ -1501,7 +1486,6 @@ function Ace2Inner(){ + observeSuspiciousNodes(); + p.mark("dirty"); + var dirtyRanges = getDirtyRanges(); +- //top.console.log("dirtyRanges: "+toSource(dirtyRanges)); + var dirtyRangesCheckOut = true; + var j = 0; + var a, b; +@@ -1535,8 +1519,6 @@ function Ace2Inner(){ + p.mark("getsel"); + var selection = getSelection(); + +- //top.console.log(magicdom.root.dom.innerHTML); +- //top.console.log("got selection: %o", selection); + var selStart, selEnd; // each one, if truthy, has [line,char] needed to set selection + var i = 0; + var splicesToDo = []; +@@ -1584,7 +1566,6 @@ function Ace2Inner(){ + // It could be SPAN or a DIV; basically this is any case where the contentCollector + // decides it isn't done. + // Note that this clean node might need to be there for the next dirty range. +- //top.console.log("inclusive of "+lastDirtyNode.next().dom.tagName); + b++; + var cleanLine = lastDirtyNode.nextSibling; + cc.collectContent(cleanLine); +@@ -1609,7 +1590,6 @@ function Ace2Inner(){ + // Firefox isn't quite so bad, but it's still pretty quirky. + var scrollToTheLeftNeeded = true; + } +- // top.console.log("Editor warning: " + linesWrapped + " long line" + (linesWrapped == 1 ? " was" : "s were") + " hard-wrapped into " + ccData.numLinesAfter + " lines."); + } + + if (ss[0] >= 0) selStart = [ss[0] + a + netNumLinesChangeSoFar, ss[1]]; +@@ -1673,7 +1653,6 @@ function Ace2Inner(){ + if(n.parentNode) n.parentNode.removeChild(n); + + //dmesg(htmlPrettyEscape(htmlForRemovedChild(n))); +- //top.console.log("removed: "+id); + }); + + if(scrollToTheLeftNeeded){ // needed to stop chrome from breaking the ui when long strings without spaces are pasted +@@ -1893,6 +1872,7 @@ function Ace2Inner(){ + { + var line = lineAndChar[0]; + var charsLeft = lineAndChar[1]; ++ // Do not uncomment this in production it will break iFrames. + //top.console.log("line: %d, key: %s, node: %o", line, rep.lines.atIndex(line).key, + //getCleanNodeByKey(rep.lines.atIndex(line).key)); + var lineEntry = rep.lines.atIndex(line); +@@ -2018,7 +1998,6 @@ function Ace2Inner(){ + n = parNode; + } + } +- if (n.id === "") top.console.debug("BAD"); + if (n.firstChild && isBlockElement(n.firstChild)) + { + col += 1; // lineMarker +@@ -2905,11 +2884,13 @@ function Ace2Inner(){ + } + + return true; ++ // Do not uncomment this in production it will break iFrames. + //top.console.log("selStart: %o, selEnd: %o, focusAtStart: %s", rep.selStart, rep.selEnd, + //String(!!rep.selFocusAtStart)); + } + return false; +- //top.console.log("%o %o %s", rep.selStart, rep.selEnd, rep.selFocusAtStart); ++ // Do not uncomment this in production it will break iFrames. ++ //top.console.log("%o %o %s", rep.selStart, rep.selEnd, rep.selFocusAtStart); + } + + function isPadLoading(eventType) +@@ -3142,14 +3123,13 @@ function Ace2Inner(){ + // returns whether line was already correctly assigned (i.e. correctly + // clean or dirty, according to cleanRanges, and if clean, correctly + // attached or not attached (i.e. in the same range as) the prev and next lines). +- //top.console.log("correctly assigning: %d", line); + var rng = rangeForLine(line); + var lineClean = isClean(line); + if (rng < 0) + { + if (lineClean) + { +- top.console.debug("somehow lost clean line"); ++ // somehow lost clean line + } + return true; + } +@@ -3229,7 +3209,6 @@ function Ace2Inner(){ + detectChangesAroundLine(N - 1, 1); + + p.mark("obs"); +- //top.console.log("observedChanges: "+toSource(observedChanges)); + for (var k in observedChanges.cleanNodesNearChanges) + { + var key = k.substring(1); +@@ -4708,10 +4687,6 @@ function Ace2Inner(){ + // can handle "backwards"-oriented selection, shift-arrow-keys move start + // of selection + browserSelection.collapse(end.container, end.offset); +- //top.console.trace(); +- //top.console.log(htmlPrettyEscape(rep.alltext)); +- //top.console.log("%o %o", rep.selStart, rep.selEnd); +- //top.console.log("%o %d", start.container, start.offset); + browserSelection.extend(start.container, start.offset); + } + else diff --git a/docker/etherpad/patches/iframe_editor.css.patch b/docker/etherpad/patches/iframe_editor.css.patch new file mode 100644 index 0000000000..8b2442f360 --- /dev/null +++ b/docker/etherpad/patches/iframe_editor.css.patch @@ -0,0 +1,11 @@ +--- iframe_editor.css 2020-07-17 10:26:43.835522898 -0700 ++++ iframe_editor.css.fixed 2020-07-17 10:26:59.972181257 -0700 +@@ -51,7 +51,7 @@ + + #innerdocbody span { + line-height: 125%; +- padding: 6px 0 !important; ++ padding: 0 0 !important; + } + + option {