From b541045263535a690a875d22f5001f677e3418d4 Mon Sep 17 00:00:00 2001 From: Thomas Parisot Date: Mon, 30 Sep 2024 20:00:31 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20d=C3=A9claration=20de=20la=20configurat?= =?UTF-8?q?ion=20applicative?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ça a le bénéfice de faire planter l'application au démarrage en cas de réglage absent. --- export/package-lock.json | 138 ++++++++++++++++++++-------------- export/package.json | 5 +- export/src/app.js | 4 +- export/src/config.js | 41 ++++++++++ export/src/export.js | 5 +- export/src/graphql.js | 5 +- graphql/app.js | 53 +++++++------ graphql/config.js | 146 ++++++++++++++++++++++++++++++++++++ graphql/helpers/metadata.js | 3 +- graphql/package-lock.json | 97 ++++++++++++++++++++++++ graphql/package.json | 5 +- 11 files changed, 410 insertions(+), 92 deletions(-) create mode 100644 export/src/config.js create mode 100644 graphql/config.js diff --git a/export/package-lock.json b/export/package-lock.json index 854102ec8..f89d06836 100644 --- a/export/package-lock.json +++ b/export/package-lock.json @@ -10,6 +10,8 @@ "license": "GPL-3.0", "dependencies": { "archiver": "5.3.2", + "convict": "^6.2.4", + "convict-format-with-validator": "^6.2.0", "cors": "^2.8.5", "express": "^4.16.4", "graphql": "^16.1.0", @@ -21,7 +23,6 @@ }, "devDependencies": { "dotenv": "^16.0.1", - "dotenv-cli": "^5.1.0", "jest": "^29.5.0" }, "engines": { @@ -1838,6 +1839,37 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "node_modules/convict": { + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/convict/-/convict-6.2.4.tgz", + "integrity": "sha512-qN60BAwdMVdofckX7AlohVJ2x9UvjTNoKVXCL2LxFk1l7757EJqf1nySdMkPQer0bt8kQ5lQiyZ9/2NvrFBuwQ==", + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "yargs-parser": "^20.2.7" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/convict-format-with-validator": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/convict-format-with-validator/-/convict-format-with-validator-6.2.0.tgz", + "integrity": "sha512-2LIL3yEZY27M13UHLIP4mGivusP9h2M+X4mYsRBLexwUp8+0sgVk2MgB2b2bnQwkn293lkbkxgdevzn0nZdyzQ==", + "dependencies": { + "validator": "^13.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/convict/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, "node_modules/cookie": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", @@ -2033,30 +2065,6 @@ "url": "https://github.com/motdotla/dotenv?sponsor=1" } }, - "node_modules/dotenv-cli": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-5.1.0.tgz", - "integrity": "sha512-NoEZAlKo9WVrG0b3i9mBxdD6INdDuGqdgR74t68t8084QcI077/1MnPerRW1odl+9uULhcdnQp2U0pYVppKHOA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "dotenv": "^16.0.0", - "dotenv-expand": "^8.0.1", - "minimist": "^1.2.5" - }, - "bin": { - "dotenv": "cli.js" - } - }, - "node_modules/dotenv-expand": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-8.0.3.tgz", - "integrity": "sha512-SErOMvge0ZUyWd5B0NXMQlDkN+8r+HhVUsxgOO7IoPDOdDRD2JjExpN6y3KnFR66jsJMwSn1pqIivhU5rcJiNg==", - "dev": true, - "engines": { - "node": ">=12" - } - }, "node_modules/duplexify": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", @@ -3593,6 +3601,11 @@ "node": ">=8" } }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, "node_modules/lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", @@ -3774,15 +3787,6 @@ "node": "*" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -4861,6 +4865,14 @@ "node": ">=10.12.0" } }, + "node_modules/validator": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -6424,6 +6436,30 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "convict": { + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/convict/-/convict-6.2.4.tgz", + "integrity": "sha512-qN60BAwdMVdofckX7AlohVJ2x9UvjTNoKVXCL2LxFk1l7757EJqf1nySdMkPQer0bt8kQ5lQiyZ9/2NvrFBuwQ==", + "requires": { + "lodash.clonedeep": "^4.5.0", + "yargs-parser": "^20.2.7" + }, + "dependencies": { + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + } + } + }, + "convict-format-with-validator": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/convict-format-with-validator/-/convict-format-with-validator-6.2.0.tgz", + "integrity": "sha512-2LIL3yEZY27M13UHLIP4mGivusP9h2M+X4mYsRBLexwUp8+0sgVk2MgB2b2bnQwkn293lkbkxgdevzn0nZdyzQ==", + "requires": { + "validator": "^13.6.0" + } + }, "cookie": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", @@ -6560,24 +6596,6 @@ "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", "dev": true }, - "dotenv-cli": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-5.1.0.tgz", - "integrity": "sha512-NoEZAlKo9WVrG0b3i9mBxdD6INdDuGqdgR74t68t8084QcI077/1MnPerRW1odl+9uULhcdnQp2U0pYVppKHOA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "dotenv": "^16.0.0", - "dotenv-expand": "^8.0.1", - "minimist": "^1.2.5" - } - }, - "dotenv-expand": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-8.0.3.tgz", - "integrity": "sha512-SErOMvge0ZUyWd5B0NXMQlDkN+8r+HhVUsxgOO7IoPDOdDRD2JjExpN6y3KnFR66jsJMwSn1pqIivhU5rcJiNg==", - "dev": true - }, "duplexify": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", @@ -7729,6 +7747,11 @@ "p-locate": "^4.1.0" } }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, "lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", @@ -7870,12 +7893,6 @@ "brace-expansion": "^1.1.7" } }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -8675,6 +8692,11 @@ "convert-source-map": "^2.0.0" } }, + "validator": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/export/package.json b/export/package.json index c6c8b4f2d..f9e3014ad 100644 --- a/export/package.json +++ b/export/package.json @@ -11,7 +11,7 @@ "scripts": { "test": "jest", "start": "node src/app.js", - "dev": "npx dotenv -e ../stylo.env npm run start", + "dev": "node src/app.js", "prod": "NODE_ENV=production node --heapsnapshot-signal=SIGUSR2 src/app.js" }, "repository": { @@ -33,6 +33,8 @@ "homepage": "https://github.com/EcrituresNumeriques/stylo#readme", "dependencies": { "archiver": "5.3.2", + "convict": "^6.2.4", + "convict-format-with-validator": "^6.2.0", "cors": "^2.8.5", "express": "^4.16.4", "graphql": "^16.1.0", @@ -44,7 +46,6 @@ }, "devDependencies": { "dotenv": "^16.0.1", - "dotenv-cli": "^5.1.0", "jest": "^29.5.0" }, "husky": { diff --git a/export/src/app.js b/export/src/app.js index f0498d7cf..574c37f8d 100644 --- a/export/src/app.js +++ b/export/src/app.js @@ -4,6 +4,8 @@ const { logger } = require('./logger') const pino = require('pino-http')({ logger }) +const config = require('./config.js') +config.validate({ allowed: 'strict' }) const { exportArticleHtml, @@ -29,7 +31,7 @@ app.use(cors({ origin: '*' })) -const listenPort = process.env.PORT || 3060 +const listenPort = config.get('port') const asyncExportVersionHtml = asyncHandler(exportVersionHtml) const asyncExportArticleHtml = asyncHandler(exportArticleHtml) diff --git a/export/src/config.js b/export/src/config.js new file mode 100644 index 000000000..b46cba61d --- /dev/null +++ b/export/src/config.js @@ -0,0 +1,41 @@ +const convict = require('convict') +require('dotenv').config({ path: '../../stylo.env' }) + +convict.addFormat(require('convict-format-with-validator').url) + +/** + * @type {convict.Config<{ + * + * }>} + */ +module.exports = convict({ + port: { + default: 3060, + format: 'port', + env: 'PORT' + }, + api: { + urlEndpoint: { + default: 'http://localhost:3030/graphql', + format: 'url', + env: 'SNOWPACK_PUBLIC_GRAPHQL_ENDPOINT' + }, + passthroughToken: { + format: 'string', + sensitive: true, + env: 'SE_GRAPHQL_TOKEN' + } + }, + export: { + // legacy option + canonicalBaseUrl: { + format: 'url', + env: 'EXPORT_CANONICAL_BASE_URL' + }, + urlEndpoint: { + default: 'http://127.0.0.1:3080', + format: 'url', + env: 'SNOWPACK_PUBLIC_PANDOC_EXPORT_ENDPOINT' + } + } +}) diff --git a/export/src/export.js b/export/src/export.js index fc317f2f1..f0e462731 100644 --- a/export/src/export.js +++ b/export/src/export.js @@ -1,3 +1,4 @@ +const config = require('./config.js') const archiver = require('archiver') const { logger } = require('./logger') @@ -5,8 +6,8 @@ const { FindByIdNotFoundError } = require('./helpers/errors') const { normalize } = require('./helpers/filename') const { getArticleById, getVersionById, getCorpusById } = require('./graphql') -const canonicalBaseUrl = process.env.EXPORT_CANONICAL_BASE_URL -const exportEndpoint = process.env.SNOWPACK_PUBLIC_PANDOC_EXPORT_ENDPOINT || 'http://127.0.0.1:3080' +const canonicalBaseUrl = config.get('export.canonicalBaseUrl') +const exportEndpoint = config.get('export.urlEndpoint') const exportZip = async ({ bib, yaml, md, id, versionId, title }, res, _) => { const filename = `${normalize(title)}.zip` diff --git a/export/src/graphql.js b/export/src/graphql.js index 26607cfb0..7747a5748 100644 --- a/export/src/graphql.js +++ b/export/src/graphql.js @@ -17,8 +17,9 @@ function getGraphQLClient () { if (graphQLClient) { return graphQLClient } - const graphqlEndpoint = process.env.SNOWPACK_PUBLIC_GRAPHQL_ENDPOINT || 'http://localhost:3030/graphql' - const passthroughToken = process.env.SE_GRAPHQL_TOKEN + const graphqlEndpoint = config.get('api.urlEndpoint') + const passthroughToken = config.get('api.passthroughToken') + graphQLClient = new GraphQLClient(graphqlEndpoint, { headers: { authorization: `Bearer ${passthroughToken}`, diff --git a/graphql/app.js b/graphql/app.js index 7cd560e79..47388a967 100644 --- a/graphql/app.js +++ b/graphql/app.js @@ -1,6 +1,9 @@ const pkg = require('./package.json') const ospath = require('node:path') const process = require('node:process') +const config = require('./config.js') +config.validate({ allowed: 'strict' }) + process.env.YPERSISTENCE = ospath.join(__dirname, 'ydata') const express = require('express') @@ -35,35 +38,35 @@ const wss = new WebSocket.Server({ noServer: true }) const app = express() -const mongoServer = process.env.MONGO_SERVER -const mongoServerPort = process.env.MONGO_SERVER_PORT -const mongoServerDB = process.env.MONGO_SERVER_DB - -const listenPort = process.env.PORT || 3030 -const origin = process.env.ALLOW_CORS_FRONTEND -const jwtSecret = process.env.JWT_SECRET_SESSION_COOKIE -const sessionSecret = process.env.SESSION_SECRET -const oicName = process.env.OPENID_CONNECT_NAME -const oicIssuer = process.env.OPENID_CONNECT_ISSUER -const oicAuthUrl = process.env.OPENID_CONNECT_AUTH_URL -const oicTokenUrl = process.env.OPENID_CONNECT_TOKEN_URL -const oicUserInfoUrl = process.env.OPENID_CONNECT_USER_INFO_URL -const oicCallbackUrl = process.env.OPENID_CONNECT_CALLBACK_URL -const oicClientId = process.env.OPENID_CONNECT_CLIENT_ID -const oicClientSecret = process.env.OPENID_CONNECT_CLIENT_SECRET -const oicScope = process.env.OPENID_CONNECT_SCOPE || 'profile email' - -const zoteroAuthClientKey = process.env.ZOTERO_AUTH_CLIENT_KEY -const zoteroAuthClientSecret = process.env.ZOTERO_AUTH_CLIENT_SECRET -const zoteroAuthCallbackUrl = process.env.ZOTERO_AUTH_CALLBACK_URL -const zoteroRequestTokenEndpoint = process.env.ZOTERO_REQUEST_TOKEN_ENDPOINT || 'https://www.zotero.org/oauth/request' -const zoteroAccessTokenEndpoint = process.env.ZOTERO_ACCESS_TOKEN_ENDPOINT || 'https://www.zotero.org/oauth/access' -const zoteroAuthorizeEndpoint = process.env.ZOTERO_AUTHORIZE_ENDPOINT || 'https://www.zotero.org/oauth/authorize' +const mongoServer = config.get('mongo.host') +const mongoServerPort = config.get('mongo.port') +const mongoServerDB = config.get('mongo.db') + +const listenPort = config.get('port') +const origin = config.get('security.cors.origin') +const jwtSecret = config.get('security.jwt.secret') +const sessionSecret = config.get('security.session.secret') +const oicName = config.get('oauthProvider.name') +const oicIssuer = config.get('oauthProvider.issuer') +const oicAuthUrl = config.get('oauthProvider.auth.url') +const oicTokenUrl = config.get('oauthProvider.auth.tokenUrl') +const oicUserInfoUrl = config.get('oauthProvider.auth.userInfo') +const oicCallbackUrl = config.get('oauthProvider.callbackUrl') +const oicClientId = config.get('oauthProvider.client.id') +const oicClientSecret = config.get('oauthProvider.client.secret') +const oicScope = config.get('oauthProvider.scope') + +const zoteroAuthClientKey = config.get('zotero.auth.clientKey') +const zoteroAuthClientSecret = config.get('zotero.auth.clientSecret') +const zoteroAuthCallbackUrl = config.get('zotero.auth.callbackUrl') +const zoteroRequestTokenEndpoint = config.get('zotero.requestToken') +const zoteroAccessTokenEndpoint = config.get('zotero.accessPoint') +const zoteroAuthorizeEndpoint = config.get('zotero.authorize') const zoteroAuthScope = ['library_access=1', 'all_groups=read'] //A Secure cookie is only sent to the server with an encrypted request over the HTTPS protocol. // Note that insecure sites (http:) can't set cookies with the Secure directive. -const secureCookie = process.env.HTTPS === 'true' +const secureCookie = config.get('securedCookie') // When we have multiple origins (for instance, using deploy previews on different domains) then cookies `sameSite` attribute is permissive (using 'none' value). // When we have a single origin (most likely when running in a production environment) then we are using a secure/strict value for cookies `sameSite` attribute ('strict'). // When using 'strict' value, cookies will not be sent along with requests initiated by third-party websites. diff --git a/graphql/config.js b/graphql/config.js new file mode 100644 index 000000000..b75521a97 --- /dev/null +++ b/graphql/config.js @@ -0,0 +1,146 @@ +const convict = require('convict') +require('dotenv').config({ path: '../stylo.env' }) + +convict.addFormat(require('convict-format-with-validator').url) + +/** + * @type {convict.Config<{ + * + * }>} + */ +module.exports = convict({ + export: { + baseUrl: { + format: 'url', + env: 'EXPORT_CANONICAL_BASE_URL' + }, + urlEndpoint: { + default: 'http://127.0.0.1:3080', + format: 'url', + env: 'SNOWPACK_PUBLIC_PANDOC_EXPORT_ENDPOINT' + } + }, + mongo: { + db: { + format: String, + env: 'MONGO_SERVER_DB' + }, + host: { + format: 'ip', + env: 'MONGO_SERVER' + }, + port: { + format: 'port', + env: 'MONGO_SERVER_PORT' + } + }, + oauthProvider: { + name: { + format: String, + env: 'OPENID_CONNECT_NAME' + }, + issuer: { + format: 'url', + env: 'OPENID_CONNECT_ISSUER' + }, + callbackUrl: { + format: 'url', + env: 'OPENID_CONNECT_CALLBACK_URL' + }, + client: { + id: { + format: String, + sensitive: true, + env: 'OPENID_CONNECT_CLIENT_ID' + }, + secret: { + format: String, + sensitive: true, + env: 'OPENID_CONNECT_CLIENT_SECRET' + } + }, + scope: { + default: 'profile email', + env: 'OPENID_CONNECT_SCOPE' + }, + auth: { + tokenUrl: { + format: 'url', + env: 'OPENID_CONNECT_TOKEN_URL' + }, + userInfo: { + format: 'url', + env: 'OPENID_CONNECT_USER_INFO_URL' + }, + url: { + format: 'url', + env: 'OPENID_CONNECT_AUTH_URL' + } + } + }, + port: { + default: 3030, + format: 'port', + env: 'PORT' + }, + securedCookie: { + format: Boolean, + env: 'HTTPS' + }, + security: { + cors: { + origin: { + // url1 url2 + default: 'http://127.0.0.1:3000 http://127.0.0.1:3030', + env: 'ALLOW_CORS_FRONTEND' + } + }, + jwt: { + secret: { + format: String, + sensitive: true, + env: 'JWT_SECRET_SESSION_COOKIE' + } + }, + session: { + secret: { + format: String, + sensitive: true, + env: 'SESSION_SECRET' + } + } + }, + zotero: { + accessPoint: { + default: 'https://www.zotero.org/oauth/access', + format: 'url', + env: 'ZOTERO_ACCESS_TOKEN_ENDPOINT' + }, + authorize: { + default: 'https://www.zotero.org/oauth/authorize', + format: 'url', + env: 'ZOTERO_AUTHORIZE_ENDPOINT' + }, + requestToken: { + default: 'https://www.zotero.org/oauth/request', + format: 'url', + env: 'ZOTERO_REQUEST_TOKEN_ENDPOINT' + }, + auth: { + callbackUrl: { + format: 'url', + env: 'ZOTERO_AUTH_CALLBACK_URL' + }, + clientKey: { + format: String, + sensitive: true, + env: 'ZOTERO_AUTH_CLIENT_KEY' + }, + clientSecret: { + format: String, + sensitive: true, + env: 'ZOTERO_AUTH_CLIENT_SECRET' + } + } + } +}) diff --git a/graphql/helpers/metadata.js b/graphql/helpers/metadata.js index 94195788e..cbd2deb4d 100644 --- a/graphql/helpers/metadata.js +++ b/graphql/helpers/metadata.js @@ -2,8 +2,9 @@ const YAML = require('js-yaml') const { YAMLException } = require('js-yaml') const removeMd = require('remove-markdown') const { logger } = require('../logger') +const config = require('../config.js') -const canonicalBaseUrl = process.env.EXPORT_CANONICAL_BASE_URL +const canonicalBaseUrl = config.get('export.baseUrl') const FORMATTED_FIELD_RE = /_f$/ /** diff --git a/graphql/package-lock.json b/graphql/package-lock.json index a23ae4256..e52301883 100644 --- a/graphql/package-lock.json +++ b/graphql/package-lock.json @@ -16,10 +16,13 @@ "body-parser": "^1.18.3", "colornames": "^1.1.1", "connect-mongo": "^3.2.0", + "convict": "^6.2.4", + "convict-format-with-validator": "^6.2.0", "cors": "^2.8.5", "css-tree": "^2.3.1", "dataloader": "^2.2.2", "dompurify": "^2.4.3", + "dotenv": "^16.4.5", "express": "^4.16.4", "express-session": "^1.17.1", "graphql-http": "^1.9.0", @@ -3848,6 +3851,37 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "node_modules/convict": { + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/convict/-/convict-6.2.4.tgz", + "integrity": "sha512-qN60BAwdMVdofckX7AlohVJ2x9UvjTNoKVXCL2LxFk1l7757EJqf1nySdMkPQer0bt8kQ5lQiyZ9/2NvrFBuwQ==", + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "yargs-parser": "^20.2.7" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/convict-format-with-validator": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/convict-format-with-validator/-/convict-format-with-validator-6.2.0.tgz", + "integrity": "sha512-2LIL3yEZY27M13UHLIP4mGivusP9h2M+X4mYsRBLexwUp8+0sgVk2MgB2b2bnQwkn293lkbkxgdevzn0nZdyzQ==", + "dependencies": { + "validator": "^13.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/convict/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, "node_modules/cookie": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", @@ -4113,6 +4147,17 @@ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.7.tgz", "integrity": "sha512-kxxKlPEDa6Nc5WJi+qRgPbOAbgTpSULL+vI3NUXsZMlkJxTqYI9wg5ZTay2sFrdZRWHPWNi+EdAhcJf81WtoMQ==" }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/duplexify": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", @@ -6576,6 +6621,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -8832,6 +8882,14 @@ "node": ">=10.12.0" } }, + "node_modules/validator": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/value-or-promise": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.12.tgz", @@ -12183,6 +12241,30 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "convict": { + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/convict/-/convict-6.2.4.tgz", + "integrity": "sha512-qN60BAwdMVdofckX7AlohVJ2x9UvjTNoKVXCL2LxFk1l7757EJqf1nySdMkPQer0bt8kQ5lQiyZ9/2NvrFBuwQ==", + "requires": { + "lodash.clonedeep": "^4.5.0", + "yargs-parser": "^20.2.7" + }, + "dependencies": { + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + } + } + }, + "convict-format-with-validator": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/convict-format-with-validator/-/convict-format-with-validator-6.2.0.tgz", + "integrity": "sha512-2LIL3yEZY27M13UHLIP4mGivusP9h2M+X4mYsRBLexwUp8+0sgVk2MgB2b2bnQwkn293lkbkxgdevzn0nZdyzQ==", + "requires": { + "validator": "^13.6.0" + } + }, "cookie": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", @@ -12380,6 +12462,11 @@ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.7.tgz", "integrity": "sha512-kxxKlPEDa6Nc5WJi+qRgPbOAbgTpSULL+vI3NUXsZMlkJxTqYI9wg5ZTay2sFrdZRWHPWNi+EdAhcJf81WtoMQ==" }, + "dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==" + }, "duplexify": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", @@ -14205,6 +14292,11 @@ "p-locate": "^5.0.0" } }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -15895,6 +15987,11 @@ "convert-source-map": "^2.0.0" } }, + "validator": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==" + }, "value-or-promise": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.12.tgz", diff --git a/graphql/package.json b/graphql/package.json index 94e5fcadc..9730fa7a4 100644 --- a/graphql/package.json +++ b/graphql/package.json @@ -25,10 +25,13 @@ "body-parser": "^1.18.3", "colornames": "^1.1.1", "connect-mongo": "^3.2.0", + "convict": "^6.2.4", + "convict-format-with-validator": "^6.2.0", "cors": "^2.8.5", "css-tree": "^2.3.1", "dataloader": "^2.2.2", "dompurify": "^2.4.3", + "dotenv": "^16.4.5", "express": "^4.16.4", "express-session": "^1.17.1", "graphql-http": "^1.9.0", @@ -58,4 +61,4 @@ "volta": { "node": "18.18.2" } -} \ No newline at end of file +}