浏览代码

[CE/SP] Hotfixes 3.5.10 / 4.0.5 (#13961)

* [CE/SP] Hotfixes 3.5.10 / 4.0.5

* [CE/SP] include PR13122 in 4.0.5 hotfixes

---------

Co-authored-by: Jakob Ackermann <jakob.ackermann@overleaf.com>
GitOrigin-RevId: 68d31f4a4573d2cad1ee564a62957ad2c858cbe7
Miguel Serrano 3 年之前
父节点
当前提交
59fe2fe463

+ 9 - 0
server-ce/hotfix/3.5.10/Dockerfile

@@ -0,0 +1,9 @@
+FROM sharelatex/sharelatex:3.5.9
+
+# Patch: clear invite and invite tokens through the websocket
+COPY pr_13427.patch .
+RUN patch -p0 < pr_13427.patch
+
+# Patch: https://github.com/Automattic/mongoose/commit/f1efabf350522257364aa5c2cb36e441cf08f1a2
+COPY mongoose_proto.patch .
+RUN patch -p0 < mongoose_proto.patch

+ 12 - 0
server-ce/hotfix/3.5.10/mongoose_proto.patch

@@ -0,0 +1,12 @@
+--- node_modules/mongoose/lib/document.js
++++ node_modules/mongoose/lib/document.js
+@@ -689,6 +689,10 @@ function init(self, obj, doc, opts, prefix) {
+
+   function _init(index) {
+     i = keys[index];
++    // avoid prototype pollution
++    if (i === '__proto__' || i === 'constructor') {
++      return;
++    }
+     path = prefix + i;
+     schema = self.$__schema.path(path);

+ 92 - 0
server-ce/hotfix/3.5.10/pr_13427.patch

@@ -0,0 +1,92 @@
+--- services/web/app/src/Features/Editor/EditorHttpController.js
++++ services/web/app/src/Features/Editor/EditorHttpController.js
+@@ -73,6 +73,7 @@ async function joinProject(req, res, next) {
+   if (isRestrictedUser) {
+     project.owner = { _id: project.owner._id }
+     project.members = []
++    project.invites = []
+   }
+   // Only show the 'renamed or deleted' message once
+   if (project.deletedByExternalDataSource) {
+--- services/web/app/src/Features/Project/ProjectEditorHandler.js
++++ services/web/app/src/Features/Project/ProjectEditorHandler.js
+@@ -48,19 +48,13 @@
+         deletedDocsFromDocstore
+       ),
+       members: [],
+-      invites,
++      invites: this.buildInvitesView(invites),
+       imageName:
+         project.imageName != null
+           ? Path.basename(project.imageName)
+           : undefined,
+     }
+
+-    if (result.invites == null) {
+-      result.invites = []
+-    }
+-    result.invites.forEach(invite => {
+-      delete invite.token
+-    })
+     ;({ owner, ownerFeatures, members } =
+       this.buildOwnerAndMembersViews(members))
+     result.owner = owner
+@@ -99,7 +93,7 @@
+     let owner = null
+     let ownerFeatures = null
+     const filteredMembers = []
+-    for (const member of Array.from(members || [])) {
++    for (const member of members || []) {
+       if (member.privilegeLevel === 'owner') {
+         ownerFeatures = member.user.features
+         owner = this.buildUserModelView(member.user, 'owner')
+@@ -128,24 +122,15 @@
+   },
+
+   buildFolderModelView(folder) {
+-    let file
+     const fileRefs = _.filter(folder.fileRefs || [], file => file != null)
+     return {
+       _id: folder._id,
+       name: folder.name,
+-      folders: Array.from(folder.folders || []).map(childFolder =>
++      folders: (folder.folders || []).map(childFolder =>
+         this.buildFolderModelView(childFolder)
+       ),
+-      fileRefs: (() => {
+-        const result = []
+-        for (file of Array.from(fileRefs)) {
+-          result.push(this.buildFileModelView(file))
+-        }
+-        return result
+-      })(),
+-      docs: Array.from(folder.docs || []).map(doc =>
+-        this.buildDocModelView(doc)
+-      ),
++      fileRefs: fileRefs.map(file => this.buildFileModelView(file)),
++      docs: (folder.docs || []).map(doc => this.buildDocModelView(doc)),
+     }
+   },
+
+@@ -164,4 +149,21 @@
+       name: doc.name,
+     }
+   },
++
++  buildInvitesView(invites) {
++    if (invites == null) {
++      return []
++    }
++    return invites.map(invite =>
++      _.pick(invite, [
++        '_id',
++        'createdAt',
++        'email',
++        'expires',
++        'privileges',
++        'projectId',
++        'sendingUserId',
++      ])
++    )
++  },
+ }

+ 13 - 0
server-ce/hotfix/4.0.5/Dockerfile

@@ -0,0 +1,13 @@
+FROM sharelatex/sharelatex:4.0.4
+
+# Patch: clear invite and invite tokens through the websocket
+COPY pr_13427.patch .
+RUN patch -p0 < pr_13427.patch
+
+# Patch: https://github.com/Automattic/mongoose/commit/f1efabf350522257364aa5c2cb36e441cf08f1a2
+COPY mongoose_proto.patch .
+RUN patch -p0 < mongoose_proto.patch
+
+# Patch: Allow digits in PDF filenames
+COPY pr_13122.patch .
+RUN patch -p0 < pr_13122.patch

+ 12 - 0
server-ce/hotfix/4.0.5/mongoose_proto.patch

@@ -0,0 +1,12 @@
+--- services/web/node_modules/mongoose/lib/document.js
++++ services/web/node_modules/mongoose/lib/document.js
+@@ -739,6 +739,10 @@ function init(self, obj, doc, opts, prefix) {
+
+   function _init(index) {
+     i = keys[index];
++    // avoid prototype pollution
++    if (i === '__proto__' || i === 'constructor') {
++      return;
++    }
+     path = prefix + i;
+     schemaType = docSchema.path(path);

+ 11 - 0
server-ce/hotfix/4.0.5/pr_13122.patch

@@ -0,0 +1,11 @@
+--- services/web/app/src/Features/Compile/CompileController.js
++++ services/web/app/src/Features/Compile/CompileController.js
+@@ -371,7 +371,7 @@ module.exports = CompileController = {
+   },
+
+   _getSafeProjectName(project) {
+-    return project.name.replace(/\P{L}/gu, '_')
++    return project.name.replace(/[^\p{L}\p{Nd}]/gu, '_')
+   },
+
+   deleteAuxFiles(req, res, next) {

+ 92 - 0
server-ce/hotfix/4.0.5/pr_13427.patch

@@ -0,0 +1,92 @@
+--- services/web/app/src/Features/Editor/EditorHttpController.js
++++ services/web/app/src/Features/Editor/EditorHttpController.js
+@@ -73,6 +73,7 @@ async function joinProject(req, res, next) {
+   if (isRestrictedUser) {
+     project.owner = { _id: project.owner._id }
+     project.members = []
++    project.invites = []
+   }
+   // Only show the 'renamed or deleted' message once
+   if (project.deletedByExternalDataSource) {
+--- services/web/app/src/Features/Project/ProjectEditorHandler.js
++++ services/web/app/src/Features/Project/ProjectEditorHandler.js
+@@ -48,19 +48,13 @@
+         deletedDocsFromDocstore
+       ),
+       members: [],
+-      invites,
++      invites: this.buildInvitesView(invites),
+       imageName:
+         project.imageName != null
+           ? Path.basename(project.imageName)
+           : undefined,
+     }
+
+-    if (result.invites == null) {
+-      result.invites = []
+-    }
+-    result.invites.forEach(invite => {
+-      delete invite.token
+-    })
+     ;({ owner, ownerFeatures, members } =
+       this.buildOwnerAndMembersViews(members))
+     result.owner = owner
+@@ -99,7 +93,7 @@
+     let owner = null
+     let ownerFeatures = null
+     const filteredMembers = []
+-    for (const member of Array.from(members || [])) {
++    for (const member of members || []) {
+       if (member.privilegeLevel === 'owner') {
+         ownerFeatures = member.user.features
+         owner = this.buildUserModelView(member.user, 'owner')
+@@ -128,24 +122,15 @@
+   },
+
+   buildFolderModelView(folder) {
+-    let file
+     const fileRefs = _.filter(folder.fileRefs || [], file => file != null)
+     return {
+       _id: folder._id,
+       name: folder.name,
+-      folders: Array.from(folder.folders || []).map(childFolder =>
++      folders: (folder.folders || []).map(childFolder =>
+         this.buildFolderModelView(childFolder)
+       ),
+-      fileRefs: (() => {
+-        const result = []
+-        for (file of Array.from(fileRefs)) {
+-          result.push(this.buildFileModelView(file))
+-        }
+-        return result
+-      })(),
+-      docs: Array.from(folder.docs || []).map(doc =>
+-        this.buildDocModelView(doc)
+-      ),
++      fileRefs: fileRefs.map(file => this.buildFileModelView(file)),
++      docs: (folder.docs || []).map(doc => this.buildDocModelView(doc)),
+     }
+   },
+
+@@ -164,4 +149,21 @@
+       name: doc.name,
+     }
+   },
++
++  buildInvitesView(invites) {
++    if (invites == null) {
++      return []
++    }
++    return invites.map(invite =>
++      _.pick(invite, [
++        '_id',
++        'createdAt',
++        'email',
++        'expires',
++        'privileges',
++        'projectId',
++        'sendingUserId',
++      ])
++    )
++  },
+ }