mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
[misc] run format:fix
This commit is contained in:
parent
d812c86c51
commit
d7c641eaf7
3 changed files with 993 additions and 839 deletions
|
@ -16,42 +16,36 @@
|
||||||
* DS207: Consider shorter variations of null checks
|
* DS207: Consider shorter variations of null checks
|
||||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||||
*/
|
*/
|
||||||
const coffee = require("coffee-script");
|
const coffee = require('coffee-script')
|
||||||
const fs = require("fs");
|
const fs = require('fs')
|
||||||
const {
|
const { spawn } = require('child_process')
|
||||||
spawn
|
const { exec } = require('child_process')
|
||||||
} = require("child_process");
|
const rimraf = require('rimraf')
|
||||||
const {
|
const Path = require('path')
|
||||||
exec
|
const semver = require('semver')
|
||||||
} = require("child_process");
|
const knox = require('knox')
|
||||||
const rimraf = require("rimraf");
|
const crypto = require('crypto')
|
||||||
const Path = require("path");
|
const async = require('async')
|
||||||
const semver = require("semver");
|
const settings = require('settings-sharelatex')
|
||||||
const knox = require("knox");
|
const _ = require('underscore')
|
||||||
const crypto = require("crypto");
|
|
||||||
const async = require("async");
|
|
||||||
const settings = require("settings-sharelatex");
|
|
||||||
const _ = require("underscore");
|
|
||||||
|
|
||||||
|
const SERVICES = require('./config/services')
|
||||||
|
|
||||||
const SERVICES = require("./config/services");
|
module.exports = function (grunt) {
|
||||||
|
let Helpers
|
||||||
|
let service
|
||||||
|
grunt.loadNpmTasks('grunt-bunyan')
|
||||||
|
grunt.loadNpmTasks('grunt-execute')
|
||||||
|
grunt.loadNpmTasks('grunt-available-tasks')
|
||||||
|
grunt.loadNpmTasks('grunt-concurrent')
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-coffee')
|
||||||
|
grunt.loadNpmTasks('grunt-shell')
|
||||||
|
|
||||||
module.exports = function(grunt) {
|
grunt.task.loadTasks('./tasks')
|
||||||
let Helpers;
|
|
||||||
let service;
|
|
||||||
grunt.loadNpmTasks('grunt-bunyan');
|
|
||||||
grunt.loadNpmTasks('grunt-execute');
|
|
||||||
grunt.loadNpmTasks('grunt-available-tasks');
|
|
||||||
grunt.loadNpmTasks('grunt-concurrent');
|
|
||||||
grunt.loadNpmTasks("grunt-contrib-coffee");
|
|
||||||
grunt.loadNpmTasks("grunt-shell");
|
|
||||||
|
|
||||||
grunt.task.loadTasks("./tasks");
|
const execute = {}
|
||||||
|
|
||||||
const execute = {};
|
|
||||||
for (service of Array.from(SERVICES)) {
|
for (service of Array.from(SERVICES)) {
|
||||||
execute[service.name] =
|
execute[service.name] = { src: `${service.name}/app.js` }
|
||||||
{src: `${service.name}/app.js`};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
grunt.initConfig({
|
grunt.initConfig({
|
||||||
|
@ -59,178 +53,221 @@ module.exports = function(grunt) {
|
||||||
|
|
||||||
concurrent: {
|
concurrent: {
|
||||||
all: {
|
all: {
|
||||||
tasks: (((() => {
|
tasks: (() => {
|
||||||
const result = [];
|
const result = []
|
||||||
for (service of Array.from(SERVICES)) { result.push(`run:${service.name}`);
|
for (service of Array.from(SERVICES)) {
|
||||||
|
result.push(`run:${service.name}`)
|
||||||
}
|
}
|
||||||
return result;
|
return result
|
||||||
})())),
|
})(),
|
||||||
options: {
|
options: {
|
||||||
limit: SERVICES.length,
|
limit: SERVICES.length,
|
||||||
logConcurrentOutput: true
|
logConcurrentOutput: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
availabletasks: {
|
availabletasks: {
|
||||||
tasks: {
|
tasks: {
|
||||||
options: {
|
options: {
|
||||||
filter: 'exclude',
|
filter: 'exclude',
|
||||||
tasks: [
|
tasks: ['concurrent', 'execute', 'bunyan', 'availabletasks'],
|
||||||
'concurrent',
|
|
||||||
'execute',
|
|
||||||
'bunyan',
|
|
||||||
'availabletasks'
|
|
||||||
],
|
|
||||||
groups: {
|
groups: {
|
||||||
"Run tasks": [
|
'Run tasks': ['run', 'run:all', 'default'].concat(
|
||||||
"run",
|
(() => {
|
||||||
"run:all",
|
const result1 = []
|
||||||
"default"
|
for (service of Array.from(SERVICES)) {
|
||||||
].concat(((() => {
|
result1.push(`run:${service.name}`)
|
||||||
const result1 = [];
|
|
||||||
for (service of Array.from(SERVICES)) { result1.push(`run:${service.name}`);
|
|
||||||
}
|
}
|
||||||
return result1;
|
return result1
|
||||||
})())),
|
})()
|
||||||
"Misc": [
|
),
|
||||||
"help"
|
Misc: ['help'],
|
||||||
|
'Install tasks': (() => {
|
||||||
|
const result2 = []
|
||||||
|
for (service of Array.from(SERVICES)) {
|
||||||
|
result2.push(`install:${service.name}`)
|
||||||
|
}
|
||||||
|
return result2
|
||||||
|
})().concat(['install:all', 'install']),
|
||||||
|
'Update tasks': (() => {
|
||||||
|
const result3 = []
|
||||||
|
for (service of Array.from(SERVICES)) {
|
||||||
|
result3.push(`update:${service.name}`)
|
||||||
|
}
|
||||||
|
return result3
|
||||||
|
})().concat(['update:all', 'update']),
|
||||||
|
Checks: [
|
||||||
|
'check',
|
||||||
|
'check:redis',
|
||||||
|
'check:latexmk',
|
||||||
|
'check:s3',
|
||||||
|
'check:make',
|
||||||
|
'check:mongo',
|
||||||
],
|
],
|
||||||
"Install tasks": ((() => {
|
},
|
||||||
const result2 = [];
|
},
|
||||||
for (service of Array.from(SERVICES)) { result2.push(`install:${service.name}`);
|
},
|
||||||
}
|
},
|
||||||
return result2;
|
})
|
||||||
})()).concat(["install:all", "install"]),
|
|
||||||
"Update tasks": ((() => {
|
|
||||||
const result3 = [];
|
|
||||||
for (service of Array.from(SERVICES)) { result3.push(`update:${service.name}`);
|
|
||||||
}
|
|
||||||
return result3;
|
|
||||||
})()).concat(["update:all", "update"]),
|
|
||||||
"Checks": ["check", "check:redis", "check:latexmk", "check:s3", "check:make", "check:mongo"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}});
|
|
||||||
|
|
||||||
for (service of Array.from(SERVICES)) {
|
for (service of Array.from(SERVICES)) {
|
||||||
((service => grunt.registerTask(`install:${service.name}`, `Download and set up the ${service.name} service`, function() {
|
;(service =>
|
||||||
const done = this.async();
|
grunt.registerTask(
|
||||||
return Helpers.installService(service, done);
|
`install:${service.name}`,
|
||||||
})))(service);
|
`Download and set up the ${service.name} service`,
|
||||||
|
function () {
|
||||||
|
const done = this.async()
|
||||||
|
return Helpers.installService(service, done)
|
||||||
|
}
|
||||||
|
))(service)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
grunt.registerTask(
|
||||||
|
'install:all',
|
||||||
grunt.registerTask('install:all', "Download and set up all ShareLaTeX services",
|
'Download and set up all ShareLaTeX services',
|
||||||
[].concat(
|
[]
|
||||||
((() => {
|
.concat(
|
||||||
const result4 = [];
|
(() => {
|
||||||
for (service of Array.from(SERVICES)) { result4.push(`install:${service.name}`);
|
const result4 = []
|
||||||
|
for (service of Array.from(SERVICES)) {
|
||||||
|
result4.push(`install:${service.name}`)
|
||||||
}
|
}
|
||||||
return result4;
|
return result4
|
||||||
})())
|
})()
|
||||||
).concat(['postinstall'])
|
)
|
||||||
);
|
.concat(['postinstall'])
|
||||||
|
|
||||||
grunt.registerTask('install', 'install:all');
|
|
||||||
grunt.registerTask('postinstall', 'Explain postinstall steps', function() {
|
|
||||||
return Helpers.postinstallMessage(this.async());
|
|
||||||
});
|
|
||||||
|
|
||||||
grunt.registerTask('update:all', "Checkout and update all ShareLaTeX services",
|
|
||||||
["check:make"].concat(
|
|
||||||
((() => {
|
|
||||||
const result5 = [];
|
|
||||||
for (service of Array.from(SERVICES)) { result5.push(`update:${service.name}`);
|
|
||||||
}
|
|
||||||
return result5;
|
|
||||||
})())
|
|
||||||
)
|
)
|
||||||
);
|
|
||||||
grunt.registerTask('update', 'update:all');
|
|
||||||
grunt.registerTask('run', "Run all of the sharelatex processes", ['concurrent:all']);
|
|
||||||
grunt.registerTask('run:all', 'run');
|
|
||||||
|
|
||||||
grunt.registerTask('help', 'Display this help list', 'availabletasks');
|
grunt.registerTask('install', 'install:all')
|
||||||
grunt.registerTask('default', 'run');
|
grunt.registerTask('postinstall', 'Explain postinstall steps', function () {
|
||||||
|
return Helpers.postinstallMessage(this.async())
|
||||||
|
})
|
||||||
|
|
||||||
grunt.registerTask("check:redis", "Check that redis is installed and running", function() {
|
grunt.registerTask(
|
||||||
return Helpers.checkRedisConnect(this.async());
|
'update:all',
|
||||||
});
|
'Checkout and update all ShareLaTeX services',
|
||||||
|
['check:make'].concat(
|
||||||
grunt.registerTask("check:mongo", "Check that mongo is installed", function() {
|
(() => {
|
||||||
return Helpers.checkMongoConnect(this.async());
|
const result5 = []
|
||||||
});
|
for (service of Array.from(SERVICES)) {
|
||||||
|
result5.push(`update:${service.name}`)
|
||||||
grunt.registerTask("check", "Check that you have the required dependencies installed", ["check:redis", "check:mongo", "check:make"]);
|
|
||||||
|
|
||||||
grunt.registerTask("check:make", "Check that make is installed", function() {
|
|
||||||
return Helpers.checkMake(this.async());
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
return Helpers = {
|
|
||||||
installService(service, callback) {
|
|
||||||
if (callback == null) { callback = function(error) {}; }
|
|
||||||
console.log(`Installing ${service.name}`);
|
|
||||||
return Helpers.cloneGitRepo(service, function(error) {
|
|
||||||
if (error != null) {
|
|
||||||
return callback(error);
|
|
||||||
} else {
|
|
||||||
return callback();
|
|
||||||
}
|
}
|
||||||
});
|
return result5
|
||||||
|
})()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
grunt.registerTask('update', 'update:all')
|
||||||
|
grunt.registerTask('run', 'Run all of the sharelatex processes', [
|
||||||
|
'concurrent:all',
|
||||||
|
])
|
||||||
|
grunt.registerTask('run:all', 'run')
|
||||||
|
|
||||||
|
grunt.registerTask('help', 'Display this help list', 'availabletasks')
|
||||||
|
grunt.registerTask('default', 'run')
|
||||||
|
|
||||||
|
grunt.registerTask(
|
||||||
|
'check:redis',
|
||||||
|
'Check that redis is installed and running',
|
||||||
|
function () {
|
||||||
|
return Helpers.checkRedisConnect(this.async())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
grunt.registerTask(
|
||||||
|
'check:mongo',
|
||||||
|
'Check that mongo is installed',
|
||||||
|
function () {
|
||||||
|
return Helpers.checkMongoConnect(this.async())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
grunt.registerTask(
|
||||||
|
'check',
|
||||||
|
'Check that you have the required dependencies installed',
|
||||||
|
['check:redis', 'check:mongo', 'check:make']
|
||||||
|
)
|
||||||
|
|
||||||
|
grunt.registerTask('check:make', 'Check that make is installed', function () {
|
||||||
|
return Helpers.checkMake(this.async())
|
||||||
|
})
|
||||||
|
|
||||||
|
return (Helpers = {
|
||||||
|
installService(service, callback) {
|
||||||
|
if (callback == null) {
|
||||||
|
callback = function (error) {}
|
||||||
|
}
|
||||||
|
console.log(`Installing ${service.name}`)
|
||||||
|
return Helpers.cloneGitRepo(service, function (error) {
|
||||||
|
if (error != null) {
|
||||||
|
return callback(error)
|
||||||
|
} else {
|
||||||
|
return callback()
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
cloneGitRepo(service, callback) {
|
cloneGitRepo(service, callback) {
|
||||||
if (callback == null) { callback = function(error) {}; }
|
if (callback == null) {
|
||||||
const repo_src = service.repo;
|
callback = function (error) {}
|
||||||
const dir = service.name;
|
}
|
||||||
|
const repo_src = service.repo
|
||||||
|
const dir = service.name
|
||||||
if (!fs.existsSync(dir)) {
|
if (!fs.existsSync(dir)) {
|
||||||
const proc = spawn("git", [
|
const proc = spawn('git', ['clone', repo_src, dir], {
|
||||||
"clone",
|
stdio: 'inherit',
|
||||||
repo_src,
|
})
|
||||||
dir
|
return proc.on('close', () =>
|
||||||
], {stdio: "inherit"});
|
Helpers.checkoutVersion(service, callback)
|
||||||
return proc.on("close", () => Helpers.checkoutVersion(service, callback));
|
)
|
||||||
} else {
|
} else {
|
||||||
console.log(`${dir} already installed, skipping.`);
|
console.log(`${dir} already installed, skipping.`)
|
||||||
return callback();
|
return callback()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
checkoutVersion(service, callback) {
|
checkoutVersion(service, callback) {
|
||||||
if (callback == null) { callback = function(error) {}; }
|
if (callback == null) {
|
||||||
const dir = service.name;
|
callback = function (error) {}
|
||||||
grunt.log.write(`checking out ${service.name} ${service.version}`);
|
}
|
||||||
const proc = spawn("git", ["checkout", service.version], {stdio: "inherit", cwd: dir});
|
const dir = service.name
|
||||||
return proc.on("close", () => callback());
|
grunt.log.write(`checking out ${service.name} ${service.version}`)
|
||||||
|
const proc = spawn('git', ['checkout', service.version], {
|
||||||
|
stdio: 'inherit',
|
||||||
|
cwd: dir,
|
||||||
|
})
|
||||||
|
return proc.on('close', () => callback())
|
||||||
},
|
},
|
||||||
|
|
||||||
postinstallMessage(callback) {
|
postinstallMessage(callback) {
|
||||||
if (callback == null) { callback = function(error) {}; }
|
if (callback == null) {
|
||||||
|
callback = function (error) {}
|
||||||
|
}
|
||||||
grunt.log.write(`\
|
grunt.log.write(`\
|
||||||
Services cloned:
|
Services cloned:
|
||||||
${(() => {
|
${(() => {
|
||||||
const result6 = [];
|
const result6 = []
|
||||||
for (service of Array.from(SERVICES)) { result6.push(service.name);
|
for (service of Array.from(SERVICES)) {
|
||||||
|
result6.push(service.name)
|
||||||
}
|
}
|
||||||
return result6;
|
return result6
|
||||||
})()}
|
})()}
|
||||||
To install services run:
|
To install services run:
|
||||||
$ source bin/install-services
|
$ source bin/install-services
|
||||||
This will install the required node versions and run \`npm install\` for each service.
|
This will install the required node versions and run \`npm install\` for each service.
|
||||||
See https://github.com/sharelatex/sharelatex/pull/549 for more info.\
|
See https://github.com/sharelatex/sharelatex/pull/549 for more info.\
|
||||||
`
|
`)
|
||||||
);
|
return callback()
|
||||||
return callback();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
checkMake(callback) {
|
checkMake(callback) {
|
||||||
if (callback == null) { callback = function(error) {}; }
|
if (callback == null) {
|
||||||
grunt.log.write("Checking make is installed... ");
|
callback = function (error) {}
|
||||||
return exec("make --version", function(error, stdout, stderr) {
|
}
|
||||||
if ((error != null) && error.message.match("not found")) {
|
grunt.log.write('Checking make is installed... ')
|
||||||
grunt.log.error("FAIL.");
|
return exec('make --version', function (error, stdout, stderr) {
|
||||||
|
if (error != null && error.message.match('not found')) {
|
||||||
|
grunt.log.error('FAIL.')
|
||||||
grunt.log.errorlns(`\
|
grunt.log.errorlns(`\
|
||||||
Either make is not installed or is not in your path.
|
Either make is not installed or is not in your path.
|
||||||
|
|
||||||
|
@ -238,31 +275,32 @@ On Ubuntu you can install make with:
|
||||||
|
|
||||||
sudo apt-get install build-essential
|
sudo apt-get install build-essential
|
||||||
\
|
\
|
||||||
`
|
`)
|
||||||
);
|
return callback(error)
|
||||||
return callback(error);
|
|
||||||
} else if (error != null) {
|
} else if (error != null) {
|
||||||
return callback(error);
|
return callback(error)
|
||||||
} else {
|
} else {
|
||||||
grunt.log.write("OK.");
|
grunt.log.write('OK.')
|
||||||
return callback();
|
return callback()
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
checkMongoConnect(callback) {
|
checkMongoConnect(callback) {
|
||||||
if (callback == null) { callback = function(error) {}; }
|
if (callback == null) {
|
||||||
grunt.log.write("Checking can connect to mongo");
|
callback = function (error) {}
|
||||||
const mongojs = require("mongojs");
|
|
||||||
const db = mongojs(settings.mongo.url, ["tags"]);
|
|
||||||
db.runCommand({ ping: 1 }, function(err, res) {
|
|
||||||
if (!err && res.ok) {
|
|
||||||
grunt.log.write("OK.");
|
|
||||||
}
|
}
|
||||||
return callback();
|
grunt.log.write('Checking can connect to mongo')
|
||||||
});
|
const mongojs = require('mongojs')
|
||||||
return db.on('error', function(err){
|
const db = mongojs(settings.mongo.url, ['tags'])
|
||||||
err = "Can not connect to mongodb";
|
db.runCommand({ ping: 1 }, function (err, res) {
|
||||||
grunt.log.error("FAIL.");
|
if (!err && res.ok) {
|
||||||
|
grunt.log.write('OK.')
|
||||||
|
}
|
||||||
|
return callback()
|
||||||
|
})
|
||||||
|
return db.on('error', function (err) {
|
||||||
|
err = 'Can not connect to mongodb'
|
||||||
|
grunt.log.error('FAIL.')
|
||||||
grunt.log.errorlns(`\
|
grunt.log.errorlns(`\
|
||||||
!!!!!!!!!!!!!! MONGO ERROR !!!!!!!!!!!!!!
|
!!!!!!!!!!!!!! MONGO ERROR !!!!!!!!!!!!!!
|
||||||
|
|
||||||
|
@ -271,29 +309,30 @@ ShareLaTeX can not talk to the mongodb instance
|
||||||
Check the mongodb instance is running and accessible on env var SHARELATEX_MONGO_URL
|
Check the mongodb instance is running and accessible on env var SHARELATEX_MONGO_URL
|
||||||
|
|
||||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\
|
||||||
`
|
`)
|
||||||
);
|
throw new Error('Can not connect to Mongodb')
|
||||||
throw new Error("Can not connect to Mongodb");
|
return callback(err)
|
||||||
return callback(err);
|
})
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
checkRedisConnect(callback) {
|
checkRedisConnect(callback) {
|
||||||
if (callback == null) { callback = function(error) {}; }
|
if (callback == null) {
|
||||||
grunt.log.write("Checking can connect to redis\n");
|
callback = function (error) {}
|
||||||
const rclient = require("redis").createClient(settings.redis.web);
|
|
||||||
|
|
||||||
rclient.ping(function(err, res) {
|
|
||||||
if ((err == null)) {
|
|
||||||
grunt.log.write("OK.");
|
|
||||||
} else {
|
|
||||||
throw new Error("Can not connect to redis");
|
|
||||||
}
|
}
|
||||||
return callback();
|
grunt.log.write('Checking can connect to redis\n')
|
||||||
});
|
const rclient = require('redis').createClient(settings.redis.web)
|
||||||
const errorHandler = _.once(function(err){
|
|
||||||
err = "Can not connect to redis";
|
rclient.ping(function (err, res) {
|
||||||
grunt.log.error("FAIL.");
|
if (err == null) {
|
||||||
|
grunt.log.write('OK.')
|
||||||
|
} else {
|
||||||
|
throw new Error('Can not connect to redis')
|
||||||
|
}
|
||||||
|
return callback()
|
||||||
|
})
|
||||||
|
const errorHandler = _.once(function (err) {
|
||||||
|
err = 'Can not connect to redis'
|
||||||
|
grunt.log.error('FAIL.')
|
||||||
grunt.log.errorlns(`\
|
grunt.log.errorlns(`\
|
||||||
!!!!!!!!!!!!!! REDIS ERROR !!!!!!!!!!!!!!
|
!!!!!!!!!!!!!! REDIS ERROR !!!!!!!!!!!!!!
|
||||||
|
|
||||||
|
@ -302,19 +341,17 @@ ShareLaTeX can not talk to the redis instance
|
||||||
Check the redis instance is running and accessible on env var SHARELATEX_REDIS_HOST
|
Check the redis instance is running and accessible on env var SHARELATEX_REDIS_HOST
|
||||||
|
|
||||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\
|
||||||
`
|
`)
|
||||||
);
|
throw new Error('Can not connect to redis')
|
||||||
throw new Error("Can not connect to redis");
|
return callback(err)
|
||||||
return callback(err);
|
})
|
||||||
});
|
return rclient.on('error', errorHandler)
|
||||||
return rclient.on('error', errorHandler);
|
},
|
||||||
}
|
})
|
||||||
};
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function __guard__(value, transform) {
|
function __guard__(value, transform) {
|
||||||
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined;
|
return typeof value !== 'undefined' && value !== null
|
||||||
|
? transform(value)
|
||||||
|
: undefined
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,46 +12,45 @@
|
||||||
* DS207: Consider shorter variations of null checks
|
* DS207: Consider shorter variations of null checks
|
||||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||||
*/
|
*/
|
||||||
let allTexLiveDockerImageNames, allTexLiveDockerImages, redisConfig, siteUrl;
|
let allTexLiveDockerImageNames, allTexLiveDockerImages, redisConfig, siteUrl
|
||||||
let e;
|
let e
|
||||||
const Path = require('path');
|
const Path = require('path')
|
||||||
|
|
||||||
// These credentials are used for authenticating api requests
|
// These credentials are used for authenticating api requests
|
||||||
// between services that may need to go over public channels
|
// between services that may need to go over public channels
|
||||||
const httpAuthUser = "sharelatex";
|
const httpAuthUser = 'sharelatex'
|
||||||
const httpAuthPass = process.env.WEB_API_PASSWORD;
|
const httpAuthPass = process.env.WEB_API_PASSWORD
|
||||||
const httpAuthUsers = {};
|
const httpAuthUsers = {}
|
||||||
httpAuthUsers[httpAuthUser] = httpAuthPass;
|
httpAuthUsers[httpAuthUser] = httpAuthPass
|
||||||
|
|
||||||
const parse = function(option){
|
const parse = function (option) {
|
||||||
if (option != null) {
|
if (option != null) {
|
||||||
try {
|
try {
|
||||||
const opt = JSON.parse(option);
|
const opt = JSON.parse(option)
|
||||||
return opt;
|
return opt
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new Error(`problem parsing ${option}, invalid JSON`);
|
throw new Error(`problem parsing ${option}, invalid JSON`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const parseIntOrFail = function(value){
|
const parseIntOrFail = function (value) {
|
||||||
const parsedValue = parseInt(value, 10);
|
const parsedValue = parseInt(value, 10)
|
||||||
if (isNaN(parsedValue)) {
|
if (isNaN(parsedValue)) {
|
||||||
throw new Error(`'${value}' is an invalid integer`);
|
throw new Error(`'${value}' is an invalid integer`)
|
||||||
}
|
}
|
||||||
return parsedValue;
|
return parsedValue
|
||||||
};
|
}
|
||||||
|
|
||||||
const DATA_DIR = '/var/lib/sharelatex/data';
|
const DATA_DIR = '/var/lib/sharelatex/data'
|
||||||
const TMP_DIR = '/var/lib/sharelatex/tmp';
|
const TMP_DIR = '/var/lib/sharelatex/tmp'
|
||||||
|
|
||||||
const settings = {
|
const settings = {
|
||||||
|
|
||||||
clsi: {
|
clsi: {
|
||||||
optimiseInDocker: process.env.OPTIMISE_PDF === 'true'
|
optimiseInDocker: process.env.OPTIMISE_PDF === 'true',
|
||||||
},
|
},
|
||||||
|
|
||||||
brandPrefix: "",
|
brandPrefix: '',
|
||||||
|
|
||||||
allowAnonymousReadAndWriteSharing:
|
allowAnonymousReadAndWriteSharing:
|
||||||
process.env.SHARELATEX_ALLOW_ANONYMOUS_READ_AND_WRITE_SHARING === 'true',
|
process.env.SHARELATEX_ALLOW_ANONYMOUS_READ_AND_WRITE_SHARING === 'true',
|
||||||
|
@ -66,7 +65,7 @@ const settings = {
|
||||||
//
|
//
|
||||||
// The following works out of the box with Mongo's default settings:
|
// The following works out of the box with Mongo's default settings:
|
||||||
mongo: {
|
mongo: {
|
||||||
url : process.env.SHARELATEX_MONGO_URL || 'mongodb://dockerhost/sharelatex'
|
url: process.env.SHARELATEX_MONGO_URL || 'mongodb://dockerhost/sharelatex',
|
||||||
},
|
},
|
||||||
|
|
||||||
// Redis is used in ShareLaTeX for high volume queries, like real-time
|
// Redis is used in ShareLaTeX for high volume queries, like real-time
|
||||||
|
@ -75,36 +74,72 @@ const settings = {
|
||||||
// The following config will work with Redis's default settings:
|
// The following config will work with Redis's default settings:
|
||||||
redis: {
|
redis: {
|
||||||
web: (redisConfig = {
|
web: (redisConfig = {
|
||||||
host: process.env.SHARELATEX_REDIS_HOST || "dockerhost",
|
host: process.env.SHARELATEX_REDIS_HOST || 'dockerhost',
|
||||||
port: process.env.SHARELATEX_REDIS_PORT || "6379",
|
port: process.env.SHARELATEX_REDIS_PORT || '6379',
|
||||||
password: process.env.SHARELATEX_REDIS_PASS || undefined,
|
password: process.env.SHARELATEX_REDIS_PASS || undefined,
|
||||||
key_schema: {
|
key_schema: {
|
||||||
// document-updater
|
// document-updater
|
||||||
blockingKey({doc_id}) { return `Blocking:${doc_id}`; },
|
blockingKey({ doc_id }) {
|
||||||
docLines({doc_id}) { return `doclines:${doc_id}`; },
|
return `Blocking:${doc_id}`
|
||||||
docOps({doc_id}) { return `DocOps:${doc_id}`; },
|
},
|
||||||
docVersion({doc_id}) { return `DocVersion:${doc_id}`; },
|
docLines({ doc_id }) {
|
||||||
docHash({doc_id}) { return `DocHash:${doc_id}`; },
|
return `doclines:${doc_id}`
|
||||||
projectKey({doc_id}) { return `ProjectId:${doc_id}`; },
|
},
|
||||||
docsInProject({project_id}) { return `DocsIn:${project_id}`; },
|
docOps({ doc_id }) {
|
||||||
ranges({doc_id}) { return `Ranges:${doc_id}`; },
|
return `DocOps:${doc_id}`
|
||||||
|
},
|
||||||
|
docVersion({ doc_id }) {
|
||||||
|
return `DocVersion:${doc_id}`
|
||||||
|
},
|
||||||
|
docHash({ doc_id }) {
|
||||||
|
return `DocHash:${doc_id}`
|
||||||
|
},
|
||||||
|
projectKey({ doc_id }) {
|
||||||
|
return `ProjectId:${doc_id}`
|
||||||
|
},
|
||||||
|
docsInProject({ project_id }) {
|
||||||
|
return `DocsIn:${project_id}`
|
||||||
|
},
|
||||||
|
ranges({ doc_id }) {
|
||||||
|
return `Ranges:${doc_id}`
|
||||||
|
},
|
||||||
// document-updater:realtime
|
// document-updater:realtime
|
||||||
pendingUpdates({doc_id}) { return `PendingUpdates:${doc_id}`; },
|
pendingUpdates({ doc_id }) {
|
||||||
|
return `PendingUpdates:${doc_id}`
|
||||||
|
},
|
||||||
// document-updater:history
|
// document-updater:history
|
||||||
uncompressedHistoryOps({doc_id}) { return `UncompressedHistoryOps:${doc_id}`; },
|
uncompressedHistoryOps({ doc_id }) {
|
||||||
docsWithHistoryOps({project_id}) { return `DocsWithHistoryOps:${project_id}`; },
|
return `UncompressedHistoryOps:${doc_id}`
|
||||||
|
},
|
||||||
|
docsWithHistoryOps({ project_id }) {
|
||||||
|
return `DocsWithHistoryOps:${project_id}`
|
||||||
|
},
|
||||||
// document-updater:lock
|
// document-updater:lock
|
||||||
blockingKey({doc_id}) { return `Blocking:${doc_id}`; },
|
blockingKey({ doc_id }) {
|
||||||
|
return `Blocking:${doc_id}`
|
||||||
|
},
|
||||||
// track-changes:lock
|
// track-changes:lock
|
||||||
historyLock({doc_id}) { return `HistoryLock:${doc_id}`; },
|
historyLock({ doc_id }) {
|
||||||
historyIndexLock({project_id}) { return `HistoryIndexLock:${project_id}`; },
|
return `HistoryLock:${doc_id}`
|
||||||
|
},
|
||||||
|
historyIndexLock({ project_id }) {
|
||||||
|
return `HistoryIndexLock:${project_id}`
|
||||||
|
},
|
||||||
// track-changes:history
|
// track-changes:history
|
||||||
uncompressedHistoryOps({doc_id}) { return `UncompressedHistoryOps:${doc_id}`; },
|
uncompressedHistoryOps({ doc_id }) {
|
||||||
docsWithHistoryOps({project_id}) { return `DocsWithHistoryOps:${project_id}`; },
|
return `UncompressedHistoryOps:${doc_id}`
|
||||||
|
},
|
||||||
|
docsWithHistoryOps({ project_id }) {
|
||||||
|
return `DocsWithHistoryOps:${project_id}`
|
||||||
|
},
|
||||||
// realtime
|
// realtime
|
||||||
clientsInProject({project_id}) { return `clients_in_project:${project_id}`; },
|
clientsInProject({ project_id }) {
|
||||||
connectedUser({project_id, client_id}){ return `connected_user:${project_id}:${client_id}`; }
|
return `clients_in_project:${project_id}`
|
||||||
}
|
},
|
||||||
|
connectedUser({ project_id, client_id }) {
|
||||||
|
return `connected_user:${project_id}:${client_id}`
|
||||||
|
},
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
fairy: redisConfig,
|
fairy: redisConfig,
|
||||||
// track-changes and document-updater
|
// track-changes and document-updater
|
||||||
|
@ -115,7 +150,7 @@ const settings = {
|
||||||
websessions: redisConfig,
|
websessions: redisConfig,
|
||||||
api: redisConfig,
|
api: redisConfig,
|
||||||
pubsub: redisConfig,
|
pubsub: redisConfig,
|
||||||
project_history: redisConfig
|
project_history: redisConfig,
|
||||||
},
|
},
|
||||||
|
|
||||||
// The compile server (the clsi) uses a SQL database to cache files and
|
// The compile server (the clsi) uses a SQL database to cache files and
|
||||||
|
@ -129,12 +164,12 @@ const settings = {
|
||||||
//
|
//
|
||||||
mysql: {
|
mysql: {
|
||||||
clsi: {
|
clsi: {
|
||||||
database: "clsi",
|
database: 'clsi',
|
||||||
username: "clsi",
|
username: 'clsi',
|
||||||
password: "",
|
password: '',
|
||||||
dialect: "sqlite",
|
dialect: 'sqlite',
|
||||||
storage: Path.join(DATA_DIR, "db.sqlite")
|
storage: Path.join(DATA_DIR, 'db.sqlite'),
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// File storage
|
// File storage
|
||||||
|
@ -143,11 +178,11 @@ const settings = {
|
||||||
// ShareLaTeX can store binary files like images either locally or in Amazon
|
// ShareLaTeX can store binary files like images either locally or in Amazon
|
||||||
// S3. The default is locally:
|
// S3. The default is locally:
|
||||||
filestore: {
|
filestore: {
|
||||||
backend: "fs",
|
backend: 'fs',
|
||||||
stores: {
|
stores: {
|
||||||
user_files: Path.join(DATA_DIR, "user_files"),
|
user_files: Path.join(DATA_DIR, 'user_files'),
|
||||||
template_files: Path.join(DATA_DIR, "template_files")
|
template_files: Path.join(DATA_DIR, 'template_files'),
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// To use Amazon S3 as a storage backend, comment out the above config, and
|
// To use Amazon S3 as a storage backend, comment out the above config, and
|
||||||
|
@ -163,7 +198,7 @@ const settings = {
|
||||||
//
|
//
|
||||||
|
|
||||||
trackchanges: {
|
trackchanges: {
|
||||||
continueOnError: true
|
continueOnError: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Local disk caching
|
// Local disk caching
|
||||||
|
@ -172,15 +207,15 @@ const settings = {
|
||||||
// If we ever need to write something to disk (e.g. incoming requests
|
// If we ever need to write something to disk (e.g. incoming requests
|
||||||
// that need processing but may be too big for memory), then write
|
// that need processing but may be too big for memory), then write
|
||||||
// them to disk here:
|
// them to disk here:
|
||||||
dumpFolder: Path.join(TMP_DIR, "dumpFolder"),
|
dumpFolder: Path.join(TMP_DIR, 'dumpFolder'),
|
||||||
// Where to write uploads before they are processed
|
// Where to write uploads before they are processed
|
||||||
uploadFolder: Path.join(TMP_DIR, "uploads"),
|
uploadFolder: Path.join(TMP_DIR, 'uploads'),
|
||||||
// Where to write the project to disk before running LaTeX on it
|
// Where to write the project to disk before running LaTeX on it
|
||||||
compilesDir: Path.join(DATA_DIR, "compiles"),
|
compilesDir: Path.join(DATA_DIR, 'compiles'),
|
||||||
// Where to cache downloaded URLs for the CLSI
|
// Where to cache downloaded URLs for the CLSI
|
||||||
clsiCacheDir: Path.join(DATA_DIR, "cache"),
|
clsiCacheDir: Path.join(DATA_DIR, 'cache'),
|
||||||
// Where to write the output files to disk after running LaTeX
|
// Where to write the output files to disk after running LaTeX
|
||||||
outputDir: Path.join(DATA_DIR, "output")
|
outputDir: Path.join(DATA_DIR, 'output'),
|
||||||
},
|
},
|
||||||
|
|
||||||
// Server Config
|
// Server Config
|
||||||
|
@ -191,23 +226,27 @@ const settings = {
|
||||||
siteUrl: (siteUrl = process.env.SHARELATEX_SITE_URL || 'http://localhost'),
|
siteUrl: (siteUrl = process.env.SHARELATEX_SITE_URL || 'http://localhost'),
|
||||||
|
|
||||||
// The name this is used to describe your ShareLaTeX Installation
|
// The name this is used to describe your ShareLaTeX Installation
|
||||||
appName: process.env.SHARELATEX_APP_NAME || "ShareLaTeX (Community Edition)",
|
appName: process.env.SHARELATEX_APP_NAME || 'ShareLaTeX (Community Edition)',
|
||||||
|
|
||||||
restrictInvitesToExistingAccounts: process.env.SHARELATEX_RESTRICT_INVITES_TO_EXISTING_ACCOUNTS === 'true',
|
restrictInvitesToExistingAccounts:
|
||||||
|
process.env.SHARELATEX_RESTRICT_INVITES_TO_EXISTING_ACCOUNTS === 'true',
|
||||||
|
|
||||||
nav: {
|
nav: {
|
||||||
title: process.env.SHARELATEX_NAV_TITLE || process.env.SHARELATEX_APP_NAME || "ShareLaTeX Community Edition"
|
title:
|
||||||
|
process.env.SHARELATEX_NAV_TITLE ||
|
||||||
|
process.env.SHARELATEX_APP_NAME ||
|
||||||
|
'ShareLaTeX Community Edition',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
// The email address which users will be directed to as the main point of
|
// The email address which users will be directed to as the main point of
|
||||||
// contact for this installation of ShareLaTeX.
|
// contact for this installation of ShareLaTeX.
|
||||||
adminEmail: process.env.SHARELATEX_ADMIN_EMAIL || "placeholder@example.com",
|
adminEmail: process.env.SHARELATEX_ADMIN_EMAIL || 'placeholder@example.com',
|
||||||
|
|
||||||
// If provided, a sessionSecret is used to sign cookies so that they cannot be
|
// If provided, a sessionSecret is used to sign cookies so that they cannot be
|
||||||
// spoofed. This is recommended.
|
// spoofed. This is recommended.
|
||||||
security: {
|
security: {
|
||||||
sessionSecret: process.env.SHARELATEX_SESSION_SECRET || process.env.CRYPTO_RANDOM
|
sessionSecret:
|
||||||
|
process.env.SHARELATEX_SESSION_SECRET || process.env.CRYPTO_RANDOM,
|
||||||
},
|
},
|
||||||
|
|
||||||
// These credentials are used for authenticating api requests
|
// These credentials are used for authenticating api requests
|
||||||
|
@ -224,7 +263,7 @@ const settings = {
|
||||||
|
|
||||||
// If you are running ShareLaTeX over https, set this to true to send the
|
// If you are running ShareLaTeX over https, set this to true to send the
|
||||||
// cookie with a secure flag (recommended).
|
// cookie with a secure flag (recommended).
|
||||||
secureCookie: (process.env.SHARELATEX_SECURE_COOKIE != null),
|
secureCookie: process.env.SHARELATEX_SECURE_COOKIE != null,
|
||||||
|
|
||||||
// If you are running ShareLaTeX behind a proxy (like Apache, Nginx, etc)
|
// If you are running ShareLaTeX behind a proxy (like Apache, Nginx, etc)
|
||||||
// then set this to true to allow it to correctly detect the forwarded IP
|
// then set this to true to allow it to correctly detect the forwarded IP
|
||||||
|
@ -234,61 +273,64 @@ const settings = {
|
||||||
|
|
||||||
i18n: {
|
i18n: {
|
||||||
subdomainLang: {
|
subdomainLang: {
|
||||||
www: {lngCode:process.env.SHARELATEX_SITE_LANGUAGE || "en", url: siteUrl}
|
www: {
|
||||||
|
lngCode: process.env.SHARELATEX_SITE_LANGUAGE || 'en',
|
||||||
|
url: siteUrl,
|
||||||
},
|
},
|
||||||
defaultLng: process.env.SHARELATEX_SITE_LANGUAGE || "en"
|
},
|
||||||
|
defaultLng: process.env.SHARELATEX_SITE_LANGUAGE || 'en',
|
||||||
},
|
},
|
||||||
|
|
||||||
currentImageName: process.env.TEX_LIVE_DOCKER_IMAGE,
|
currentImageName: process.env.TEX_LIVE_DOCKER_IMAGE,
|
||||||
|
|
||||||
apis: {
|
apis: {
|
||||||
web: {
|
web: {
|
||||||
url: "http://localhost:3000",
|
url: 'http://localhost:3000',
|
||||||
user: httpAuthUser,
|
user: httpAuthUser,
|
||||||
pass: httpAuthPass
|
pass: httpAuthPass,
|
||||||
},
|
},
|
||||||
project_history: {
|
project_history: {
|
||||||
enabled: false
|
enabled: false,
|
||||||
}
|
|
||||||
},
|
},
|
||||||
references:{},
|
},
|
||||||
notifications:undefined,
|
references: {},
|
||||||
|
notifications: undefined,
|
||||||
|
|
||||||
defaultFeatures: {
|
defaultFeatures: {
|
||||||
collaborators: -1,
|
collaborators: -1,
|
||||||
dropbox: true,
|
dropbox: true,
|
||||||
versioning: true,
|
versioning: true,
|
||||||
compileTimeout: parseIntOrFail(process.env.COMPILE_TIMEOUT || 180),
|
compileTimeout: parseIntOrFail(process.env.COMPILE_TIMEOUT || 180),
|
||||||
compileGroup: "standard",
|
compileGroup: 'standard',
|
||||||
trackChanges: true,
|
trackChanges: true,
|
||||||
templates: true,
|
templates: true,
|
||||||
references: true
|
references: true,
|
||||||
}
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
// # OPTIONAL CONFIGURABLE SETTINGS
|
// # OPTIONAL CONFIGURABLE SETTINGS
|
||||||
|
|
||||||
if (process.env.SHARELATEX_LEFT_FOOTER != null) {
|
if (process.env.SHARELATEX_LEFT_FOOTER != null) {
|
||||||
try {
|
try {
|
||||||
settings.nav.left_footer = JSON.parse(process.env.SHARELATEX_LEFT_FOOTER);
|
settings.nav.left_footer = JSON.parse(process.env.SHARELATEX_LEFT_FOOTER)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
e = error;
|
e = error
|
||||||
console.error("could not parse SHARELATEX_LEFT_FOOTER, not valid JSON");
|
console.error('could not parse SHARELATEX_LEFT_FOOTER, not valid JSON')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.SHARELATEX_RIGHT_FOOTER != null) {
|
if (process.env.SHARELATEX_RIGHT_FOOTER != null) {
|
||||||
settings.nav.right_footer = process.env.SHARELATEX_RIGHT_FOOTER;
|
settings.nav.right_footer = process.env.SHARELATEX_RIGHT_FOOTER
|
||||||
try {
|
try {
|
||||||
settings.nav.right_footer = JSON.parse(process.env.SHARELATEX_RIGHT_FOOTER);
|
settings.nav.right_footer = JSON.parse(process.env.SHARELATEX_RIGHT_FOOTER)
|
||||||
} catch (error1) {
|
} catch (error1) {
|
||||||
e = error1;
|
e = error1
|
||||||
console.error("could not parse SHARELATEX_RIGHT_FOOTER, not valid JSON");
|
console.error('could not parse SHARELATEX_RIGHT_FOOTER, not valid JSON')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.SHARELATEX_HEADER_IMAGE_URL != null) {
|
if (process.env.SHARELATEX_HEADER_IMAGE_URL != null) {
|
||||||
settings.nav.custom_logo = process.env.SHARELATEX_HEADER_IMAGE_URL;
|
settings.nav.custom_logo = process.env.SHARELATEX_HEADER_IMAGE_URL
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.SHARELATEX_HEADER_NAV_LINKS != null) {
|
if (process.env.SHARELATEX_HEADER_NAV_LINKS != null) {
|
||||||
|
@ -299,21 +341,20 @@ if (process.env.SHARELATEX_HEADER_NAV_LINKS != null) {
|
||||||
# See https://github.com/sharelatex/sharelatex/wiki/Configuring-Headers,-Footers-&-Logo
|
# See https://github.com/sharelatex/sharelatex/wiki/Configuring-Headers,-Footers-&-Logo
|
||||||
#
|
#
|
||||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #\
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #\
|
||||||
`
|
`)
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.SHARELATEX_HEADER_EXTRAS != null) {
|
if (process.env.SHARELATEX_HEADER_EXTRAS != null) {
|
||||||
try {
|
try {
|
||||||
settings.nav.header_extras = JSON.parse(process.env.SHARELATEX_HEADER_EXTRAS);
|
settings.nav.header_extras = JSON.parse(
|
||||||
|
process.env.SHARELATEX_HEADER_EXTRAS
|
||||||
|
)
|
||||||
} catch (error2) {
|
} catch (error2) {
|
||||||
e = error2;
|
e = error2
|
||||||
console.error("could not parse SHARELATEX_HEADER_EXTRAS, not valid JSON");
|
console.error('could not parse SHARELATEX_HEADER_EXTRAS, not valid JSON')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Sending Email
|
// Sending Email
|
||||||
// -------------
|
// -------------
|
||||||
//
|
//
|
||||||
|
@ -323,12 +364,10 @@ if (process.env.SHARELATEX_HEADER_EXTRAS != null) {
|
||||||
//
|
//
|
||||||
// http://www.nodemailer.com/docs/transports
|
// http://www.nodemailer.com/docs/transports
|
||||||
|
|
||||||
|
|
||||||
if (process.env.SHARELATEX_EMAIL_FROM_ADDRESS != null) {
|
if (process.env.SHARELATEX_EMAIL_FROM_ADDRESS != null) {
|
||||||
|
|
||||||
settings.email = {
|
settings.email = {
|
||||||
fromAddress: process.env.SHARELATEX_EMAIL_FROM_ADDRESS,
|
fromAddress: process.env.SHARELATEX_EMAIL_FROM_ADDRESS,
|
||||||
replyTo: process.env.SHARELATEX_EMAIL_REPLY_TO || "",
|
replyTo: process.env.SHARELATEX_EMAIL_REPLY_TO || '',
|
||||||
driver: process.env.SHARELATEX_EMAIL_DRIVER,
|
driver: process.env.SHARELATEX_EMAIL_DRIVER,
|
||||||
parameters: {
|
parameters: {
|
||||||
// AWS Creds
|
// AWS Creds
|
||||||
|
@ -341,65 +380,73 @@ if (process.env.SHARELATEX_EMAIL_FROM_ADDRESS != null) {
|
||||||
secure: parse(process.env.SHARELATEX_EMAIL_SMTP_SECURE),
|
secure: parse(process.env.SHARELATEX_EMAIL_SMTP_SECURE),
|
||||||
ignoreTLS: parse(process.env.SHARELATEX_EMAIL_SMTP_IGNORE_TLS),
|
ignoreTLS: parse(process.env.SHARELATEX_EMAIL_SMTP_IGNORE_TLS),
|
||||||
name: process.env.SHARELATEX_EMAIL_SMTP_NAME,
|
name: process.env.SHARELATEX_EMAIL_SMTP_NAME,
|
||||||
logger: process.env.SHARELATEX_EMAIL_SMTP_LOGGER === 'true'
|
logger: process.env.SHARELATEX_EMAIL_SMTP_LOGGER === 'true',
|
||||||
},
|
},
|
||||||
|
|
||||||
textEncoding: process.env.SHARELATEX_EMAIL_TEXT_ENCODING,
|
textEncoding: process.env.SHARELATEX_EMAIL_TEXT_ENCODING,
|
||||||
template: {
|
template: {
|
||||||
customFooter: process.env.SHARELATEX_CUSTOM_EMAIL_FOOTER
|
customFooter: process.env.SHARELATEX_CUSTOM_EMAIL_FOOTER,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if (process.env.SHARELATEX_EMAIL_AWS_SES_REGION != null) {
|
if (process.env.SHARELATEX_EMAIL_AWS_SES_REGION != null) {
|
||||||
settings.email.parameters.region = process.env.SHARELATEX_EMAIL_AWS_SES_REGION;
|
settings.email.parameters.region =
|
||||||
|
process.env.SHARELATEX_EMAIL_AWS_SES_REGION
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((process.env.SHARELATEX_EMAIL_SMTP_USER != null) || (process.env.SHARELATEX_EMAIL_SMTP_PASS != null)) {
|
if (
|
||||||
|
process.env.SHARELATEX_EMAIL_SMTP_USER != null ||
|
||||||
|
process.env.SHARELATEX_EMAIL_SMTP_PASS != null
|
||||||
|
) {
|
||||||
settings.email.parameters.auth = {
|
settings.email.parameters.auth = {
|
||||||
user: process.env.SHARELATEX_EMAIL_SMTP_USER,
|
user: process.env.SHARELATEX_EMAIL_SMTP_USER,
|
||||||
pass: process.env.SHARELATEX_EMAIL_SMTP_PASS
|
pass: process.env.SHARELATEX_EMAIL_SMTP_PASS,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.SHARELATEX_EMAIL_SMTP_TLS_REJECT_UNAUTH != null) {
|
if (process.env.SHARELATEX_EMAIL_SMTP_TLS_REJECT_UNAUTH != null) {
|
||||||
settings.email.parameters.tls =
|
settings.email.parameters.tls = {
|
||||||
{rejectUnauthorized: parse(process.env.SHARELATEX_EMAIL_SMTP_TLS_REJECT_UNAUTH)};
|
rejectUnauthorized: parse(
|
||||||
|
process.env.SHARELATEX_EMAIL_SMTP_TLS_REJECT_UNAUTH
|
||||||
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// i18n
|
// i18n
|
||||||
if (process.env.SHARELATEX_LANG_DOMAIN_MAPPING != null) {
|
if (process.env.SHARELATEX_LANG_DOMAIN_MAPPING != null) {
|
||||||
|
settings.i18n.subdomainLang = parse(
|
||||||
settings.i18n.subdomainLang = parse(process.env.SHARELATEX_LANG_DOMAIN_MAPPING);
|
process.env.SHARELATEX_LANG_DOMAIN_MAPPING
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Password Settings
|
// Password Settings
|
||||||
// -----------
|
// -----------
|
||||||
// These restrict the passwords users can use when registering
|
// These restrict the passwords users can use when registering
|
||||||
// opts are from http://antelle.github.io/passfield
|
// opts are from http://antelle.github.io/passfield
|
||||||
if (process.env.SHARELATEX_PASSWORD_VALIDATION_PATTERN || process.env.SHARELATEX_PASSWORD_VALIDATION_MIN_LENGTH || process.env.SHARELATEX_PASSWORD_VALIDATION_MAX_LENGTH) {
|
if (
|
||||||
|
process.env.SHARELATEX_PASSWORD_VALIDATION_PATTERN ||
|
||||||
|
process.env.SHARELATEX_PASSWORD_VALIDATION_MIN_LENGTH ||
|
||||||
|
process.env.SHARELATEX_PASSWORD_VALIDATION_MAX_LENGTH
|
||||||
|
) {
|
||||||
settings.passwordStrengthOptions = {
|
settings.passwordStrengthOptions = {
|
||||||
pattern: process.env.SHARELATEX_PASSWORD_VALIDATION_PATTERN || "aA$3",
|
pattern: process.env.SHARELATEX_PASSWORD_VALIDATION_PATTERN || 'aA$3',
|
||||||
length: {min:process.env.SHARELATEX_PASSWORD_VALIDATION_MIN_LENGTH || 8, max: process.env.SHARELATEX_PASSWORD_VALIDATION_MAX_LENGTH || 150}
|
length: {
|
||||||
};
|
min: process.env.SHARELATEX_PASSWORD_VALIDATION_MIN_LENGTH || 8,
|
||||||
|
max: process.env.SHARELATEX_PASSWORD_VALIDATION_MAX_LENGTH || 150,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ######################
|
// ######################
|
||||||
// ShareLaTeX Server Pro
|
// ShareLaTeX Server Pro
|
||||||
// ######################
|
// ######################
|
||||||
|
|
||||||
if (parse(process.env.SHARELATEX_IS_SERVER_PRO) === true) {
|
if (parse(process.env.SHARELATEX_IS_SERVER_PRO) === true) {
|
||||||
settings.bypassPercentageRollouts = true;
|
settings.bypassPercentageRollouts = true
|
||||||
settings.apis.references =
|
settings.apis.references = { url: 'http://localhost:3040' }
|
||||||
{url: "http://localhost:3040"};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// LDAP - SERVER PRO ONLY
|
// LDAP - SERVER PRO ONLY
|
||||||
// ----------
|
// ----------
|
||||||
|
|
||||||
|
@ -411,18 +458,21 @@ if (process.env.SHARELATEX_LDAP_HOST) {
|
||||||
# See https://github.com/sharelatex/sharelatex/wiki/Server-Pro:-LDAP-Config
|
# See https://github.com/sharelatex/sharelatex/wiki/Server-Pro:-LDAP-Config
|
||||||
#
|
#
|
||||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #\
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #\
|
||||||
`
|
`)
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.SHARELATEX_LDAP_URL) {
|
if (process.env.SHARELATEX_LDAP_URL) {
|
||||||
let _ldap_connect_timeout, _ldap_group_search_attribs, _ldap_search_attribs, _ldap_timeout;
|
let _ldap_connect_timeout,
|
||||||
settings.externalAuth = true;
|
_ldap_group_search_attribs,
|
||||||
|
_ldap_search_attribs,
|
||||||
|
_ldap_timeout
|
||||||
|
settings.externalAuth = true
|
||||||
settings.ldap = {
|
settings.ldap = {
|
||||||
emailAtt: process.env.SHARELATEX_LDAP_EMAIL_ATT,
|
emailAtt: process.env.SHARELATEX_LDAP_EMAIL_ATT,
|
||||||
nameAtt: process.env.SHARELATEX_LDAP_NAME_ATT,
|
nameAtt: process.env.SHARELATEX_LDAP_NAME_ATT,
|
||||||
lastNameAtt: process.env.SHARELATEX_LDAP_LAST_NAME_ATT,
|
lastNameAtt: process.env.SHARELATEX_LDAP_LAST_NAME_ATT,
|
||||||
updateUserDetailsOnLogin: process.env.SHARELATEX_LDAP_UPDATE_USER_DETAILS_ON_LOGIN === 'true',
|
updateUserDetailsOnLogin:
|
||||||
|
process.env.SHARELATEX_LDAP_UPDATE_USER_DETAILS_ON_LOGIN === 'true',
|
||||||
placeholder: process.env.SHARELATEX_LDAP_PLACEHOLDER,
|
placeholder: process.env.SHARELATEX_LDAP_PLACEHOLDER,
|
||||||
server: {
|
server: {
|
||||||
url: process.env.SHARELATEX_LDAP_URL,
|
url: process.env.SHARELATEX_LDAP_URL,
|
||||||
|
@ -432,94 +482,108 @@ if (process.env.SHARELATEX_LDAP_URL) {
|
||||||
searchBase: process.env.SHARELATEX_LDAP_SEARCH_BASE,
|
searchBase: process.env.SHARELATEX_LDAP_SEARCH_BASE,
|
||||||
searchScope: process.env.SHARELATEX_LDAP_SEARCH_SCOPE,
|
searchScope: process.env.SHARELATEX_LDAP_SEARCH_SCOPE,
|
||||||
searchFilter: process.env.SHARELATEX_LDAP_SEARCH_FILTER,
|
searchFilter: process.env.SHARELATEX_LDAP_SEARCH_FILTER,
|
||||||
searchAttributes: (
|
searchAttributes: (_ldap_search_attribs =
|
||||||
(_ldap_search_attribs = process.env.SHARELATEX_LDAP_SEARCH_ATTRIBUTES) ?
|
process.env.SHARELATEX_LDAP_SEARCH_ATTRIBUTES)
|
||||||
(() => { try {
|
? (() => {
|
||||||
return JSON.parse(_ldap_search_attribs);
|
try {
|
||||||
|
return JSON.parse(_ldap_search_attribs)
|
||||||
} catch (error3) {
|
} catch (error3) {
|
||||||
e = error3;
|
e = error3
|
||||||
return console.error("could not parse SHARELATEX_LDAP_SEARCH_ATTRIBUTES");
|
return console.error(
|
||||||
} })()
|
'could not parse SHARELATEX_LDAP_SEARCH_ATTRIBUTES'
|
||||||
:
|
)
|
||||||
undefined
|
}
|
||||||
),
|
})()
|
||||||
|
: undefined,
|
||||||
groupDnProperty: process.env.SHARELATEX_LDAP_GROUP_DN_PROPERTY,
|
groupDnProperty: process.env.SHARELATEX_LDAP_GROUP_DN_PROPERTY,
|
||||||
groupSearchBase: process.env.SHARELATEX_LDAP_GROUP_SEARCH_BASE,
|
groupSearchBase: process.env.SHARELATEX_LDAP_GROUP_SEARCH_BASE,
|
||||||
groupSearchScope: process.env.SHARELATEX_LDAP_GROUP_SEARCH_SCOPE,
|
groupSearchScope: process.env.SHARELATEX_LDAP_GROUP_SEARCH_SCOPE,
|
||||||
groupSearchFilter: process.env.SHARELATEX_LDAP_GROUP_SEARCH_FILTER,
|
groupSearchFilter: process.env.SHARELATEX_LDAP_GROUP_SEARCH_FILTER,
|
||||||
groupSearchAttributes: (
|
groupSearchAttributes: (_ldap_group_search_attribs =
|
||||||
(_ldap_group_search_attribs = process.env.SHARELATEX_LDAP_GROUP_SEARCH_ATTRIBUTES) ?
|
process.env.SHARELATEX_LDAP_GROUP_SEARCH_ATTRIBUTES)
|
||||||
(() => { try {
|
? (() => {
|
||||||
return JSON.parse(_ldap_group_search_attribs);
|
try {
|
||||||
|
return JSON.parse(_ldap_group_search_attribs)
|
||||||
} catch (error4) {
|
} catch (error4) {
|
||||||
e = error4;
|
e = error4
|
||||||
return console.error("could not parse SHARELATEX_LDAP_GROUP_SEARCH_ATTRIBUTES");
|
return console.error(
|
||||||
} })()
|
'could not parse SHARELATEX_LDAP_GROUP_SEARCH_ATTRIBUTES'
|
||||||
:
|
|
||||||
undefined
|
|
||||||
),
|
|
||||||
cache: process.env.SHARELATEX_LDAP_CACHE === 'true',
|
|
||||||
timeout: (
|
|
||||||
(_ldap_timeout = process.env.SHARELATEX_LDAP_TIMEOUT) ?
|
|
||||||
(() => { try {
|
|
||||||
return parseIntOrFail(_ldap_timeout);
|
|
||||||
} catch (error5) {
|
|
||||||
e = error5;
|
|
||||||
return console.error("Cannot parse SHARELATEX_LDAP_TIMEOUT");
|
|
||||||
} })()
|
|
||||||
:
|
|
||||||
undefined
|
|
||||||
),
|
|
||||||
connectTimeout: (
|
|
||||||
(_ldap_connect_timeout = process.env.SHARELATEX_LDAP_CONNECT_TIMEOUT) ?
|
|
||||||
(() => { try {
|
|
||||||
return parseIntOrFail(_ldap_connect_timeout);
|
|
||||||
} catch (error6) {
|
|
||||||
e = error6;
|
|
||||||
return console.error("Cannot parse SHARELATEX_LDAP_CONNECT_TIMEOUT");
|
|
||||||
} })()
|
|
||||||
:
|
|
||||||
undefined
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
})()
|
||||||
|
: undefined,
|
||||||
if (process.env.SHARELATEX_LDAP_TLS_OPTS_CA_PATH) {
|
cache: process.env.SHARELATEX_LDAP_CACHE === 'true',
|
||||||
let ca, ca_paths;
|
timeout: (_ldap_timeout = process.env.SHARELATEX_LDAP_TIMEOUT)
|
||||||
|
? (() => {
|
||||||
try {
|
try {
|
||||||
ca = JSON.parse(process.env.SHARELATEX_LDAP_TLS_OPTS_CA_PATH);
|
return parseIntOrFail(_ldap_timeout)
|
||||||
} catch (error7) {
|
} catch (error5) {
|
||||||
e = error7;
|
e = error5
|
||||||
console.error("could not parse SHARELATEX_LDAP_TLS_OPTS_CA_PATH, invalid JSON");
|
return console.error('Cannot parse SHARELATEX_LDAP_TIMEOUT')
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
: undefined,
|
||||||
|
connectTimeout: (_ldap_connect_timeout =
|
||||||
|
process.env.SHARELATEX_LDAP_CONNECT_TIMEOUT)
|
||||||
|
? (() => {
|
||||||
|
try {
|
||||||
|
return parseIntOrFail(_ldap_connect_timeout)
|
||||||
|
} catch (error6) {
|
||||||
|
e = error6
|
||||||
|
return console.error(
|
||||||
|
'Cannot parse SHARELATEX_LDAP_CONNECT_TIMEOUT'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
: undefined,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof(ca) === 'string') {
|
if (process.env.SHARELATEX_LDAP_TLS_OPTS_CA_PATH) {
|
||||||
ca_paths = [ca];
|
let ca, ca_paths
|
||||||
} else if ((typeof(ca) === 'object') && ((ca != null ? ca.length : undefined) != null)) {
|
try {
|
||||||
ca_paths = ca;
|
ca = JSON.parse(process.env.SHARELATEX_LDAP_TLS_OPTS_CA_PATH)
|
||||||
|
} catch (error7) {
|
||||||
|
e = error7
|
||||||
|
console.error(
|
||||||
|
'could not parse SHARELATEX_LDAP_TLS_OPTS_CA_PATH, invalid JSON'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof ca === 'string') {
|
||||||
|
ca_paths = [ca]
|
||||||
|
} else if (
|
||||||
|
typeof ca === 'object' &&
|
||||||
|
(ca != null ? ca.length : undefined) != null
|
||||||
|
) {
|
||||||
|
ca_paths = ca
|
||||||
} else {
|
} else {
|
||||||
console.error("problem parsing SHARELATEX_LDAP_TLS_OPTS_CA_PATH");
|
console.error('problem parsing SHARELATEX_LDAP_TLS_OPTS_CA_PATH')
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ldap.server.tlsOptions = {
|
settings.ldap.server.tlsOptions = {
|
||||||
rejectUnauthorized: process.env.SHARELATEX_LDAP_TLS_OPTS_REJECT_UNAUTH === "true",
|
rejectUnauthorized:
|
||||||
ca:ca_paths // e.g.'/etc/ldap/ca_certs.pem'
|
process.env.SHARELATEX_LDAP_TLS_OPTS_REJECT_UNAUTH === 'true',
|
||||||
};
|
ca: ca_paths, // e.g.'/etc/ldap/ca_certs.pem'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (process.env.SHARELATEX_SAML_ENTRYPOINT) {
|
if (process.env.SHARELATEX_SAML_ENTRYPOINT) {
|
||||||
// NOTE: see https://github.com/node-saml/passport-saml/blob/master/README.md for docs of `server` options
|
// NOTE: see https://github.com/node-saml/passport-saml/blob/master/README.md for docs of `server` options
|
||||||
let _saml_additionalAuthorizeParams, _saml_additionalLogoutParams, _saml_additionalParams, _saml_expiration, _saml_skew;
|
let _saml_additionalAuthorizeParams,
|
||||||
settings.externalAuth = true;
|
_saml_additionalLogoutParams,
|
||||||
|
_saml_additionalParams,
|
||||||
|
_saml_expiration,
|
||||||
|
_saml_skew
|
||||||
|
settings.externalAuth = true
|
||||||
settings.saml = {
|
settings.saml = {
|
||||||
updateUserDetailsOnLogin: process.env.SHARELATEX_SAML_UPDATE_USER_DETAILS_ON_LOGIN === 'true',
|
updateUserDetailsOnLogin:
|
||||||
|
process.env.SHARELATEX_SAML_UPDATE_USER_DETAILS_ON_LOGIN === 'true',
|
||||||
identityServiceName: process.env.SHARELATEX_SAML_IDENTITY_SERVICE_NAME,
|
identityServiceName: process.env.SHARELATEX_SAML_IDENTITY_SERVICE_NAME,
|
||||||
emailField: process.env.SHARELATEX_SAML_EMAIL_FIELD || process.env.SHARELATEX_SAML_EMAIL_FIELD_NAME,
|
emailField:
|
||||||
|
process.env.SHARELATEX_SAML_EMAIL_FIELD ||
|
||||||
|
process.env.SHARELATEX_SAML_EMAIL_FIELD_NAME,
|
||||||
firstNameField: process.env.SHARELATEX_SAML_FIRST_NAME_FIELD,
|
firstNameField: process.env.SHARELATEX_SAML_FIRST_NAME_FIELD,
|
||||||
lastNameField: process.env.SHARELATEX_SAML_LAST_NAME_FIELD,
|
lastNameField: process.env.SHARELATEX_SAML_LAST_NAME_FIELD,
|
||||||
server: {
|
server: {
|
||||||
|
@ -531,162 +595,184 @@ if (process.env.SHARELATEX_SAML_ENTRYPOINT) {
|
||||||
decryptionCert: process.env.SHARELATEX_SAML_DECRYPTION_CERT,
|
decryptionCert: process.env.SHARELATEX_SAML_DECRYPTION_CERT,
|
||||||
signatureAlgorithm: process.env.SHARELATEX_SAML_SIGNATURE_ALGORITHM,
|
signatureAlgorithm: process.env.SHARELATEX_SAML_SIGNATURE_ALGORITHM,
|
||||||
identifierFormat: process.env.SHARELATEX_SAML_IDENTIFIER_FORMAT,
|
identifierFormat: process.env.SHARELATEX_SAML_IDENTIFIER_FORMAT,
|
||||||
attributeConsumingServiceIndex: process.env.SHARELATEX_SAML_ATTRIBUTE_CONSUMING_SERVICE_INDEX,
|
attributeConsumingServiceIndex:
|
||||||
|
process.env.SHARELATEX_SAML_ATTRIBUTE_CONSUMING_SERVICE_INDEX,
|
||||||
authnContext: process.env.SHARELATEX_SAML_AUTHN_CONTEXT,
|
authnContext: process.env.SHARELATEX_SAML_AUTHN_CONTEXT,
|
||||||
authnRequestBinding: process.env.SHARELATEX_SAML_AUTHN_REQUEST_BINDING,
|
authnRequestBinding: process.env.SHARELATEX_SAML_AUTHN_REQUEST_BINDING,
|
||||||
validateInResponseTo: process.env.SHARELATEX_SAML_VALIDATE_IN_RESPONSE_TO,
|
validateInResponseTo: process.env.SHARELATEX_SAML_VALIDATE_IN_RESPONSE_TO,
|
||||||
cacheProvider: process.env.SHARELATEX_SAML_CACHE_PROVIDER,
|
cacheProvider: process.env.SHARELATEX_SAML_CACHE_PROVIDER,
|
||||||
logoutUrl: process.env.SHARELATEX_SAML_LOGOUT_URL,
|
logoutUrl: process.env.SHARELATEX_SAML_LOGOUT_URL,
|
||||||
logoutCallbackUrl: process.env.SHARELATEX_SAML_LOGOUT_CALLBACK_URL,
|
logoutCallbackUrl: process.env.SHARELATEX_SAML_LOGOUT_CALLBACK_URL,
|
||||||
disableRequestedAuthnContext: process.env.SHARELATEX_SAML_DISABLE_REQUESTED_AUTHN_CONTEXT === 'true',
|
disableRequestedAuthnContext:
|
||||||
|
process.env.SHARELATEX_SAML_DISABLE_REQUESTED_AUTHN_CONTEXT === 'true',
|
||||||
forceAuthn: process.env.SHARELATEX_SAML_FORCE_AUTHN === 'true',
|
forceAuthn: process.env.SHARELATEX_SAML_FORCE_AUTHN === 'true',
|
||||||
skipRequestCompression: process.env.SHARELATEX_SAML_SKIP_REQUEST_COMPRESSION === 'true',
|
skipRequestCompression:
|
||||||
acceptedClockSkewMs: (
|
process.env.SHARELATEX_SAML_SKIP_REQUEST_COMPRESSION === 'true',
|
||||||
(_saml_skew = process.env.SHARELATEX_SAML_ACCEPTED_CLOCK_SKEW_MS) ?
|
acceptedClockSkewMs: (_saml_skew =
|
||||||
(() => { try {
|
process.env.SHARELATEX_SAML_ACCEPTED_CLOCK_SKEW_MS)
|
||||||
return parseIntOrFail(_saml_skew);
|
? (() => {
|
||||||
|
try {
|
||||||
|
return parseIntOrFail(_saml_skew)
|
||||||
} catch (error8) {
|
} catch (error8) {
|
||||||
e = error8;
|
e = error8
|
||||||
return console.error("Cannot parse SHARELATEX_SAML_ACCEPTED_CLOCK_SKEW_MS");
|
return console.error(
|
||||||
} })()
|
'Cannot parse SHARELATEX_SAML_ACCEPTED_CLOCK_SKEW_MS'
|
||||||
:
|
|
||||||
undefined
|
|
||||||
),
|
|
||||||
requestIdExpirationPeriodMs: (
|
|
||||||
(_saml_expiration = process.env.SHARELATEX_SAML_REQUEST_ID_EXPIRATION_PERIOD_MS) ?
|
|
||||||
(() => { try {
|
|
||||||
return parseIntOrFail(_saml_expiration);
|
|
||||||
} catch (error9) {
|
|
||||||
e = error9;
|
|
||||||
return console.error("Cannot parse SHARELATEX_SAML_REQUEST_ID_EXPIRATION_PERIOD_MS");
|
|
||||||
} })()
|
|
||||||
:
|
|
||||||
undefined
|
|
||||||
),
|
|
||||||
additionalParams: (
|
|
||||||
(_saml_additionalParams = process.env.SHARELATEX_SAML_ADDITIONAL_PARAMS) ?
|
|
||||||
(() => { try {
|
|
||||||
return JSON.parse(_saml_additionalParams);
|
|
||||||
} catch (error10) {
|
|
||||||
e = error10;
|
|
||||||
return console.error("Cannot parse SHARELATEX_SAML_ADDITIONAL_PARAMS");
|
|
||||||
} })()
|
|
||||||
:
|
|
||||||
undefined
|
|
||||||
),
|
|
||||||
additionalAuthorizeParams: (
|
|
||||||
(_saml_additionalAuthorizeParams = process.env.SHARELATEX_SAML_ADDITIONAL_AUTHORIZE_PARAMS) ?
|
|
||||||
(() => { try {
|
|
||||||
return JSON.parse(_saml_additionalAuthorizeParams );
|
|
||||||
} catch (error11) {
|
|
||||||
e = error11;
|
|
||||||
return console.error("Cannot parse SHARELATEX_SAML_ADDITIONAL_AUTHORIZE_PARAMS");
|
|
||||||
} })()
|
|
||||||
:
|
|
||||||
undefined
|
|
||||||
),
|
|
||||||
additionalLogoutParams: (
|
|
||||||
(_saml_additionalLogoutParams = process.env.SHARELATEX_SAML_ADDITIONAL_LOGOUT_PARAMS) ?
|
|
||||||
(() => { try {
|
|
||||||
return JSON.parse(_saml_additionalLogoutParams );
|
|
||||||
} catch (error12) {
|
|
||||||
e = error12;
|
|
||||||
return console.error("Cannot parse SHARELATEX_SAML_ADDITIONAL_LOGOUT_PARAMS");
|
|
||||||
} })()
|
|
||||||
:
|
|
||||||
undefined
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
})()
|
||||||
|
: undefined,
|
||||||
|
requestIdExpirationPeriodMs: (_saml_expiration =
|
||||||
|
process.env.SHARELATEX_SAML_REQUEST_ID_EXPIRATION_PERIOD_MS)
|
||||||
|
? (() => {
|
||||||
|
try {
|
||||||
|
return parseIntOrFail(_saml_expiration)
|
||||||
|
} catch (error9) {
|
||||||
|
e = error9
|
||||||
|
return console.error(
|
||||||
|
'Cannot parse SHARELATEX_SAML_REQUEST_ID_EXPIRATION_PERIOD_MS'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
: undefined,
|
||||||
|
additionalParams: (_saml_additionalParams =
|
||||||
|
process.env.SHARELATEX_SAML_ADDITIONAL_PARAMS)
|
||||||
|
? (() => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(_saml_additionalParams)
|
||||||
|
} catch (error10) {
|
||||||
|
e = error10
|
||||||
|
return console.error(
|
||||||
|
'Cannot parse SHARELATEX_SAML_ADDITIONAL_PARAMS'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
: undefined,
|
||||||
|
additionalAuthorizeParams: (_saml_additionalAuthorizeParams =
|
||||||
|
process.env.SHARELATEX_SAML_ADDITIONAL_AUTHORIZE_PARAMS)
|
||||||
|
? (() => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(_saml_additionalAuthorizeParams)
|
||||||
|
} catch (error11) {
|
||||||
|
e = error11
|
||||||
|
return console.error(
|
||||||
|
'Cannot parse SHARELATEX_SAML_ADDITIONAL_AUTHORIZE_PARAMS'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
: undefined,
|
||||||
|
additionalLogoutParams: (_saml_additionalLogoutParams =
|
||||||
|
process.env.SHARELATEX_SAML_ADDITIONAL_LOGOUT_PARAMS)
|
||||||
|
? (() => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(_saml_additionalLogoutParams)
|
||||||
|
} catch (error12) {
|
||||||
|
e = error12
|
||||||
|
return console.error(
|
||||||
|
'Cannot parse SHARELATEX_SAML_ADDITIONAL_LOGOUT_PARAMS'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
: undefined,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// SHARELATEX_SAML_CERT cannot be empty
|
// SHARELATEX_SAML_CERT cannot be empty
|
||||||
// https://github.com/node-saml/passport-saml/commit/f6b1c885c0717f1083c664345556b535f217c102
|
// https://github.com/node-saml/passport-saml/commit/f6b1c885c0717f1083c664345556b535f217c102
|
||||||
if (process.env.SHARELATEX_SAML_CERT) {
|
if (process.env.SHARELATEX_SAML_CERT) {
|
||||||
settings.saml.server.cert = process.env.SHARELATEX_SAML_CERT;
|
settings.saml.server.cert = process.env.SHARELATEX_SAML_CERT
|
||||||
settings.saml.server.privateCert = process.env.SHARELATEX_SAML_PRIVATE_CERT;
|
settings.saml.server.privateCert = process.env.SHARELATEX_SAML_PRIVATE_CERT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compiler
|
// Compiler
|
||||||
// --------
|
// --------
|
||||||
if (process.env.SANDBOXED_COMPILES === "true") {
|
if (process.env.SANDBOXED_COMPILES === 'true') {
|
||||||
settings.clsi = {
|
settings.clsi = {
|
||||||
dockerRunner: true,
|
dockerRunner: true,
|
||||||
docker: {
|
docker: {
|
||||||
image: process.env.TEX_LIVE_DOCKER_IMAGE,
|
image: process.env.TEX_LIVE_DOCKER_IMAGE,
|
||||||
env: {
|
env: {
|
||||||
HOME: "/tmp",
|
HOME: '/tmp',
|
||||||
PATH: process.env.COMPILER_PATH || "/usr/local/texlive/2015/bin/x86_64-linux:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
PATH:
|
||||||
|
process.env.COMPILER_PATH ||
|
||||||
|
'/usr/local/texlive/2015/bin/x86_64-linux:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
|
||||||
|
},
|
||||||
|
user: 'www-data',
|
||||||
},
|
},
|
||||||
user: "www-data"
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if ((settings.path == null)) {
|
if (settings.path == null) {
|
||||||
settings.path = {};
|
settings.path = {}
|
||||||
}
|
}
|
||||||
settings.path.synctexBaseDir = () => "/compile";
|
settings.path.synctexBaseDir = () => '/compile'
|
||||||
if (process.env.SANDBOXED_COMPILES_SIBLING_CONTAINERS === 'true') {
|
if (process.env.SANDBOXED_COMPILES_SIBLING_CONTAINERS === 'true') {
|
||||||
console.log("Using sibling containers for sandboxed compiles");
|
console.log('Using sibling containers for sandboxed compiles')
|
||||||
if (process.env.SANDBOXED_COMPILES_HOST_DIR) {
|
if (process.env.SANDBOXED_COMPILES_HOST_DIR) {
|
||||||
settings.path.sandboxedCompilesHostDir = process.env.SANDBOXED_COMPILES_HOST_DIR;
|
settings.path.sandboxedCompilesHostDir =
|
||||||
|
process.env.SANDBOXED_COMPILES_HOST_DIR
|
||||||
} else {
|
} else {
|
||||||
console.error('Sibling containers, but SANDBOXED_COMPILES_HOST_DIR not set');
|
console.error(
|
||||||
|
'Sibling containers, but SANDBOXED_COMPILES_HOST_DIR not set'
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Templates
|
// Templates
|
||||||
// ---------
|
// ---------
|
||||||
if (process.env.SHARELATEX_TEMPLATES_USER_ID) {
|
if (process.env.SHARELATEX_TEMPLATES_USER_ID) {
|
||||||
settings.templates = {
|
settings.templates = {
|
||||||
mountPointUrl: "/templates",
|
mountPointUrl: '/templates',
|
||||||
user_id: process.env.SHARELATEX_TEMPLATES_USER_ID
|
user_id: process.env.SHARELATEX_TEMPLATES_USER_ID,
|
||||||
};
|
}
|
||||||
|
|
||||||
settings.templateLinks = parse(process.env.SHARELATEX_NEW_PROJECT_TEMPLATE_LINKS);
|
settings.templateLinks = parse(
|
||||||
|
process.env.SHARELATEX_NEW_PROJECT_TEMPLATE_LINKS
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// /Learn
|
// /Learn
|
||||||
// -------
|
// -------
|
||||||
if (process.env.SHARELATEX_PROXY_LEARN != null) {
|
if (process.env.SHARELATEX_PROXY_LEARN != null) {
|
||||||
settings.proxyLearn = parse(process.env.SHARELATEX_PROXY_LEARN);
|
settings.proxyLearn = parse(process.env.SHARELATEX_PROXY_LEARN)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// /References
|
// /References
|
||||||
// -----------
|
// -----------
|
||||||
if (process.env.SHARELATEX_ELASTICSEARCH_URL != null) {
|
if (process.env.SHARELATEX_ELASTICSEARCH_URL != null) {
|
||||||
settings.references.elasticsearch =
|
settings.references.elasticsearch = {
|
||||||
{host: process.env.SHARELATEX_ELASTICSEARCH_URL};
|
host: process.env.SHARELATEX_ELASTICSEARCH_URL,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TeX Live Images
|
// TeX Live Images
|
||||||
// -----------
|
// -----------
|
||||||
if (process.env.ALL_TEX_LIVE_DOCKER_IMAGES != null) {
|
if (process.env.ALL_TEX_LIVE_DOCKER_IMAGES != null) {
|
||||||
allTexLiveDockerImages = process.env.ALL_TEX_LIVE_DOCKER_IMAGES.split(',');
|
allTexLiveDockerImages = process.env.ALL_TEX_LIVE_DOCKER_IMAGES.split(',')
|
||||||
}
|
}
|
||||||
if (process.env.ALL_TEX_LIVE_DOCKER_IMAGE_NAMES != null) {
|
if (process.env.ALL_TEX_LIVE_DOCKER_IMAGE_NAMES != null) {
|
||||||
allTexLiveDockerImageNames = process.env.ALL_TEX_LIVE_DOCKER_IMAGE_NAMES.split(',');
|
allTexLiveDockerImageNames =
|
||||||
|
process.env.ALL_TEX_LIVE_DOCKER_IMAGE_NAMES.split(',')
|
||||||
}
|
}
|
||||||
if (allTexLiveDockerImages != null) {
|
if (allTexLiveDockerImages != null) {
|
||||||
settings.allowedImageNames = [];
|
settings.allowedImageNames = []
|
||||||
for (let index = 0; index < allTexLiveDockerImages.length; index++) {
|
for (let index = 0; index < allTexLiveDockerImages.length; index++) {
|
||||||
const fullImageName = allTexLiveDockerImages[index];
|
const fullImageName = allTexLiveDockerImages[index]
|
||||||
const imageName = Path.basename(fullImageName);
|
const imageName = Path.basename(fullImageName)
|
||||||
const imageDesc = (allTexLiveDockerImageNames != null) ? allTexLiveDockerImageNames[index] : imageName;
|
const imageDesc =
|
||||||
settings.allowedImageNames.push({ imageName, imageDesc });
|
allTexLiveDockerImageNames != null
|
||||||
|
? allTexLiveDockerImageNames[index]
|
||||||
|
: imageName
|
||||||
|
settings.allowedImageNames.push({ imageName, imageDesc })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// With lots of incoming and outgoing HTTP connections to different services,
|
// With lots of incoming and outgoing HTTP connections to different services,
|
||||||
// sometimes long running, it is a good idea to increase the default number
|
// sometimes long running, it is a good idea to increase the default number
|
||||||
// of sockets that Node will hold open.
|
// of sockets that Node will hold open.
|
||||||
const http = require('http');
|
const http = require('http')
|
||||||
http.globalAgent.maxSockets = 300;
|
http.globalAgent.maxSockets = 300
|
||||||
const https = require('https');
|
const https = require('https')
|
||||||
https.globalAgent.maxSockets = 300;
|
https.globalAgent.maxSockets = 300
|
||||||
|
|
||||||
module.exports = settings;
|
module.exports = settings
|
||||||
|
|
|
@ -11,35 +11,55 @@
|
||||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = function(grunt) {
|
module.exports = function (grunt) {
|
||||||
|
grunt.registerTask(
|
||||||
grunt.registerTask('user:create-admin', "Create a user with the given email address and make them an admin. Update in place if the user already exists. Usage: grunt user:create-admin --email joe@example.com", function() {
|
'user:create-admin',
|
||||||
const done = this.async();
|
'Create a user with the given email address and make them an admin. Update in place if the user already exists. Usage: grunt user:create-admin --email joe@example.com',
|
||||||
const email = grunt.option("email");
|
function () {
|
||||||
if ((email == null)) {
|
const done = this.async()
|
||||||
console.error("Usage: grunt user:create-admin --email=joe@example.com");
|
const email = grunt.option('email')
|
||||||
process.exit(1);
|
if (email == null) {
|
||||||
|
console.error('Usage: grunt user:create-admin --email=joe@example.com')
|
||||||
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
const settings = require("settings-sharelatex");
|
const settings = require('settings-sharelatex')
|
||||||
const mongodb = require("../web/app/src/infrastructure/mongodb");
|
const mongodb = require('../web/app/src/infrastructure/mongodb')
|
||||||
const UserRegistrationHandler = require("../web/app/src/Features/User/UserRegistrationHandler");
|
const UserRegistrationHandler = require('../web/app/src/Features/User/UserRegistrationHandler')
|
||||||
const OneTimeTokenHandler = require("../web/app/src/Features/Security/OneTimeTokenHandler");
|
const OneTimeTokenHandler = require('../web/app/src/Features/Security/OneTimeTokenHandler')
|
||||||
return mongodb.waitForDb().then(() => UserRegistrationHandler.registerNewUser({
|
return mongodb.waitForDb().then(() =>
|
||||||
|
UserRegistrationHandler.registerNewUser(
|
||||||
|
{
|
||||||
email,
|
email,
|
||||||
password: require("crypto").randomBytes(32).toString("hex")
|
password: require('crypto').randomBytes(32).toString('hex'),
|
||||||
}, function(error, user) {
|
},
|
||||||
if ((error != null) && ((error != null ? error.message : undefined) !== "EmailAlreadyRegistered")) {
|
function (error, user) {
|
||||||
throw error;
|
if (
|
||||||
|
error != null &&
|
||||||
|
(error != null ? error.message : undefined) !==
|
||||||
|
'EmailAlreadyRegistered'
|
||||||
|
) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
user.isAdmin = true
|
||||||
|
return user.save(function (error) {
|
||||||
|
if (error != null) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
const ONE_WEEK = 7 * 24 * 60 * 60 // seconds
|
||||||
|
return OneTimeTokenHandler.getNewToken(
|
||||||
|
'password',
|
||||||
|
{
|
||||||
|
expiresIn: ONE_WEEK,
|
||||||
|
email: user.email,
|
||||||
|
user_id: user._id.toString(),
|
||||||
|
},
|
||||||
|
function (err, token) {
|
||||||
|
if (err != null) {
|
||||||
|
return next(err)
|
||||||
}
|
}
|
||||||
user.isAdmin = true;
|
|
||||||
return user.save(function(error) {
|
|
||||||
if (error != null) { throw error; }
|
|
||||||
const ONE_WEEK = 7 * 24 * 60 * 60; // seconds
|
|
||||||
return OneTimeTokenHandler.getNewToken("password", { expiresIn: ONE_WEEK, email:user.email, user_id: user._id.toString() }, function(err, token){
|
|
||||||
if (err != null) { return next(err); }
|
|
||||||
|
|
||||||
console.log("");
|
console.log('')
|
||||||
console.log(`\
|
console.log(`\
|
||||||
Successfully created ${email} as an admin user.
|
Successfully created ${email} as an admin user.
|
||||||
|
|
||||||
|
@ -47,39 +67,50 @@ Please visit the following URL to set a password for ${email} and log in:
|
||||||
|
|
||||||
${settings.siteUrl}/user/password/set?passwordResetToken=${token}
|
${settings.siteUrl}/user/password/set?passwordResetToken=${token}
|
||||||
\
|
\
|
||||||
`
|
`)
|
||||||
);
|
return done()
|
||||||
return done();
|
}
|
||||||
});
|
)
|
||||||
});
|
})
|
||||||
}));
|
}
|
||||||
});
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return grunt.registerTask('user:delete', "deletes a user and all their data, Usage: grunt user:delete --email joe@example.com", function() {
|
return grunt.registerTask(
|
||||||
const done = this.async();
|
'user:delete',
|
||||||
const email = grunt.option("email");
|
'deletes a user and all their data, Usage: grunt user:delete --email joe@example.com',
|
||||||
if ((email == null)) {
|
function () {
|
||||||
console.error("Usage: grunt user:delete --email=joe@example.com");
|
const done = this.async()
|
||||||
process.exit(1);
|
const email = grunt.option('email')
|
||||||
|
if (email == null) {
|
||||||
|
console.error('Usage: grunt user:delete --email=joe@example.com')
|
||||||
|
process.exit(1)
|
||||||
}
|
}
|
||||||
const settings = require("settings-sharelatex");
|
const settings = require('settings-sharelatex')
|
||||||
const mongodb = require("../web/app/src/infrastructure/mongodb");
|
const mongodb = require('../web/app/src/infrastructure/mongodb')
|
||||||
const UserGetter = require("../web/app/src/Features/User/UserGetter");
|
const UserGetter = require('../web/app/src/Features/User/UserGetter')
|
||||||
const UserDeleter = require("../web/app/src/Features/User/UserDeleter");
|
const UserDeleter = require('../web/app/src/Features/User/UserDeleter')
|
||||||
return mongodb.waitForDb().then(() => UserGetter.getUser({email}, function(error, user) {
|
return mongodb.waitForDb().then(() =>
|
||||||
|
UserGetter.getUser({ email }, function (error, user) {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
throw error;
|
throw error
|
||||||
}
|
}
|
||||||
if ((user == null)) {
|
if (user == null) {
|
||||||
console.log(`user ${email} not in database, potentially already deleted`);
|
console.log(
|
||||||
return done();
|
`user ${email} not in database, potentially already deleted`
|
||||||
|
)
|
||||||
|
return done()
|
||||||
}
|
}
|
||||||
return UserDeleter.deleteUser(user._id, function(err){
|
return UserDeleter.deleteUser(user._id, function (err) {
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
throw err;
|
throw err
|
||||||
}
|
}
|
||||||
return done();
|
return done()
|
||||||
});
|
})
|
||||||
}));
|
})
|
||||||
});
|
)
|
||||||
};
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue