settings.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. /*
  2. * decaffeinate suggestions:
  3. * DS205: Consider reworking code to avoid use of IIFEs
  4. * DS207: Consider shorter variations of null checks
  5. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  6. */
  7. let allTexLiveDockerImageNames, allTexLiveDockerImages, redisConfig, siteUrl;
  8. let e;
  9. const Path = require('path');
  10. // These credentials are used for authenticating api requests
  11. // between services that may need to go over public channels
  12. const httpAuthUser = "sharelatex";
  13. const httpAuthPass = process.env["WEB_API_PASSWORD"];
  14. const httpAuthUsers = {};
  15. httpAuthUsers[httpAuthUser] = httpAuthPass;
  16. const parse = function(option){
  17. if (option != null) {
  18. try {
  19. const opt = JSON.parse(option);
  20. return opt;
  21. } catch (err) {
  22. throw new Error(`problem parsing ${option}, invalid JSON`);
  23. }
  24. }
  25. };
  26. const parseIntOrFail = function(value){
  27. const parsedValue = parseInt(value, 10);
  28. if (isNaN(parsedValue)) {
  29. throw new Error(`'${value}' is an invalid integer`);
  30. }
  31. return parsedValue;
  32. };
  33. const DATA_DIR = '/var/lib/sharelatex/data';
  34. const TMP_DIR = '/var/lib/sharelatex/tmp';
  35. const settings = {
  36. clsi: {
  37. optimiseInDocker: process.env['OPTIMISE_PDF'] === 'true'
  38. },
  39. brandPrefix: "",
  40. allowAnonymousReadAndWriteSharing:
  41. process.env['SHARELATEX_ALLOW_ANONYMOUS_READ_AND_WRITE_SHARING'] === 'true',
  42. // Databases
  43. // ---------
  44. // ShareLaTeX's main persistent data store is MongoDB (http://www.mongodb.org/)
  45. // Documentation about the URL connection string format can be found at:
  46. //
  47. // http://docs.mongodb.org/manual/reference/connection-string/
  48. //
  49. // The following works out of the box with Mongo's default settings:
  50. mongo: {
  51. url : process.env["SHARELATEX_MONGO_URL"] || 'mongodb://dockerhost/sharelatex'
  52. },
  53. // Redis is used in ShareLaTeX for high volume queries, like real-time
  54. // editing, and session management.
  55. //
  56. // The following config will work with Redis's default settings:
  57. redis: {
  58. web: (redisConfig = {
  59. host: process.env["SHARELATEX_REDIS_HOST"] || "dockerhost",
  60. port: process.env["SHARELATEX_REDIS_PORT"] || "6379",
  61. password: process.env["SHARELATEX_REDIS_PASS"] || undefined,
  62. key_schema: {
  63. // document-updater
  64. blockingKey({doc_id}) { return `Blocking:${doc_id}`; },
  65. docLines({doc_id}) { return `doclines:${doc_id}`; },
  66. docOps({doc_id}) { return `DocOps:${doc_id}`; },
  67. docVersion({doc_id}) { return `DocVersion:${doc_id}`; },
  68. docHash({doc_id}) { return `DocHash:${doc_id}`; },
  69. projectKey({doc_id}) { return `ProjectId:${doc_id}`; },
  70. docsInProject({project_id}) { return `DocsIn:${project_id}`; },
  71. ranges({doc_id}) { return `Ranges:${doc_id}`; },
  72. // document-updater:realtime
  73. pendingUpdates({doc_id}) { return `PendingUpdates:${doc_id}`; },
  74. // document-updater:history
  75. uncompressedHistoryOps({doc_id}) { return `UncompressedHistoryOps:${doc_id}`; },
  76. docsWithHistoryOps({project_id}) { return `DocsWithHistoryOps:${project_id}`; },
  77. // document-updater:lock
  78. blockingKey({doc_id}) { return `Blocking:${doc_id}`; },
  79. // track-changes:lock
  80. historyLock({doc_id}) { return `HistoryLock:${doc_id}`; },
  81. historyIndexLock({project_id}) { return `HistoryIndexLock:${project_id}`; },
  82. // track-changes:history
  83. uncompressedHistoryOps({doc_id}) { return `UncompressedHistoryOps:${doc_id}`; },
  84. docsWithHistoryOps({project_id}) { return `DocsWithHistoryOps:${project_id}`; },
  85. // realtime
  86. clientsInProject({project_id}) { return `clients_in_project:${project_id}`; },
  87. connectedUser({project_id, client_id}){ return `connected_user:${project_id}:${client_id}`; }
  88. }
  89. }),
  90. fairy: redisConfig,
  91. // track-changes and document-updater
  92. realtime: redisConfig,
  93. documentupdater: redisConfig,
  94. lock: redisConfig,
  95. history: redisConfig,
  96. websessions: redisConfig,
  97. api: redisConfig,
  98. pubsub: redisConfig,
  99. project_history: redisConfig
  100. },
  101. // The compile server (the clsi) uses a SQL database to cache files and
  102. // meta-data. sqlite is the default, and the load is low enough that this will
  103. // be fine in production (we use sqlite at sharelatex.com).
  104. //
  105. // If you want to configure a different database, see the Sequelize documentation
  106. // for available options:
  107. //
  108. // https://github.com/sequelize/sequelize/wiki/API-Reference-Sequelize#example-usage
  109. //
  110. mysql: {
  111. clsi: {
  112. database: "clsi",
  113. username: "clsi",
  114. password: "",
  115. dialect: "sqlite",
  116. storage: Path.join(DATA_DIR, "db.sqlite")
  117. }
  118. },
  119. // File storage
  120. // ------------
  121. // ShareLaTeX can store binary files like images either locally or in Amazon
  122. // S3. The default is locally:
  123. filestore: {
  124. backend: "fs",
  125. stores: {
  126. user_files: Path.join(DATA_DIR, "user_files"),
  127. template_files: Path.join(DATA_DIR, "template_files")
  128. }
  129. },
  130. // To use Amazon S3 as a storage backend, comment out the above config, and
  131. // uncomment the following, filling in your key, secret, and bucket name:
  132. //
  133. // filestore:
  134. // backend: "s3"
  135. // stores:
  136. // user_files: "BUCKET_NAME"
  137. // s3:
  138. // key: "AWS_KEY"
  139. // secret: "AWS_SECRET"
  140. //
  141. trackchanges: {
  142. continueOnError: true
  143. },
  144. // Local disk caching
  145. // ------------------
  146. path: {
  147. // If we ever need to write something to disk (e.g. incoming requests
  148. // that need processing but may be too big for memory), then write
  149. // them to disk here:
  150. dumpFolder: Path.join(TMP_DIR, "dumpFolder"),
  151. // Where to write uploads before they are processed
  152. uploadFolder: Path.join(TMP_DIR, "uploads"),
  153. // Where to write the project to disk before running LaTeX on it
  154. compilesDir: Path.join(DATA_DIR, "compiles"),
  155. // Where to cache downloaded URLs for the CLSI
  156. clsiCacheDir: Path.join(DATA_DIR, "cache"),
  157. // Where to write the output files to disk after running LaTeX
  158. outputDir: Path.join(DATA_DIR, "output")
  159. },
  160. // Server Config
  161. // -------------
  162. // Where your instance of ShareLaTeX can be found publicly. This is used
  163. // when emails are sent out and in generated links:
  164. siteUrl: (siteUrl = process.env["SHARELATEX_SITE_URL"] || 'http://localhost'),
  165. // The name this is used to describe your ShareLaTeX Installation
  166. appName: process.env["SHARELATEX_APP_NAME"] || "ShareLaTeX (Community Edition)",
  167. restrictInvitesToExistingAccounts: process.env["SHARELATEX_RESTRICT_INVITES_TO_EXISTING_ACCOUNTS"] === 'true',
  168. nav: {
  169. title: process.env["SHARELATEX_NAV_TITLE"] || process.env["SHARELATEX_APP_NAME"] || "ShareLaTeX Community Edition"
  170. },
  171. // The email address which users will be directed to as the main point of
  172. // contact for this installation of ShareLaTeX.
  173. adminEmail: process.env["SHARELATEX_ADMIN_EMAIL"] || "placeholder@example.com",
  174. // If provided, a sessionSecret is used to sign cookies so that they cannot be
  175. // spoofed. This is recommended.
  176. security: {
  177. sessionSecret: process.env["SHARELATEX_SESSION_SECRET"] || process.env["CRYPTO_RANDOM"]
  178. },
  179. // These credentials are used for authenticating api requests
  180. // between services that may need to go over public channels
  181. httpAuthUsers,
  182. // Should javascript assets be served minified or not.
  183. useMinifiedJs: true,
  184. // Should static assets be sent with a header to tell the browser to cache
  185. // them. This should be false in development where changes are being made,
  186. // but should be set to true in production.
  187. cacheStaticAssets: true,
  188. // If you are running ShareLaTeX over https, set this to true to send the
  189. // cookie with a secure flag (recommended).
  190. secureCookie: (process.env["SHARELATEX_SECURE_COOKIE"] != null),
  191. // If you are running ShareLaTeX behind a proxy (like Apache, Nginx, etc)
  192. // then set this to true to allow it to correctly detect the forwarded IP
  193. // address and http/https protocol information.
  194. behindProxy: process.env["SHARELATEX_BEHIND_PROXY"] || false,
  195. i18n: {
  196. subdomainLang: {
  197. www: {lngCode:process.env["SHARELATEX_SITE_LANGUAGE"] || "en", url: siteUrl}
  198. },
  199. defaultLng: process.env["SHARELATEX_SITE_LANGUAGE"] || "en"
  200. },
  201. currentImageName: process.env["TEX_LIVE_DOCKER_IMAGE"],
  202. apis: {
  203. web: {
  204. url: "http://localhost:3000",
  205. user: httpAuthUser,
  206. pass: httpAuthPass
  207. },
  208. project_history: {
  209. enabled: false
  210. }
  211. },
  212. references:{},
  213. notifications:undefined,
  214. defaultFeatures: {
  215. collaborators: -1,
  216. dropbox: true,
  217. versioning: true,
  218. compileTimeout: parseIntOrFail(process.env["COMPILE_TIMEOUT"] || 180),
  219. compileGroup: "standard",
  220. trackChanges: true,
  221. templates: true,
  222. references: true
  223. }
  224. };
  225. //# OPTIONAL CONFIGURABLE SETTINGS
  226. if (process.env["SHARELATEX_LEFT_FOOTER"] != null) {
  227. try {
  228. settings.nav.left_footer = JSON.parse(process.env["SHARELATEX_LEFT_FOOTER"]);
  229. } catch (error) {
  230. e = error;
  231. console.error("could not parse SHARELATEX_LEFT_FOOTER, not valid JSON");
  232. }
  233. }
  234. if (process.env["SHARELATEX_RIGHT_FOOTER"] != null) {
  235. settings.nav.right_footer = process.env["SHARELATEX_RIGHT_FOOTER"];
  236. try {
  237. settings.nav.right_footer = JSON.parse(process.env["SHARELATEX_RIGHT_FOOTER"]);
  238. } catch (error1) {
  239. e = error1;
  240. console.error("could not parse SHARELATEX_RIGHT_FOOTER, not valid JSON");
  241. }
  242. }
  243. if (process.env["SHARELATEX_HEADER_IMAGE_URL"] != null) {
  244. settings.nav.custom_logo = process.env["SHARELATEX_HEADER_IMAGE_URL"];
  245. }
  246. if (process.env["SHARELATEX_HEADER_NAV_LINKS"] != null) {
  247. console.error(`\
  248. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  249. #
  250. # WARNING: SHARELATEX_HEADER_NAV_LINKS is no longer supported
  251. # See https://github.com/sharelatex/sharelatex/wiki/Configuring-Headers,-Footers-&-Logo
  252. #
  253. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #\
  254. `
  255. );
  256. }
  257. if (process.env["SHARELATEX_HEADER_EXTRAS"] != null) {
  258. try {
  259. settings.nav.header_extras = JSON.parse(process.env["SHARELATEX_HEADER_EXTRAS"]);
  260. } catch (error2) {
  261. e = error2;
  262. console.error("could not parse SHARELATEX_HEADER_EXTRAS, not valid JSON");
  263. }
  264. }
  265. // Sending Email
  266. // -------------
  267. //
  268. // You must configure a mail server to be able to send invite emails from
  269. // ShareLaTeX. The config settings are passed to nodemailer. See the nodemailer
  270. // documentation for available options:
  271. //
  272. // http://www.nodemailer.com/docs/transports
  273. if (process.env["SHARELATEX_EMAIL_FROM_ADDRESS"] != null) {
  274. settings.email = {
  275. fromAddress: process.env["SHARELATEX_EMAIL_FROM_ADDRESS"],
  276. replyTo: process.env["SHARELATEX_EMAIL_REPLY_TO"] || "",
  277. driver: process.env["SHARELATEX_EMAIL_DRIVER"],
  278. parameters: {
  279. //AWS Creds
  280. AWSAccessKeyID: process.env["SHARELATEX_EMAIL_AWS_SES_ACCESS_KEY_ID"],
  281. AWSSecretKey: process.env["SHARELATEX_EMAIL_AWS_SES_SECRET_KEY"],
  282. //SMTP Creds
  283. host: process.env["SHARELATEX_EMAIL_SMTP_HOST"],
  284. port: process.env["SHARELATEX_EMAIL_SMTP_PORT"],
  285. secure: parse(process.env["SHARELATEX_EMAIL_SMTP_SECURE"]),
  286. ignoreTLS: parse(process.env["SHARELATEX_EMAIL_SMTP_IGNORE_TLS"]),
  287. name: process.env["SHARELATEX_EMAIL_SMTP_NAME"],
  288. logger: process.env["SHARELATEX_EMAIL_SMTP_LOGGER"] === 'true'
  289. },
  290. textEncoding: process.env["SHARELATEX_EMAIL_TEXT_ENCODING"],
  291. template: {
  292. customFooter: process.env["SHARELATEX_CUSTOM_EMAIL_FOOTER"]
  293. }
  294. };
  295. if (process.env["SHARELATEX_EMAIL_AWS_SES_REGION"] != null) {
  296. settings.email.parameters.region = process.env["SHARELATEX_EMAIL_AWS_SES_REGION"];
  297. }
  298. if ((process.env["SHARELATEX_EMAIL_SMTP_USER"] != null) || (process.env["SHARELATEX_EMAIL_SMTP_PASS"] != null)) {
  299. settings.email.parameters.auth = {
  300. user: process.env["SHARELATEX_EMAIL_SMTP_USER"],
  301. pass: process.env["SHARELATEX_EMAIL_SMTP_PASS"]
  302. };
  303. }
  304. if (process.env["SHARELATEX_EMAIL_SMTP_TLS_REJECT_UNAUTH"] != null) {
  305. settings.email.parameters.tls =
  306. {rejectUnauthorized: parse(process.env["SHARELATEX_EMAIL_SMTP_TLS_REJECT_UNAUTH"])};
  307. }
  308. }
  309. // i18n
  310. if (process.env["SHARELATEX_LANG_DOMAIN_MAPPING"] != null) {
  311. settings.i18n.subdomainLang = parse(process.env["SHARELATEX_LANG_DOMAIN_MAPPING"]);
  312. }
  313. // Password Settings
  314. // -----------
  315. // These restrict the passwords users can use when registering
  316. // opts are from http://antelle.github.io/passfield
  317. if (process.env["SHARELATEX_PASSWORD_VALIDATION_PATTERN"] || process.env["SHARELATEX_PASSWORD_VALIDATION_MIN_LENGTH"] || process.env["SHARELATEX_PASSWORD_VALIDATION_MAX_LENGTH"]) {
  318. settings.passwordStrengthOptions = {
  319. pattern: process.env["SHARELATEX_PASSWORD_VALIDATION_PATTERN"] || "aA$3",
  320. length: {min:process.env["SHARELATEX_PASSWORD_VALIDATION_MIN_LENGTH"] || 8, max: process.env["SHARELATEX_PASSWORD_VALIDATION_MAX_LENGTH"] || 150}
  321. };
  322. }
  323. //######################
  324. // ShareLaTeX Server Pro
  325. //######################
  326. if (parse(process.env["SHARELATEX_IS_SERVER_PRO"]) === true) {
  327. settings.bypassPercentageRollouts = true;
  328. settings.apis.references =
  329. {url: "http://localhost:3040"};
  330. }
  331. // LDAP - SERVER PRO ONLY
  332. // ----------
  333. if (process.env["SHARELATEX_LDAP_HOST"]) {
  334. console.error(`\
  335. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  336. #
  337. # WARNING: The LDAP configuration format has changed in version 0.5.1
  338. # See https://github.com/sharelatex/sharelatex/wiki/Server-Pro:-LDAP-Config
  339. #
  340. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #\
  341. `
  342. );
  343. }
  344. if (process.env["SHARELATEX_LDAP_URL"]) {
  345. let _ldap_connect_timeout, _ldap_group_search_attribs, _ldap_search_attribs, _ldap_timeout;
  346. settings.externalAuth = true;
  347. settings.ldap = {
  348. emailAtt: process.env["SHARELATEX_LDAP_EMAIL_ATT"],
  349. nameAtt: process.env["SHARELATEX_LDAP_NAME_ATT"],
  350. lastNameAtt: process.env["SHARELATEX_LDAP_LAST_NAME_ATT"],
  351. updateUserDetailsOnLogin: process.env["SHARELATEX_LDAP_UPDATE_USER_DETAILS_ON_LOGIN"] === 'true',
  352. placeholder: process.env["SHARELATEX_LDAP_PLACEHOLDER"],
  353. server: {
  354. url: process.env["SHARELATEX_LDAP_URL"],
  355. bindDn: process.env["SHARELATEX_LDAP_BIND_DN"],
  356. bindCredentials: process.env["SHARELATEX_LDAP_BIND_CREDENTIALS"],
  357. bindProperty: process.env["SHARELATEX_LDAP_BIND_PROPERTY"],
  358. searchBase: process.env["SHARELATEX_LDAP_SEARCH_BASE"],
  359. searchScope: process.env["SHARELATEX_LDAP_SEARCH_SCOPE"],
  360. searchFilter: process.env["SHARELATEX_LDAP_SEARCH_FILTER"],
  361. searchAttributes: (
  362. (_ldap_search_attribs = process.env["SHARELATEX_LDAP_SEARCH_ATTRIBUTES"]) ?
  363. (() => { try {
  364. return JSON.parse(_ldap_search_attribs);
  365. } catch (error3) {
  366. e = error3;
  367. return console.error("could not parse SHARELATEX_LDAP_SEARCH_ATTRIBUTES");
  368. } })()
  369. :
  370. undefined
  371. ),
  372. groupDnProperty: process.env["SHARELATEX_LDAP_GROUP_DN_PROPERTY"],
  373. groupSearchBase: process.env["SHARELATEX_LDAP_GROUP_SEARCH_BASE"],
  374. groupSearchScope: process.env["SHARELATEX_LDAP_GROUP_SEARCH_SCOPE"],
  375. groupSearchFilter: process.env["SHARELATEX_LDAP_GROUP_SEARCH_FILTER"],
  376. groupSearchAttributes: (
  377. (_ldap_group_search_attribs = process.env["SHARELATEX_LDAP_GROUP_SEARCH_ATTRIBUTES"]) ?
  378. (() => { try {
  379. return JSON.parse(_ldap_group_search_attribs);
  380. } catch (error4) {
  381. e = error4;
  382. return console.error("could not parse SHARELATEX_LDAP_GROUP_SEARCH_ATTRIBUTES");
  383. } })()
  384. :
  385. undefined
  386. ),
  387. cache: process.env["SHARELATEX_LDAP_CACHE"] === 'true',
  388. timeout: (
  389. (_ldap_timeout = process.env["SHARELATEX_LDAP_TIMEOUT"]) ?
  390. (() => { try {
  391. return parseIntOrFail(_ldap_timeout);
  392. } catch (error5) {
  393. e = error5;
  394. return console.error("Cannot parse SHARELATEX_LDAP_TIMEOUT");
  395. } })()
  396. :
  397. undefined
  398. ),
  399. connectTimeout: (
  400. (_ldap_connect_timeout = process.env["SHARELATEX_LDAP_CONNECT_TIMEOUT"]) ?
  401. (() => { try {
  402. return parseIntOrFail(_ldap_connect_timeout);
  403. } catch (error6) {
  404. e = error6;
  405. return console.error("Cannot parse SHARELATEX_LDAP_CONNECT_TIMEOUT");
  406. } })()
  407. :
  408. undefined
  409. )
  410. }
  411. };
  412. if (process.env["SHARELATEX_LDAP_TLS_OPTS_CA_PATH"]) {
  413. let ca, ca_paths;
  414. try {
  415. ca = JSON.parse(process.env["SHARELATEX_LDAP_TLS_OPTS_CA_PATH"]);
  416. } catch (error7) {
  417. e = error7;
  418. console.error("could not parse SHARELATEX_LDAP_TLS_OPTS_CA_PATH, invalid JSON");
  419. }
  420. if (typeof(ca) === 'string') {
  421. ca_paths = [ca];
  422. } else if ((typeof(ca) === 'object') && ((ca != null ? ca.length : undefined) != null)) {
  423. ca_paths = ca;
  424. } else {
  425. console.error("problem parsing SHARELATEX_LDAP_TLS_OPTS_CA_PATH");
  426. }
  427. settings.ldap.server.tlsOptions = {
  428. rejectUnauthorized: process.env["SHARELATEX_LDAP_TLS_OPTS_REJECT_UNAUTH"] === "true",
  429. ca:ca_paths // e.g.'/etc/ldap/ca_certs.pem'
  430. };
  431. }
  432. }
  433. if (process.env["SHARELATEX_SAML_ENTRYPOINT"]) {
  434. // NOTE: see https://github.com/node-saml/passport-saml/blob/master/README.md for docs of `server` options
  435. let _saml_additionalAuthorizeParams, _saml_additionalLogoutParams, _saml_additionalParams, _saml_expiration, _saml_skew;
  436. settings.externalAuth = true;
  437. settings.saml = {
  438. updateUserDetailsOnLogin: process.env["SHARELATEX_SAML_UPDATE_USER_DETAILS_ON_LOGIN"] === 'true',
  439. identityServiceName: process.env["SHARELATEX_SAML_IDENTITY_SERVICE_NAME"],
  440. emailField: process.env["SHARELATEX_SAML_EMAIL_FIELD"] || process.env["SHARELATEX_SAML_EMAIL_FIELD_NAME"],
  441. firstNameField: process.env["SHARELATEX_SAML_FIRST_NAME_FIELD"],
  442. lastNameField: process.env["SHARELATEX_SAML_LAST_NAME_FIELD"],
  443. server: {
  444. // strings
  445. entryPoint: process.env["SHARELATEX_SAML_ENTRYPOINT"],
  446. callbackUrl: process.env["SHARELATEX_SAML_CALLBACK_URL"],
  447. issuer: process.env["SHARELATEX_SAML_ISSUER"],
  448. decryptionPvk: process.env["SHARELATEX_SAML_DECRYPTION_PVK"],
  449. decryptionCert: process.env["SHARELATEX_SAML_DECRYPTION_CERT"],
  450. signatureAlgorithm: process.env["SHARELATEX_SAML_SIGNATURE_ALGORITHM"],
  451. identifierFormat: process.env["SHARELATEX_SAML_IDENTIFIER_FORMAT"],
  452. attributeConsumingServiceIndex: process.env["SHARELATEX_SAML_ATTRIBUTE_CONSUMING_SERVICE_INDEX"],
  453. authnContext: process.env["SHARELATEX_SAML_AUTHN_CONTEXT"],
  454. authnRequestBinding: process.env["SHARELATEX_SAML_AUTHN_REQUEST_BINDING"],
  455. validateInResponseTo: process.env["SHARELATEX_SAML_VALIDATE_IN_RESPONSE_TO"],
  456. cacheProvider: process.env["SHARELATEX_SAML_CACHE_PROVIDER"],
  457. logoutUrl: process.env["SHARELATEX_SAML_LOGOUT_URL"],
  458. logoutCallbackUrl: process.env["SHARELATEX_SAML_LOGOUT_CALLBACK_URL"],
  459. disableRequestedAuthnContext: process.env["SHARELATEX_SAML_DISABLE_REQUESTED_AUTHN_CONTEXT"] === 'true',
  460. forceAuthn: process.env["SHARELATEX_SAML_FORCE_AUTHN"] === 'true',
  461. skipRequestCompression: process.env["SHARELATEX_SAML_SKIP_REQUEST_COMPRESSION"] === 'true',
  462. acceptedClockSkewMs: (
  463. (_saml_skew = process.env["SHARELATEX_SAML_ACCEPTED_CLOCK_SKEW_MS"]) ?
  464. (() => { try {
  465. return parseIntOrFail(_saml_skew);
  466. } catch (error8) {
  467. e = error8;
  468. return console.error("Cannot parse SHARELATEX_SAML_ACCEPTED_CLOCK_SKEW_MS");
  469. } })()
  470. :
  471. undefined
  472. ),
  473. requestIdExpirationPeriodMs: (
  474. (_saml_expiration = process.env["SHARELATEX_SAML_REQUEST_ID_EXPIRATION_PERIOD_MS"]) ?
  475. (() => { try {
  476. return parseIntOrFail(_saml_expiration);
  477. } catch (error9) {
  478. e = error9;
  479. return console.error("Cannot parse SHARELATEX_SAML_REQUEST_ID_EXPIRATION_PERIOD_MS");
  480. } })()
  481. :
  482. undefined
  483. ),
  484. additionalParams: (
  485. (_saml_additionalParams = process.env["SHARELATEX_SAML_ADDITIONAL_PARAMS"]) ?
  486. (() => { try {
  487. return JSON.parse(_saml_additionalParams);
  488. } catch (error10) {
  489. e = error10;
  490. return console.error("Cannot parse SHARELATEX_SAML_ADDITIONAL_PARAMS");
  491. } })()
  492. :
  493. undefined
  494. ),
  495. additionalAuthorizeParams: (
  496. (_saml_additionalAuthorizeParams = process.env["SHARELATEX_SAML_ADDITIONAL_AUTHORIZE_PARAMS"]) ?
  497. (() => { try {
  498. return JSON.parse(_saml_additionalAuthorizeParams );
  499. } catch (error11) {
  500. e = error11;
  501. return console.error("Cannot parse SHARELATEX_SAML_ADDITIONAL_AUTHORIZE_PARAMS");
  502. } })()
  503. :
  504. undefined
  505. ),
  506. additionalLogoutParams: (
  507. (_saml_additionalLogoutParams = process.env["SHARELATEX_SAML_ADDITIONAL_LOGOUT_PARAMS"]) ?
  508. (() => { try {
  509. return JSON.parse(_saml_additionalLogoutParams );
  510. } catch (error12) {
  511. e = error12;
  512. return console.error("Cannot parse SHARELATEX_SAML_ADDITIONAL_LOGOUT_PARAMS");
  513. } })()
  514. :
  515. undefined
  516. )
  517. }
  518. };
  519. // SHARELATEX_SAML_CERT cannot be empty
  520. // https://github.com/node-saml/passport-saml/commit/f6b1c885c0717f1083c664345556b535f217c102
  521. if (process.env["SHARELATEX_SAML_CERT"]) {
  522. settings.saml.server.cert = process.env["SHARELATEX_SAML_CERT"];
  523. settings.saml.server.privateCert = process.env["SHARELATEX_SAML_PRIVATE_CERT"];
  524. }
  525. }
  526. // Compiler
  527. // --------
  528. if (process.env["SANDBOXED_COMPILES"] === "true") {
  529. settings.clsi = {
  530. dockerRunner: true,
  531. docker: {
  532. image: process.env["TEX_LIVE_DOCKER_IMAGE"],
  533. env: {
  534. HOME: "/tmp",
  535. 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"
  536. },
  537. user: "www-data"
  538. }
  539. };
  540. if ((settings.path == null)) {
  541. settings.path = {};
  542. }
  543. settings.path.synctexBaseDir = () => "/compile";
  544. if (process.env['SANDBOXED_COMPILES_SIBLING_CONTAINERS'] === 'true') {
  545. console.log("Using sibling containers for sandboxed compiles");
  546. if (process.env['SANDBOXED_COMPILES_HOST_DIR']) {
  547. settings.path.sandboxedCompilesHostDir = process.env['SANDBOXED_COMPILES_HOST_DIR'];
  548. } else {
  549. console.error('Sibling containers, but SANDBOXED_COMPILES_HOST_DIR not set');
  550. }
  551. }
  552. }
  553. // Templates
  554. // ---------
  555. if (process.env["SHARELATEX_TEMPLATES_USER_ID"]) {
  556. settings.templates = {
  557. mountPointUrl: "/templates",
  558. user_id: process.env["SHARELATEX_TEMPLATES_USER_ID"]
  559. };
  560. settings.templateLinks = parse(process.env["SHARELATEX_NEW_PROJECT_TEMPLATE_LINKS"]);
  561. }
  562. // /Learn
  563. // -------
  564. if (process.env["SHARELATEX_PROXY_LEARN"] != null) {
  565. settings.proxyLearn = parse(process.env["SHARELATEX_PROXY_LEARN"]);
  566. }
  567. // /References
  568. // -----------
  569. if (process.env["SHARELATEX_ELASTICSEARCH_URL"] != null) {
  570. settings.references.elasticsearch =
  571. {host: process.env["SHARELATEX_ELASTICSEARCH_URL"]};
  572. }
  573. // TeX Live Images
  574. // -----------
  575. if (process.env["ALL_TEX_LIVE_DOCKER_IMAGES"] != null) {
  576. allTexLiveDockerImages = process.env["ALL_TEX_LIVE_DOCKER_IMAGES"].split(',');
  577. }
  578. if (process.env["ALL_TEX_LIVE_DOCKER_IMAGE_NAMES"] != null) {
  579. allTexLiveDockerImageNames = process.env["ALL_TEX_LIVE_DOCKER_IMAGE_NAMES"].split(',');
  580. }
  581. if (allTexLiveDockerImages != null) {
  582. settings.allowedImageNames = [];
  583. for (let index = 0; index < allTexLiveDockerImages.length; index++) {
  584. const fullImageName = allTexLiveDockerImages[index];
  585. const imageName = Path.basename(fullImageName);
  586. const imageDesc = (allTexLiveDockerImageNames != null) ? allTexLiveDockerImageNames[index] : imageName;
  587. settings.allowedImageNames.push({ imageName, imageDesc });
  588. }
  589. }
  590. // With lots of incoming and outgoing HTTP connections to different services,
  591. // sometimes long running, it is a good idea to increase the default number
  592. // of sockets that Node will hold open.
  593. const http = require('http');
  594. http.globalAgent.maxSockets = 300;
  595. const https = require('https');
  596. https.globalAgent.maxSockets = 300;
  597. module.exports = settings;