mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-09 05:16:02 +00:00
Merge pull request #1072 from sharelatex/spd-open-with-overleaf
Implement v1 open-with-overleaf API in v2 (part 1) GitOrigin-RevId: 488f4eeefc29086a72295ccbc7c63d2f927add12
This commit is contained in:
parent
9d4c3039e7
commit
af2d959504
16 changed files with 338 additions and 87 deletions
|
@ -0,0 +1,13 @@
|
|||
module.exports = DocumentHelper =
|
||||
getTitleFromTexContent: (content, maxContentToScan = 30000) ->
|
||||
TITLE_WITH_CURLY_BRACES = /\\[tT]itle\*?\s*{([^}]+)}/
|
||||
TITLE_WITH_SQUARE_BRACES = /\\[tT]itle\s*\[([^\]]+)\]/
|
||||
ESCAPED_BRACES = /\\([{}\[\]])/g
|
||||
content = content.substring(0, maxContentToScan).split("\n") if typeof content is 'string'
|
||||
title = null
|
||||
for line in content
|
||||
match = line.match(TITLE_WITH_SQUARE_BRACES) || line.match(TITLE_WITH_CURLY_BRACES)
|
||||
if match?
|
||||
title = match[1].replace(ESCAPED_BRACES, (br)->br[1])
|
||||
break
|
||||
return title
|
14
services/web/app/coffee/Features/Helpers/UrlHelper.coffee
Normal file
14
services/web/app/coffee/Features/Helpers/UrlHelper.coffee
Normal file
|
@ -0,0 +1,14 @@
|
|||
Settings = require 'settings-sharelatex'
|
||||
|
||||
module.exports = UrlHelper =
|
||||
|
||||
wrapUrlWithProxy: (url) ->
|
||||
# TODO: Consider what to do for Community and Enterprise edition?
|
||||
if !Settings.apis?.linkedUrlProxy?.url?
|
||||
throw new Error('no linked url proxy configured')
|
||||
return "#{Settings.apis.linkedUrlProxy.url}?url=#{encodeURIComponent(url)}"
|
||||
|
||||
prependHttpIfNeeded: (url) ->
|
||||
if !url.match('://')
|
||||
url = 'http://' + url
|
||||
return url
|
|
@ -1,10 +1,9 @@
|
|||
request = require 'request'
|
||||
_ = require "underscore"
|
||||
urlValidator = require 'valid-url'
|
||||
Settings = require 'settings-sharelatex'
|
||||
{ InvalidUrlError, UrlFetchFailedError } = require './LinkedFilesErrors'
|
||||
LinkedFilesHandler = require './LinkedFilesHandler'
|
||||
|
||||
UrlHelper = require '../Helpers/UrlHelper'
|
||||
|
||||
module.exports = UrlAgent = {
|
||||
|
||||
|
@ -36,7 +35,7 @@ module.exports = UrlAgent = {
|
|||
_sanitizeData: (data) ->
|
||||
return {
|
||||
provider: data.provider
|
||||
url: @._prependHttpIfNeeded(data.url)
|
||||
url: UrlHelper.prependHttpIfNeeded(data.url)
|
||||
}
|
||||
|
||||
_getUrlStream: (project_id, data, current_user_id, callback = (error, fsPath) ->) ->
|
||||
|
@ -44,19 +43,9 @@ module.exports = UrlAgent = {
|
|||
url = data.url
|
||||
if !urlValidator.isWebUri(url)
|
||||
return callback(new InvalidUrlError("invalid url: #{url}"))
|
||||
url = @_wrapWithProxy(url)
|
||||
url = UrlHelper.wrapUrlWithProxy(url)
|
||||
readStream = request.get(url)
|
||||
readStream.pause()
|
||||
callback(null, readStream)
|
||||
|
||||
_prependHttpIfNeeded: (url) ->
|
||||
if !url.match('://')
|
||||
url = 'http://' + url
|
||||
return url
|
||||
|
||||
_wrapWithProxy: (url) ->
|
||||
# TODO: Consider what to do for Community and Enterprise edition?
|
||||
if !Settings.apis?.linkedUrlProxy?.url?
|
||||
throw new Error('no linked url proxy configured')
|
||||
return "#{Settings.apis.linkedUrlProxy.url}?url=#{encodeURIComponent(url)}"
|
||||
}
|
||||
|
|
|
@ -64,18 +64,18 @@ module.exports = ProjectCreationHandler =
|
|||
return callback(err) if err?
|
||||
callback err, project
|
||||
|
||||
createProjectFromSnippet : (owner_id, projectName, docLines, callback = (error, project) ->)->
|
||||
@createBlankProject owner_id, projectName, (error, project)->
|
||||
return callback(error) if error?
|
||||
ProjectCreationHandler._createRootDoc project, owner_id, docLines, callback
|
||||
|
||||
createBasicProject : (owner_id, projectName, callback = (error, project) ->)->
|
||||
self = @
|
||||
@createBlankProject owner_id, projectName, (error, project)->
|
||||
return callback(error) if error?
|
||||
self._buildTemplate "mainbasic.tex", owner_id, projectName, (error, docLines)->
|
||||
return callback(error) if error?
|
||||
ProjectEntityUpdateHandler.addDoc project._id, project.rootFolder[0]._id, "main.tex", docLines, owner_id, (error, doc)->
|
||||
if error?
|
||||
logger.err err:error, "error adding doc when creating basic project"
|
||||
return callback(error)
|
||||
ProjectEntityUpdateHandler.setRootDoc project._id, doc._id, (error) ->
|
||||
callback(error, project)
|
||||
ProjectCreationHandler._createRootDoc project, owner_id, docLines, callback
|
||||
|
||||
createExampleProject: (owner_id, projectName, callback = (error, project) ->)->
|
||||
self = @
|
||||
|
@ -85,9 +85,7 @@ module.exports = ProjectCreationHandler =
|
|||
(callback) ->
|
||||
self._buildTemplate "main.tex", owner_id, projectName, (error, docLines)->
|
||||
return callback(error) if error?
|
||||
ProjectEntityUpdateHandler.addDoc project._id, project.rootFolder[0]._id, "main.tex", docLines, owner_id, (error, doc)->
|
||||
return callback(error) if error?
|
||||
ProjectEntityUpdateHandler.setRootDoc project._id, doc._id, callback
|
||||
ProjectCreationHandler._createRootDoc project, owner_id, docLines, callback
|
||||
(callback) ->
|
||||
self._buildTemplate "references.bib", owner_id, projectName, (error, docLines)->
|
||||
return callback(error) if error?
|
||||
|
@ -99,6 +97,14 @@ module.exports = ProjectCreationHandler =
|
|||
], (error) ->
|
||||
callback(error, project)
|
||||
|
||||
_createRootDoc: (project, owner_id, docLines, callback = (error, project) ->)->
|
||||
ProjectEntityUpdateHandler.addDoc project._id, project.rootFolder[0]._id, "main.tex", docLines, owner_id, (error, doc)->
|
||||
if error?
|
||||
logger.err err:error, "error adding root doc when creating project"
|
||||
return callback(error)
|
||||
ProjectEntityUpdateHandler.setRootDoc project._id, doc._id, (error) ->
|
||||
callback(error, project)
|
||||
|
||||
_buildTemplate: (template_name, user_id, project_name, callback = (error, output) ->)->
|
||||
User.findById user_id, "first_name last_name", (error, user)->
|
||||
return callback(error) if error?
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
ENGINE_TO_COMPILER_MAP = {
|
||||
latex_dvipdf: "latex"
|
||||
pdflatex: "pdflatex"
|
||||
xelatex: "xelatex"
|
||||
lualatex: "lualatex"
|
||||
}
|
||||
|
||||
module.exports =
|
||||
compilerFromV1Engine: (engine) ->
|
||||
return ENGINE_TO_COMPILER_MAP[engine]
|
|
@ -1,15 +1,9 @@
|
|||
path = require('path')
|
||||
AuthenticationController = require('../../../js/Features/Authentication/AuthenticationController')
|
||||
TemplatesManager = require('./TemplatesManager')
|
||||
ProjectHelper = require('../../../js/Features/Project/ProjectHelper')
|
||||
logger = require('logger-sharelatex')
|
||||
|
||||
ENGINE_TO_COMPILER_MAP = {
|
||||
latex_dvipdf: "latex"
|
||||
pdflatex: "pdflatex"
|
||||
xelatex: "xelatex"
|
||||
lualatex: "lualatex"
|
||||
}
|
||||
|
||||
module.exports = TemplatesController =
|
||||
|
||||
getV1Template: (req, res)->
|
||||
|
@ -22,7 +16,7 @@ module.exports = TemplatesController =
|
|||
data.templateVersionId = templateVersionId
|
||||
data.templateId = templateId
|
||||
data.name = req.query.templateName
|
||||
data.compiler = ENGINE_TO_COMPILER_MAP[req.query.latexEngine]
|
||||
data.compiler = ProjectHelper.compilerFromV1Engine(req.query.latexEngine)
|
||||
data.mainFile = req.query.mainFile
|
||||
data.brandVariationId = req.query.brandVariationId
|
||||
res.render path.resolve(__dirname, "../../../views/project/editor/new_from_template"), data
|
||||
|
|
44
services/web/app/coffee/infrastructure/Csrf.coffee
Normal file
44
services/web/app/coffee/infrastructure/Csrf.coffee
Normal file
|
@ -0,0 +1,44 @@
|
|||
csurf = require('csurf')
|
||||
csrf = csurf()
|
||||
|
||||
# Wrapper for `csurf` middleware that provides a list of routes that can be excluded from csrf checks.
|
||||
#
|
||||
# Include with `Csrf = require('./Csrf')`
|
||||
#
|
||||
# Add the middleware to the router with:
|
||||
# myRouter.csrf = new Csrf()
|
||||
# myRouter.use webRouter.csrf.middleware
|
||||
# When building routes, specify a route to exclude from csrf checks with:
|
||||
# myRouter.csrf.disableDefaultCsrfProtection "/path" "METHOD"
|
||||
#
|
||||
# To validate the csrf token in a request to ensure that it's valid, you can use `validateRequest`, which takes a
|
||||
# request object and calls a callback with either true or false.
|
||||
|
||||
module.exports = class Csrf
|
||||
constructor: ->
|
||||
@excluded_routes = {}
|
||||
|
||||
disableDefaultCsrfProtection: (route, method) ->
|
||||
@excluded_routes[route] = {} unless @excluded_routes[route]
|
||||
@excluded_routes[route][method] = 1
|
||||
|
||||
middleware: (req, res, next) =>
|
||||
# We want to call the middleware for all routes, even if excluded, because csurf sets up a csrfToken() method on
|
||||
# the request, to get a new csrf token for any rendered forms. For excluded routes we'll then ignore a 'bad csrf
|
||||
# token' error from csurf and continue on...
|
||||
|
||||
# check whether the request method is excluded for the specified route
|
||||
if @excluded_routes[req.path]?[req.method] == 1
|
||||
# ignore the error if it's due to a bad csrf token, and continue
|
||||
csrf req, res, (err) =>
|
||||
if (err && err.code != 'EBADCSRFTOKEN')
|
||||
next(err)
|
||||
else
|
||||
next()
|
||||
else
|
||||
csrf req, res, next
|
||||
|
||||
@validateRequest: (req, cb = (valid)->) ->
|
||||
# run a dummy csrf check to see if it returns an error
|
||||
csrf req, null, (err) ->
|
||||
cb(!err?)
|
|
@ -9,6 +9,7 @@ Router = require('../router')
|
|||
helmet = require "helmet"
|
||||
metrics.inc("startup")
|
||||
UserSessionsRedis = require('../Features/User/UserSessionsRedis')
|
||||
Csrf = require('./Csrf')
|
||||
|
||||
sessionsRedisClient = UserSessionsRedis.client()
|
||||
|
||||
|
@ -17,8 +18,6 @@ RedisStore = require('connect-redis')(session)
|
|||
bodyParser = require('body-parser')
|
||||
multer = require('multer')
|
||||
methodOverride = require('method-override')
|
||||
csrf = require('csurf')
|
||||
csrfProtection = csrf()
|
||||
cookieParser = require('cookie-parser')
|
||||
bearerToken = require('express-bearer-token')
|
||||
|
||||
|
@ -114,7 +113,8 @@ Modules.hooks.fire 'passportSetup', passport, (err) ->
|
|||
|
||||
Modules.applyNonCsrfRouter(webRouter, privateApiRouter, publicApiRouter)
|
||||
|
||||
webRouter.use csrfProtection
|
||||
webRouter.csrf = new Csrf()
|
||||
webRouter.use webRouter.csrf.middleware
|
||||
webRouter.use translations.expressMiddlewear
|
||||
webRouter.use translations.setLangBasedOnDomainMiddlewear
|
||||
|
||||
|
|
90
services/web/npm-shrinkwrap.json
generated
90
services/web/npm-shrinkwrap.json
generated
|
@ -618,7 +618,7 @@
|
|||
"babel-loader": {
|
||||
"version": "7.1.4",
|
||||
"from": "babel-loader@>=7.1.2 <8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.4.tgz",
|
||||
"resolved": "http://registry.npmjs.org/babel-loader/-/babel-loader-7.1.4.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"babel-messages": {
|
||||
|
@ -1525,7 +1525,7 @@
|
|||
"capture-stack-trace": {
|
||||
"version": "1.0.0",
|
||||
"from": "capture-stack-trace@>=1.0.0 <2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"caseless": {
|
||||
|
@ -1606,13 +1606,13 @@
|
|||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"from": "readable-stream@^2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"readdirp": {
|
||||
"version": "2.1.0",
|
||||
"from": "readdirp@>=2.0.0 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"string_decoder": {
|
||||
|
@ -1631,7 +1631,7 @@
|
|||
"ci-info": {
|
||||
"version": "1.1.3",
|
||||
"from": "ci-info@>=1.0.0 <2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.1.3.tgz",
|
||||
"resolved": "http://registry.npmjs.org/ci-info/-/ci-info-1.1.3.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"cipher-base": {
|
||||
|
@ -1822,7 +1822,7 @@
|
|||
"compressible": {
|
||||
"version": "2.0.13",
|
||||
"from": "compressible@>=2.0.13 <2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.13.tgz",
|
||||
"resolved": "http://registry.npmjs.org/compressible/-/compressible-2.0.13.tgz",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"mime-db": {
|
||||
|
@ -2039,7 +2039,7 @@
|
|||
"contentful-sdk-core": {
|
||||
"version": "6.0.0-beta1",
|
||||
"from": "contentful-sdk-core@>=6.0.0-beta0 <7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/contentful-sdk-core/-/contentful-sdk-core-6.0.0-beta1.tgz"
|
||||
"resolved": "http://registry.npmjs.org/contentful-sdk-core/-/contentful-sdk-core-6.0.0-beta1.tgz"
|
||||
},
|
||||
"continuable-cache": {
|
||||
"version": "0.3.1",
|
||||
|
@ -2493,7 +2493,7 @@
|
|||
"detect-node": {
|
||||
"version": "2.0.3",
|
||||
"from": "detect-node@>=2.0.3 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.3.tgz",
|
||||
"resolved": "http://registry.npmjs.org/detect-node/-/detect-node-2.0.3.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"di": {
|
||||
|
@ -2836,7 +2836,7 @@
|
|||
"es-to-primitive": {
|
||||
"version": "1.1.1",
|
||||
"from": "es-to-primitive@>=1.1.1 <2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz",
|
||||
"resolved": "http://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"es5-ext": {
|
||||
|
@ -3104,7 +3104,7 @@
|
|||
"eslint-plugin-import": {
|
||||
"version": "2.11.0",
|
||||
"from": "eslint-plugin-import@>=2.9.0 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.11.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.11.0.tgz",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
|
@ -3188,7 +3188,7 @@
|
|||
"eslint-plugin-promise": {
|
||||
"version": "3.7.0",
|
||||
"from": "eslint-plugin-promise@>=3.6.0 <4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.7.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.7.0.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"eslint-plugin-react": {
|
||||
|
@ -3694,7 +3694,7 @@
|
|||
"follow-redirects": {
|
||||
"version": "1.0.0",
|
||||
"from": "follow-redirects@1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
|
@ -3878,7 +3878,7 @@
|
|||
"generate-function": {
|
||||
"version": "2.0.0",
|
||||
"from": "generate-function@>=2.0.0 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
|
@ -3948,7 +3948,7 @@
|
|||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"from": "readable-stream@2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
|
@ -4538,7 +4538,7 @@
|
|||
"async": {
|
||||
"version": "1.5.2",
|
||||
"from": "async@>=1.4.0 <2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz"
|
||||
"resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz"
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.4.4",
|
||||
|
@ -4562,7 +4562,7 @@
|
|||
"yargs": {
|
||||
"version": "3.10.0",
|
||||
"from": "yargs@>=3.10.0 <3.11.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
|
@ -5432,7 +5432,7 @@
|
|||
"is-symbol": {
|
||||
"version": "1.0.1",
|
||||
"from": "is-symbol@>=1.0.1 <2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz",
|
||||
"resolved": "http://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"is-typedarray": {
|
||||
|
@ -5849,7 +5849,7 @@
|
|||
"killable": {
|
||||
"version": "1.0.0",
|
||||
"from": "killable@>=1.0.0 <2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/killable/-/killable-1.0.0.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"kind-of": {
|
||||
|
@ -6200,7 +6200,7 @@
|
|||
"lodash": {
|
||||
"version": "4.17.4",
|
||||
"from": "lodash@>=4.13.1 <5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
|
||||
"resolved": "http://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
|
||||
},
|
||||
"lodash.assign": {
|
||||
"version": "4.2.0",
|
||||
|
@ -6782,7 +6782,7 @@
|
|||
"commander": {
|
||||
"version": "2.15.1",
|
||||
"from": "commander@>=2.9.0 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
|
||||
"resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
|
@ -7031,7 +7031,7 @@
|
|||
"map-stream": {
|
||||
"version": "0.1.0",
|
||||
"from": "map-stream@>=0.1.0 <0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"map-visit": {
|
||||
|
@ -7121,7 +7121,7 @@
|
|||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"from": "minimist@>=1.1.3 <2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"path-exists": {
|
||||
|
@ -7340,10 +7340,22 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"mmmagic": {
|
||||
"version": "0.5.2",
|
||||
"from": "mmmagic@latest",
|
||||
"resolved": "https://registry.npmjs.org/mmmagic/-/mmmagic-0.5.2.tgz",
|
||||
"dependencies": {
|
||||
"nan": {
|
||||
"version": "2.11.1",
|
||||
"from": "nan@>=2.11.0 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.11.1.tgz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mocha": {
|
||||
"version": "5.0.1",
|
||||
"from": "mocha@5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mocha/-/mocha-5.0.1.tgz",
|
||||
"resolved": "http://registry.npmjs.org/mocha/-/mocha-5.0.1.tgz",
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "2.11.0",
|
||||
|
@ -7900,7 +7912,7 @@
|
|||
"chokidar": {
|
||||
"version": "2.0.3",
|
||||
"from": "chokidar@>=2.0.2 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz",
|
||||
"resolved": "http://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
|
@ -8112,13 +8124,13 @@
|
|||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"from": "readable-stream@^2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"readdirp": {
|
||||
"version": "2.1.0",
|
||||
"from": "readdirp@^2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
|
@ -8481,7 +8493,7 @@
|
|||
"opn": {
|
||||
"version": "5.3.0",
|
||||
"from": "opn@>=5.1.0 <6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/opn/-/opn-5.3.0.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"optimist": {
|
||||
|
@ -9201,7 +9213,7 @@
|
|||
"proxy-agent": {
|
||||
"version": "3.0.0",
|
||||
"from": "proxy-agent@>=3.0.0 <3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-3.0.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/proxy-agent/-/proxy-agent-3.0.0.tgz",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
|
@ -9254,7 +9266,7 @@
|
|||
"event-stream": {
|
||||
"version": "3.3.4",
|
||||
"from": "event-stream@>=3.3.0 <3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
|
||||
"resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"ps-tree": {
|
||||
|
@ -9424,7 +9436,7 @@
|
|||
"querystringify": {
|
||||
"version": "0.0.4",
|
||||
"from": "querystringify@>=0.0.0 <0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-0.0.4.tgz",
|
||||
"resolved": "http://registry.npmjs.org/querystringify/-/querystringify-0.0.4.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"quick-lru": {
|
||||
|
@ -10006,7 +10018,7 @@
|
|||
"sanitize-html": {
|
||||
"version": "1.18.2",
|
||||
"from": "sanitize-html@>=1.14.1 <2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-1.18.2.tgz",
|
||||
"resolved": "http://registry.npmjs.org/sanitize-html/-/sanitize-html-1.18.2.tgz",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
|
@ -10145,7 +10157,7 @@
|
|||
"lodash": {
|
||||
"version": "4.12.0",
|
||||
"from": "lodash@4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.12.0.tgz"
|
||||
"resolved": "http://registry.npmjs.org/lodash/-/lodash-4.12.0.tgz"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -10677,7 +10689,7 @@
|
|||
"split": {
|
||||
"version": "0.3.3",
|
||||
"from": "split@>=0.3.0 <0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
|
||||
"resolved": "http://registry.npmjs.org/split/-/split-0.3.3.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"split-string": {
|
||||
|
@ -10767,7 +10779,7 @@
|
|||
"stream-combiner": {
|
||||
"version": "0.0.4",
|
||||
"from": "stream-combiner@>=0.0.4 <0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
|
||||
"resolved": "http://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"stream-http": {
|
||||
|
@ -12297,7 +12309,7 @@
|
|||
"webpack-dev-server": {
|
||||
"version": "2.11.2",
|
||||
"from": "webpack-dev-server@>=2.11.1 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.11.2.tgz",
|
||||
"resolved": "http://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.11.2.tgz",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"accepts": {
|
||||
|
@ -12353,7 +12365,7 @@
|
|||
"chokidar": {
|
||||
"version": "2.0.3",
|
||||
"from": "chokidar@>=2.0.0 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz",
|
||||
"resolved": "http://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"cliui": {
|
||||
|
@ -12521,7 +12533,7 @@
|
|||
"finalhandler": {
|
||||
"version": "1.1.1",
|
||||
"from": "finalhandler@1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
|
||||
"resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
|
@ -12773,13 +12785,13 @@
|
|||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"from": "readable-stream@^2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"readdirp": {
|
||||
"version": "2.1.0",
|
||||
"from": "readdirp@^2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"rimraf": {
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
"method-override": "^2.3.3",
|
||||
"metrics-sharelatex": "git+https://github.com/sharelatex/metrics-sharelatex.git#v1.8.0",
|
||||
"minimist": "1.2.0",
|
||||
"mmmagic": "^0.5.2",
|
||||
"mocha": "^5.0.1",
|
||||
"mongojs": "2.4.0",
|
||||
"mongoose": "4.11.4",
|
||||
|
|
|
@ -36,8 +36,8 @@ describe "RedirectUrls", ->
|
|||
it 'redirects to /sign_in_to_v1 with authWithV1 setting', (done) ->
|
||||
assertRedirect(
|
||||
'get',
|
||||
'/docs?zip_uri=http%3A%2F%2Foverleaf.test%2Ffoo%3Fbar%3Dbaz%26qux%3Dthing&bar=baz',
|
||||
'/docs_v1?zip_uri=http%3A%2F%2Foverleaf.test%2Ffoo%3Fbar%3Dbaz%26qux%3Dthing&bar=baz',
|
||||
302,
|
||||
'/sign_in_to_v1?return_to=%2Fdocs%3Fzip_uri%3Dhttp%253A%252F%252Foverleaf.test%252Ffoo%253Fbar%253Dbaz%2526qux%253Dthing%26bar%3Dbaz',
|
||||
done
|
||||
)
|
||||
)
|
||||
|
|
|
@ -137,7 +137,7 @@ module.exports =
|
|||
url: (params) -> "/destination/#{params.id}/params"
|
||||
},
|
||||
'/redirect/qs': '/destination/qs'
|
||||
'/docs': {
|
||||
'/docs_v1': {
|
||||
authWithV1: true
|
||||
url: '/docs'
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
sinon = require('sinon')
|
||||
chai = require('chai')
|
||||
should = chai.should()
|
||||
expect = chai.expect
|
||||
modulePath = "../../../../app/js/Features/Documents/DocumentHelper.js"
|
||||
SandboxedModule = require('sandboxed-module')
|
||||
|
||||
describe "DocumentHelper", ->
|
||||
beforeEach ->
|
||||
@DocumentHelper = SandboxedModule.require modulePath
|
||||
|
||||
describe "getTitleFromTexContent", ->
|
||||
|
||||
it "should return the title", ->
|
||||
document = "\\begin{document}\n\\title{foo}\n\\end{document}"
|
||||
expect(@DocumentHelper.getTitleFromTexContent(document)).to.equal "foo"
|
||||
|
||||
it "should return the title if surrounded by space", ->
|
||||
document = "\\begin{document}\n \\title{foo} \n\\end{document}"
|
||||
expect(@DocumentHelper.getTitleFromTexContent(document)).to.equal "foo"
|
||||
|
||||
it "should return null if there is no title", ->
|
||||
document = "\\begin{document}\n\\end{document}"
|
||||
expect(@DocumentHelper.getTitleFromTexContent(document)).to.eql null
|
||||
|
||||
it "should accept an array", ->
|
||||
document = ["\\begin{document}","\\title{foo}","\\end{document}"]
|
||||
expect(@DocumentHelper.getTitleFromTexContent(document)).to.equal "foo"
|
|
@ -189,24 +189,38 @@ describe 'ProjectCreationHandler', ->
|
|||
throw new Error("unknown template: #{template_name}")
|
||||
sinon.spy @handler, "_buildTemplate"
|
||||
@handler.createBlankProject = sinon.stub().callsArgWith(2, null, @project)
|
||||
@handler._createRootDoc = sinon.stub().callsArgWith(3, null, @project)
|
||||
@handler.createBasicProject(ownerId, projectName, @callback)
|
||||
|
||||
it "should create a blank project first", ->
|
||||
@handler.createBlankProject.calledWith(ownerId, projectName)
|
||||
.should.equal true
|
||||
|
||||
it 'should insert main.tex', ->
|
||||
@ProjectEntityUpdateHandler.addDoc.calledWith(project_id, rootFolderId, "main.tex", ["mainbasic.tex", "lines"], ownerId)
|
||||
it 'should create the root document', ->
|
||||
@handler._createRootDoc
|
||||
.calledWith(@project, ownerId, ["mainbasic.tex", "lines"])
|
||||
.should.equal true
|
||||
|
||||
it 'should set the main doc id', ->
|
||||
@ProjectEntityUpdateHandler.setRootDoc.calledWith(project_id, docId).should.equal true
|
||||
|
||||
it 'should build the mainbasic.tex template', ->
|
||||
@handler._buildTemplate
|
||||
.calledWith("mainbasic.tex", ownerId, projectName)
|
||||
.should.equal true
|
||||
|
||||
describe 'Creating a project from a snippet', ->
|
||||
beforeEach ->
|
||||
@project = new @ProjectModel
|
||||
@handler.createBlankProject = sinon.stub().callsArgWith(2, null, @project)
|
||||
@handler._createRootDoc = sinon.stub().callsArgWith(3, null, @project)
|
||||
@handler.createProjectFromSnippet(ownerId, projectName, ["snippet line 1", "snippet line 2"], @callback)
|
||||
|
||||
it "should create a blank project first", ->
|
||||
@handler.createBlankProject.calledWith(ownerId, projectName)
|
||||
.should.equal true
|
||||
|
||||
it 'should create the root document', ->
|
||||
@handler._createRootDoc
|
||||
.calledWith(@project, ownerId, ["snippet line 1", "snippet line 2"])
|
||||
.should.equal true
|
||||
|
||||
describe 'Creating an example project', ->
|
||||
beforeEach ->
|
||||
|
@ -219,15 +233,16 @@ describe 'ProjectCreationHandler', ->
|
|||
throw new Error("unknown template: #{template_name}")
|
||||
sinon.spy @handler, "_buildTemplate"
|
||||
@handler.createBlankProject = sinon.stub().callsArgWith(2, null, @project)
|
||||
@handler._createRootDoc = sinon.stub().callsArgWith(3, null, @project)
|
||||
@handler.createExampleProject(ownerId, projectName, @callback)
|
||||
|
||||
it "should create a blank project first", ->
|
||||
@handler.createBlankProject.calledWith(ownerId, projectName)
|
||||
.should.equal true
|
||||
|
||||
it 'should insert main.tex', ->
|
||||
@ProjectEntityUpdateHandler.addDoc
|
||||
.calledWith(project_id, rootFolderId, "main.tex", ["main.tex", "lines"], ownerId)
|
||||
it 'should create the root document', ->
|
||||
@handler._createRootDoc
|
||||
.calledWith(@project, ownerId, ["main.tex", "lines"])
|
||||
.should.equal true
|
||||
|
||||
it 'should insert references.bib', ->
|
||||
|
@ -245,9 +260,6 @@ describe 'ProjectCreationHandler', ->
|
|||
)
|
||||
.should.equal true
|
||||
|
||||
it 'should set the main doc id', ->
|
||||
@ProjectEntityUpdateHandler.setRootDoc.calledWith(project_id, docId).should.equal true
|
||||
|
||||
it 'should build the main.tex template', ->
|
||||
@handler._buildTemplate
|
||||
.calledWith("main.tex", ownerId, projectName)
|
||||
|
@ -287,3 +299,17 @@ describe 'ProjectCreationHandler', ->
|
|||
it "should put the year in", (done)->
|
||||
@template.indexOf(new Date().getUTCFullYear()).should.not.equal -1
|
||||
done()
|
||||
|
||||
describe "_createRootDoc", ->
|
||||
beforeEach (done)->
|
||||
@project = new @ProjectModel()
|
||||
|
||||
@handler._createRootDoc @project, ownerId, ["line 1", "line 2"], done
|
||||
|
||||
it 'should insert main.tex', ->
|
||||
@ProjectEntityUpdateHandler.addDoc
|
||||
.calledWith(project_id, rootFolderId, "main.tex", ["line 1", "line 2"], ownerId)
|
||||
.should.equal true
|
||||
|
||||
it 'should set the main doc id', ->
|
||||
@ProjectEntityUpdateHandler.setRootDoc.calledWith(project_id, docId).should.equal true
|
|
@ -0,0 +1,23 @@
|
|||
sinon = require('sinon')
|
||||
chai = require('chai')
|
||||
should = chai.should()
|
||||
expect = chai.expect
|
||||
modulePath = "../../../../app/js/Features/Project/ProjectHelper.js"
|
||||
SandboxedModule = require('sandboxed-module')
|
||||
|
||||
describe "ProjectHelper", ->
|
||||
beforeEach ->
|
||||
@ProjectHelper = SandboxedModule.require modulePath
|
||||
|
||||
describe "compilerFromV1Engine", ->
|
||||
it "returns the correct engine for latex_dvipdf", ->
|
||||
expect(@ProjectHelper.compilerFromV1Engine('latex_dvipdf')).to.equal 'latex'
|
||||
|
||||
it "returns the correct engine for pdflatex", ->
|
||||
expect(@ProjectHelper.compilerFromV1Engine('pdflatex')).to.equal 'pdflatex'
|
||||
|
||||
it "returns the correct engine for xelatex", ->
|
||||
expect(@ProjectHelper.compilerFromV1Engine('xelatex')).to.equal 'xelatex'
|
||||
|
||||
it "returns the correct engine for lualatex", ->
|
||||
expect(@ProjectHelper.compilerFromV1Engine('lualatex')).to.equal 'lualatex'
|
|
@ -0,0 +1,91 @@
|
|||
assert = require("chai").assert
|
||||
sinon = require('sinon')
|
||||
chai = require('chai')
|
||||
should = chai.should()
|
||||
expect = chai.expect
|
||||
modulePath = "../../../../app/js/infrastructure/Csrf.js"
|
||||
SandboxedModule = require('sandboxed-module')
|
||||
|
||||
describe "Csrf", ->
|
||||
|
||||
beforeEach ->
|
||||
@csurf_csrf = sinon.stub().callsArgWith(2, @err = {code: 'EBADCSRFTOKEN'})
|
||||
@Csrf = SandboxedModule.require modulePath, requires:
|
||||
csurf: sinon.stub().returns(@csurf_csrf)
|
||||
@csrf = new @Csrf()
|
||||
@next = sinon.stub()
|
||||
@path = '/foo/bar'
|
||||
@req =
|
||||
path: @path
|
||||
method: 'POST'
|
||||
@res = {}
|
||||
|
||||
describe 'the middleware', ->
|
||||
describe 'when there are no excluded routes', ->
|
||||
it 'passes the csrf error on', ->
|
||||
@csrf.middleware @req, @res, @next
|
||||
expect(@next.calledWith(@err)).to.equal true
|
||||
|
||||
describe 'when the route is excluded', ->
|
||||
it 'does not pass the csrf error on', ->
|
||||
@csrf.disableDefaultCsrfProtection(@path, 'POST')
|
||||
@csrf.middleware @req, @res, @next
|
||||
expect(@next.calledWith(@err)).to.equal false
|
||||
|
||||
describe 'when there is a partial route match', ->
|
||||
it 'passes the csrf error on when the match is too short', ->
|
||||
@csrf.disableDefaultCsrfProtection('/foo', 'POST')
|
||||
@csrf.middleware @req, @res, @next
|
||||
expect(@next.calledWith(@err)).to.equal true
|
||||
|
||||
it 'passes the csrf error on when the match is too long', ->
|
||||
@csrf.disableDefaultCsrfProtection('/foo/bar/baz', 'POST')
|
||||
@csrf.middleware @req, @res, @next
|
||||
expect(@next.calledWith(@err)).to.equal true
|
||||
|
||||
describe 'when there are multiple exclusions', ->
|
||||
it 'does not pass the csrf error on when the match is present', ->
|
||||
@csrf.disableDefaultCsrfProtection(@path, 'POST')
|
||||
@csrf.disableDefaultCsrfProtection('/test', 'POST')
|
||||
@csrf.disableDefaultCsrfProtection('/a/b/c', 'POST')
|
||||
@csrf.middleware @req, @res, @next
|
||||
expect(@next.calledWith(@err)).to.equal false
|
||||
|
||||
it 'passes the csrf error on when the match is not present', ->
|
||||
@csrf.disableDefaultCsrfProtection('/url', 'POST')
|
||||
@csrf.disableDefaultCsrfProtection('/test', 'POST')
|
||||
@csrf.disableDefaultCsrfProtection('/a/b/c', 'POST')
|
||||
@csrf.middleware @req, @res, @next
|
||||
expect(@next.calledWith(@err)).to.equal true
|
||||
|
||||
describe 'when the method does not match', ->
|
||||
it 'passes the csrf error on', ->
|
||||
@csrf.disableDefaultCsrfProtection(@path, 'POST')
|
||||
@req.method = 'GET'
|
||||
@csrf.middleware @req, @res, @next
|
||||
expect(@next.calledWith(@err)).to.equal true
|
||||
|
||||
describe 'when the route is excluded, but the error is not a bad-csrf-token error', ->
|
||||
it 'passes the error on', ->
|
||||
@Csrf = SandboxedModule.require modulePath, requires:
|
||||
csurf: @csurf = sinon.stub().returns(@csurf_csrf = sinon.stub().callsArgWith(2, err = {code: 'EOTHER'}))
|
||||
@csrf = new @Csrf()
|
||||
@csrf.disableDefaultCsrfProtection(@path, 'POST')
|
||||
@csrf.middleware @req, @res, @next
|
||||
expect(@next.calledWith(err)).to.equal true
|
||||
expect(@next.calledWith(@err)).to.equal false
|
||||
|
||||
describe 'validateRequest', ->
|
||||
describe 'when the request is invalid', ->
|
||||
it 'calls the callback with `false`', ->
|
||||
@cb = sinon.stub()
|
||||
@Csrf.validateRequest(@req, @cb)
|
||||
expect(@cb.calledWith(false)).to.equal true
|
||||
|
||||
describe 'when the request is valid', ->
|
||||
it 'calls the callback with `true`', ->
|
||||
@Csrf = SandboxedModule.require modulePath, requires:
|
||||
csurf: @csurf = sinon.stub().returns(@csurf_csrf = sinon.stub().callsArg(2))
|
||||
@cb = sinon.stub()
|
||||
@Csrf.validateRequest(@req, @cb)
|
||||
expect(@cb.calledWith(true)).to.equal true
|
Loading…
Add table
Reference in a new issue