Merge pull request #19357 from overleaf/msm-hotfix-4-2-7

[CE/SP] Hotfix 4.2.7/5.0.7

GitOrigin-RevId: e36a5af392c2356d4068a98acc2d637d879392f8
This commit is contained in:
Jakob Ackermann 2024-07-12 11:25:45 +02:00 committed by Copybot
parent b442a74f54
commit 788009330c
10 changed files with 318 additions and 0 deletions

View file

@ -0,0 +1,13 @@
FROM sharelatex/sharelatex:4.2.6
COPY pr_19293.patch .
RUN patch -p1 < pr_19293.patch && rm pr_19293.patch
COPY pr_19296.patch .
RUN patch -p1 < pr_19296.patch && rm pr_19296.patch
COPY pr_19297.patch .
RUN patch -p1 < pr_19297.patch && rm pr_19297.patch
COPY pr_19071.patch .
RUN patch -p1 < pr_19071.patch && rm pr_19071.patch

View file

@ -0,0 +1,37 @@
--- a/services/web/app/src/Features/Collaborators/CollaboratorsInviteHandler.js
+++ b/services/web/app/src/Features/Collaborators/CollaboratorsInviteHandler.js
@@ -7,13 +7,16 @@ const UserGetter = require('../User/UserGetter')
const ProjectGetter = require('../Project/ProjectGetter')
const Crypto = require('crypto')
const NotificationsBuilder = require('../Notifications/NotificationsBuilder')
+const _ = require('lodash')
const randomBytes = promisify(Crypto.randomBytes)
const CollaboratorsInviteHandler = {
async getAllInvites(projectId) {
logger.debug({ projectId }, 'fetching invites for project')
- const invites = await ProjectInvite.find({ projectId }).exec()
+ const invites = await ProjectInvite.find({ projectId })
+ .select('_id email sendingUserId projectId privileges createdAt expires')
+ .exec()
logger.debug(
{ projectId, count: invites.length },
'found invites for project'
@@ -101,7 +104,15 @@ const CollaboratorsInviteHandler = {
logger.err({ err, projectId, email }, 'error sending messages for invite')
})
- return invite
+ return _.pick(invite.toObject(), [
+ 'email',
+ 'sendingUserId',
+ 'projectId',
+ 'privileges',
+ '_id',
+ 'createdAt',
+ 'expires',
+ ])
},
async revokeInvite(projectId, inviteId) {

View file

@ -0,0 +1,17 @@
--- a/services/clsi/app/js/StaticServerForbidSymlinks.js
+++ b/services/clsi/app/js/StaticServerForbidSymlinks.js
@@ -25,9 +25,13 @@ module.exports = ForbidSymlinks = function (staticFn, root, options) {
let file, projectId, result
const path = req.url
// check that the path is of the form /project_id_or_name/path/to/file.log
- if ((result = path.match(/^\/?([a-zA-Z0-9_-]+)\/(.*)/))) {
+ if ((result = path.match(/^\/([a-zA-Z0-9_-]+)\/(.*)$/s))) {
projectId = result[1]
file = result[2]
+ if (path !== `/${projectId}/${file}`) {
+ logger.warn({ path }, 'unrecognized file request')
+ return res.sendStatus(404)
+ }
} else {
logger.warn({ path }, 'unrecognized file request')
return res.sendStatus(404)

View file

@ -0,0 +1,22 @@
--- a/services/clsi/app/js/LatexRunner.js
+++ b/services/clsi/app/js/LatexRunner.js
@@ -110,11 +110,14 @@ function _writeLogOutput(projectId, directory, output, callback) {
// internal method for writing non-empty log files
function _writeFile(file, content, cb) {
if (content && content.length > 0) {
- fs.writeFile(file, content, err => {
- if (err) {
- logger.error({ err, projectId, file }, 'error writing log file') // don't fail on error
- }
- cb()
+ fs.unlink(file, () => {
+ fs.writeFile(file, content, { flag: 'wx' }, err => {
+ if (err) {
+ // don't fail on error
+ logger.error({ err, projectId, file }, 'error writing log file')
+ }
+ cb()
+ })
})
} else {
cb()

View file

@ -0,0 +1,70 @@
--- a/services/web/app/src/Features/Spelling/SpellingController.js
+++ b/services/web/app/src/Features/Spelling/SpellingController.js
@@ -28,39 +28,35 @@ module.exports = {
})
},
- proxyRequestToSpellingApi(req, res) {
+ proxyCheckRequestToSpellingApi(req, res) {
const { language } = req.body
- let url = req.url.slice('/spelling'.length)
-
- if (url === '/check') {
- if (!language) {
- logger.error('"language" field should be included for spell checking')
- return res.status(422).json({ misspellings: [] })
- }
+ if (!language) {
+ logger.error({}, '"language" field should be included for spell checking')
+ return res.status(422).json({ misspellings: [] })
+ }
- if (!languageCodeIsSupported(language)) {
- // this log statement can be changed to 'error' once projects with
- // unsupported languages are removed from the DB
- logger.debug({ language }, 'language not supported')
- return res.status(422).json({ misspellings: [] })
- }
+ if (!languageCodeIsSupported(language)) {
+ // this log statement can be changed to 'error' once projects with
+ // unsupported languages are removed from the DB
+ logger.debug({ language }, 'language not supported')
+ return res.status(422).json({ misspellings: [] })
}
const userId = SessionManager.getLoggedInUserId(req.session)
- url = `/user/${userId}${url}`
+ const url = `${Settings.apis.spelling.url}/user/${userId}/check`
req.headers.Host = Settings.apis.spelling.host
return request({
- url: Settings.apis.spelling.url + url,
- method: req.method,
+ url,
+ method: 'POST',
headers: req.headers,
json: req.body,
timeout: TEN_SECONDS,
})
.on('error', function (error) {
- logger.error({ err: error }, 'Spelling API error')
+ logger.error({ err: error }, 'Spelling Check API error')
return res.status(500).end()
})
.pipe(res)
},
-}
+}
\ No newline at end of file
--- a/services/web/app/src/router.js
+++ b/services/web/app/src/router.js
@@ -1083,7 +1083,7 @@ function initialize(webRouter, privateApiRouter, publicApiRouter) {
webRouter.post(
'/spelling/check',
AuthenticationController.requireLogin(),
- SpellingController.proxyRequestToSpellingApi
+ SpellingController.proxyCheckRequestToSpellingApi
)
webRouter.post(
'/spelling/learn',

View file

@ -0,0 +1,13 @@
FROM sharelatex/sharelatex:5.0.6
COPY pr_19293.patch .
RUN patch -p1 < pr_19293.patch && rm pr_19293.patch
COPY pr_19296.patch .
RUN patch -p1 < pr_19296.patch && rm pr_19296.patch
COPY pr_19297.patch .
RUN patch -p1 < pr_19297.patch && rm pr_19297.patch
COPY pr_19071.patch .
RUN patch -p1 < pr_19071.patch && rm pr_19071.patch

View file

@ -0,0 +1,37 @@
--- a/services/web/app/src/Features/Collaborators/CollaboratorsInviteHandler.js
+++ b/services/web/app/src/Features/Collaborators/CollaboratorsInviteHandler.js
@@ -7,13 +7,16 @@ const UserGetter = require('../User/UserGetter')
const ProjectGetter = require('../Project/ProjectGetter')
const Crypto = require('crypto')
const NotificationsBuilder = require('../Notifications/NotificationsBuilder')
+const _ = require('lodash')
const randomBytes = promisify(Crypto.randomBytes)
const CollaboratorsInviteHandler = {
async getAllInvites(projectId) {
logger.debug({ projectId }, 'fetching invites for project')
- const invites = await ProjectInvite.find({ projectId }).exec()
+ const invites = await ProjectInvite.find({ projectId })
+ .select('_id email sendingUserId projectId privileges createdAt expires')
+ .exec()
logger.debug(
{ projectId, count: invites.length },
'found invites for project'
@@ -101,7 +104,15 @@ const CollaboratorsInviteHandler = {
logger.err({ err, projectId, email }, 'error sending messages for invite')
})
- return invite
+ return _.pick(invite.toObject(), [
+ 'email',
+ 'sendingUserId',
+ 'projectId',
+ 'privileges',
+ '_id',
+ 'createdAt',
+ 'expires',
+ ])
},
async revokeInvite(projectId, inviteId) {

View file

@ -0,0 +1,17 @@
--- a/services/clsi/app/js/StaticServerForbidSymlinks.js
+++ b/services/clsi/app/js/StaticServerForbidSymlinks.js
@@ -25,9 +25,13 @@ module.exports = ForbidSymlinks = function (staticFn, root, options) {
let file, projectId, result
const path = req.url
// check that the path is of the form /project_id_or_name/path/to/file.log
- if ((result = path.match(/^\/?([a-zA-Z0-9_-]+)\/(.*)/))) {
+ if ((result = path.match(/^\/([a-zA-Z0-9_-]+)\/(.*)$/s))) {
projectId = result[1]
file = result[2]
+ if (path !== `/${projectId}/${file}`) {
+ logger.warn({ path }, 'unrecognized file request')
+ return res.sendStatus(404)
+ }
} else {
logger.warn({ path }, 'unrecognized file request')
return res.sendStatus(404)

View file

@ -0,0 +1,22 @@
--- a/services/clsi/app/js/LatexRunner.js
+++ b/services/clsi/app/js/LatexRunner.js
@@ -110,11 +110,14 @@ function _writeLogOutput(projectId, directory, output, callback) {
// internal method for writing non-empty log files
function _writeFile(file, content, cb) {
if (content && content.length > 0) {
- fs.writeFile(file, content, err => {
- if (err) {
- logger.error({ err, projectId, file }, 'error writing log file') // don't fail on error
- }
- cb()
+ fs.unlink(file, () => {
+ fs.writeFile(file, content, { flag: 'wx' }, err => {
+ if (err) {
+ // don't fail on error
+ logger.error({ err, projectId, file }, 'error writing log file')
+ }
+ cb()
+ })
})
} else {
cb()

View file

@ -0,0 +1,70 @@
--- a/services/web/app/src/Features/Spelling/SpellingController.js
+++ b/services/web/app/src/Features/Spelling/SpellingController.js
@@ -28,39 +28,35 @@ module.exports = {
})
},
- proxyRequestToSpellingApi(req, res) {
+ proxyCheckRequestToSpellingApi(req, res) {
const { language } = req.body
- let url = req.url.slice('/spelling'.length)
-
- if (url === '/check') {
- if (!language) {
- logger.error('"language" field should be included for spell checking')
- return res.status(422).json({ misspellings: [] })
- }
+ if (!language) {
+ logger.error({}, '"language" field should be included for spell checking')
+ return res.status(422).json({ misspellings: [] })
+ }
- if (!languageCodeIsSupported(language)) {
- // this log statement can be changed to 'error' once projects with
- // unsupported languages are removed from the DB
- logger.debug({ language }, 'language not supported')
- return res.status(422).json({ misspellings: [] })
- }
+ if (!languageCodeIsSupported(language)) {
+ // this log statement can be changed to 'error' once projects with
+ // unsupported languages are removed from the DB
+ logger.debug({ language }, 'language not supported')
+ return res.status(422).json({ misspellings: [] })
}
const userId = SessionManager.getLoggedInUserId(req.session)
- url = `/user/${userId}${url}`
+ const url = `${Settings.apis.spelling.url}/user/${userId}/check`
req.headers.Host = Settings.apis.spelling.host
return request({
- url: Settings.apis.spelling.url + url,
- method: req.method,
+ url,
+ method: 'POST',
headers: req.headers,
json: req.body,
timeout: TEN_SECONDS,
})
.on('error', function (error) {
- logger.error({ err: error }, 'Spelling API error')
+ logger.error({ err: error }, 'Spelling Check API error')
return res.status(500).end()
})
.pipe(res)
},
-}
+}
\ No newline at end of file
--- a/services/web/app/src/router.js
+++ b/services/web/app/src/router.js
@@ -1083,7 +1083,7 @@ function initialize(webRouter, privateApiRouter, publicApiRouter) {
webRouter.post(
'/spelling/check',
AuthenticationController.requireLogin(),
- SpellingController.proxyRequestToSpellingApi
+ SpellingController.proxyCheckRequestToSpellingApi
)
webRouter.post(
'/spelling/learn',