Kaynağa Gözat

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

[CE/SP] Hotfix 4.2.7/5.0.7

GitOrigin-RevId: e36a5af392c2356d4068a98acc2d637d879392f8
Jakob Ackermann 2 yıl önce
ebeveyn
işleme
788009330c

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

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

+ 37 - 0
server-ce/hotfix/4.2.7/pr_19071.patch

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

+ 17 - 0
server-ce/hotfix/4.2.7/pr_19293.patch

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

+ 22 - 0
server-ce/hotfix/4.2.7/pr_19296.patch

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

+ 70 - 0
server-ce/hotfix/4.2.7/pr_19297.patch

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

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

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

+ 37 - 0
server-ce/hotfix/5.0.7/pr_19071.patch

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

+ 17 - 0
server-ce/hotfix/5.0.7/pr_19293.patch

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

+ 22 - 0
server-ce/hotfix/5.0.7/pr_19296.patch

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

+ 70 - 0
server-ce/hotfix/5.0.7/pr_19297.patch

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