[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
This commit is contained in:
Miguel Serrano 2023-07-20 12:24:55 +02:00 committed by Copybot
parent d2f470450e
commit 59fe2fe463
7 changed files with 241 additions and 0 deletions

View file

@ -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

View file

@ -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);

View file

@ -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',
+ ])
+ )
+ },
}

View file

@ -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

View file

@ -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);

View file

@ -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) {

View file

@ -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',
+ ])
+ )
+ },
}