From 13c8b85c787f256abba2f67355121ba12dddb961 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Thu, 14 Jan 2021 22:13:21 +0100 Subject: [PATCH 1/4] refactor backend config --- backend/src/config/index.js | 171 +++++++++--------- backend/src/db/clean.js | 3 +- .../src/middleware/email/emailMiddleware.js | 2 +- backend/src/middleware/sentryMiddleware.js | 12 +- backend/src/schema/resolvers/images/images.js | 4 +- 5 files changed, 94 insertions(+), 98 deletions(-) diff --git a/backend/src/config/index.js b/backend/src/config/index.js index 0370d4552..d03fb7e00 100644 --- a/backend/src/config/index.js +++ b/backend/src/config/index.js @@ -2,111 +2,106 @@ import dotenv from 'dotenv' import links from './links.js' import metadata from './metadata.js' +// Load env file if (require.resolve) { - // are we in a nodejs environment? try { dotenv.config({ path: require.resolve('../../.env') }) } catch (error) { - if (error.code !== 'MODULE_NOT_FOUND') throw error - console.log('WARN: No `.env` file found in `/app` (docker) or `/backend` (no docker)') // eslint-disable-line no-console + if (error.code === 'MODULE_NOT_FOUND') { + console.log('WARN: No `.env` file found in `/app` (docker) or `/backend` (no docker)') // eslint-disable-line no-console + } else { + throw error + } } } -// eslint-disable-next-line no-undef -const env = typeof Cypress !== 'undefined' ? Cypress.env() : process.env +// Use Cypress env or process.env +const env = typeof Cypress !== 'undefined' ? Cypress.env() : process.env // eslint-disable-line no-undef -const { - MAPBOX_TOKEN, - JWT_SECRET, - PRIVATE_KEY_PASSPHRASE, - SMTP_IGNORE_TLS = true, - SMTP_HOST, - SMTP_PORT, - SMTP_USERNAME, - SMTP_PASSWORD, - SENTRY_DSN_BACKEND, - COMMIT, - AWS_ACCESS_KEY_ID, - AWS_SECRET_ACCESS_KEY, - AWS_ENDPOINT, - AWS_REGION, - AWS_BUCKET, - NEO4J_URI = 'bolt://localhost:7687', - NEO4J_USERNAME = 'neo4j', - NEO4J_PASSWORD = 'neo4j', - CLIENT_URI = 'http://localhost:3000', - GRAPHQL_URI = 'http://localhost:4000', - REDIS_DOMAIN, - REDIS_PORT, - REDIS_PASSWORD, - EMAIL_DEFAULT_SENDER, -} = env - -export const requiredConfigs = { - MAPBOX_TOKEN, - JWT_SECRET, - PRIVATE_KEY_PASSPHRASE, +const environment = { + NODE_ENV: env.NODE_ENV || process.NODE_ENV, + DEBUG: env.NODE_ENV !== 'production' && env.DEBUG, + TEST: env.NODE_ENV === 'test', + PRODUCTION: env.NODE_ENV === 'production', + DISABLED_MIDDLEWARES: (env.NODE_ENV !== 'production' && env.DISABLED_MIDDLEWARES) || false, } +const required = { + MAPBOX_TOKEN: env.MAPBOX_TOKEN, + JWT_SECRET: env.JWT_SECRET, + PRIVATE_KEY_PASSPHRASE: env.PRIVATE_KEY_PASSPHRASE, +} + +const server = { + CLIENT_URI: env.CLIENT_URI || 'http://localhost:3000', + GRAPHQL_URI: env.GRAPHQL_URI || 'http://localhost:4000', +} + +const smtp = { + SMTP_HOST: env.SMTP_HOST, + SMTP_PORT: env.SMTP_PORT, + SMTP_IGNORE_TLS: env.SMTP_IGNORE_TLS || true, + SMTP_USERNAME: env.SMTP_USERNAME, + SMTP_PASSWORD: env.SMTP_PASSWORD, +} + +const neo4j = { + NEO4J_URI: env.NEO4J_URI || 'bolt://localhost:7687', + NEO4J_USERNAME: env.NEO4J_USERNAME || 'neo4j', + NEO4J_PASSWORD: env.NEO4J_PASSWORD || 'neo4j', +} + +const sentry = { + SENTRY_DSN_BACKEND: env.SENTRY_DSN_BACKEND, + COMMIT: env.COMMIT, +} + +const redis = { + REDIS_DOMAIN: env.REDIS_DOMAIN, + REDIS_PORT: env.REDIS_PORT, + REDIS_PASSWORD: env.REDIS_PASSWORD, +} + +const s3 = { + AWS_ACCESS_KEY_ID: env.AWS_ACCESS_KEY_ID, + AWS_SECRET_ACCESS_KEY: env.AWS_SECRET_ACCESS_KEY, + AWS_ENDPOINT: env.AWS_ENDPOINT, + AWS_REGION: env.AWS_REGION, + AWS_BUCKET: env.AWS_BUCKET, + S3_CONFIGURED: + env.AWS_ACCESS_KEY_ID && + env.AWS_SECRET_ACCESS_KEY && + env.AWS_ENDPOINT && + env.AWS_REGION && + env.AWS_BUCKET, +} + +const options = { + EMAIL_DEFAULT_SENDER: env.EMAIL_DEFAULT_SENDER, + SUPPORT_URL: links.SUPPORT, + APPLICATION_NAME: metadata.APPLICATION_NAME, + ORGANIZATION_URL: links.ORGANIZATION, + PUBLIC_REGISTRATION: env.PUBLIC_REGISTRATION === 'true', +} + +// Check if all required configs are present if (require.resolve) { // are we in a nodejs environment? - Object.entries(requiredConfigs).map((entry) => { + Object.entries(required).map((entry) => { if (!entry[1]) { throw new Error(`ERROR: "${entry[0]}" env variable is missing.`) } }) } -export const smtpConfigs = { - SMTP_HOST, - SMTP_PORT, - SMTP_IGNORE_TLS, - SMTP_USERNAME, - SMTP_PASSWORD, -} -export const neo4jConfigs = { NEO4J_URI, NEO4J_USERNAME, NEO4J_PASSWORD } -export const serverConfigs = { - CLIENT_URI, - GRAPHQL_URI, - PUBLIC_REGISTRATION: process.env.PUBLIC_REGISTRATION === 'true', -} - -export const developmentConfigs = { - DEBUG: process.env.NODE_ENV !== 'production' && process.env.DEBUG, - DISABLED_MIDDLEWARES: - (process.env.NODE_ENV !== 'production' && process.env.DISABLED_MIDDLEWARES) || '', -} - -export const sentryConfigs = { SENTRY_DSN_BACKEND, COMMIT } -export const redisConfigs = { REDIS_DOMAIN, REDIS_PORT, REDIS_PASSWORD } - -const S3_CONFIGURED = - AWS_ACCESS_KEY_ID && AWS_SECRET_ACCESS_KEY && AWS_ENDPOINT && AWS_REGION && AWS_BUCKET - -export const s3Configs = { - AWS_ACCESS_KEY_ID, - AWS_SECRET_ACCESS_KEY, - AWS_ENDPOINT, - AWS_REGION, - AWS_BUCKET, - S3_CONFIGURED, -} - -export const customConfigs = { - EMAIL_DEFAULT_SENDER, - SUPPORT_URL: links.SUPPORT, - APPLICATION_NAME: metadata.APPLICATION_NAME, - ORGANIZATION_URL: links.ORGANIZATION, -} - export default { - ...requiredConfigs, - ...smtpConfigs, - ...neo4jConfigs, - ...serverConfigs, - ...developmentConfigs, - ...sentryConfigs, - ...redisConfigs, - ...s3Configs, - ...customConfigs, + ...environment, + ...server, + ...required, + ...smtp, + ...neo4j, + ...sentry, + ...redis, + ...s3, + ...options, } diff --git a/backend/src/db/clean.js b/backend/src/db/clean.js index 97a21a055..db8e8aad6 100644 --- a/backend/src/db/clean.js +++ b/backend/src/db/clean.js @@ -1,6 +1,7 @@ import { cleanDatabase } from '../db/factories' +import CONFIG from '../config' -if (process.env.NODE_ENV === 'production') { +if (CONFIG.PRODUCTION) { throw new Error(`You cannot clean the database in production environment!`) } diff --git a/backend/src/middleware/email/emailMiddleware.js b/backend/src/middleware/email/emailMiddleware.js index a69530582..4dbb3ad03 100644 --- a/backend/src/middleware/email/emailMiddleware.js +++ b/backend/src/middleware/email/emailMiddleware.js @@ -13,7 +13,7 @@ const hasAuthData = CONFIG.SMTP_USERNAME && CONFIG.SMTP_PASSWORD let sendMail = () => {} if (!hasEmailConfig) { - if (process.env.NODE_ENV !== 'test') { + if (!CONFIG.TEST) { // eslint-disable-next-line no-console console.log('Warning: Email middleware will not try to send mails.') } diff --git a/backend/src/middleware/sentryMiddleware.js b/backend/src/middleware/sentryMiddleware.js index da8ef32d0..8891b8677 100644 --- a/backend/src/middleware/sentryMiddleware.js +++ b/backend/src/middleware/sentryMiddleware.js @@ -1,16 +1,16 @@ import { sentry } from 'graphql-middleware-sentry' -import { sentryConfigs } from '../config' +import CONFIG from '../config' let sentryMiddleware = (resolve, root, args, context, resolveInfo) => resolve(root, args, context, resolveInfo) -if (sentryConfigs.SENTRY_DSN_BACKEND) { +if (CONFIG.SENTRY_DSN_BACKEND) { sentryMiddleware = sentry({ forwardErrors: true, config: { - dsn: sentryConfigs.SENTRY_DSN_BACKEND, - release: sentryConfigs.COMMIT, - environment: process.env.NODE_ENV, + dsn: CONFIG.SENTRY_DSN_BACKEND, + release: CONFIG.COMMIT, + environment: CONFIG.NODE_ENV, }, withScope: (scope, error, context) => { scope.setUser({ @@ -23,7 +23,7 @@ if (sentryConfigs.SENTRY_DSN_BACKEND) { }) } else { // eslint-disable-next-line no-console - if (process.env.NODE_ENV !== 'test') console.log('Warning: Sentry middleware inactive.') + if (!CONFIG.TEST) console.log('Warning: Sentry middleware inactive.') } export default sentryMiddleware diff --git a/backend/src/schema/resolvers/images/images.js b/backend/src/schema/resolvers/images/images.js index 18a3569b6..9b57579c4 100644 --- a/backend/src/schema/resolvers/images/images.js +++ b/backend/src/schema/resolvers/images/images.js @@ -5,10 +5,10 @@ import slug from 'slug' import { existsSync, unlinkSync, createWriteStream } from 'fs' import { UserInputError } from 'apollo-server' import { getDriver } from '../../../db/neo4j' -import { s3Configs } from '../../../config' +import CONFIG from '../../../config' // const widths = [34, 160, 320, 640, 1024] -const { AWS_ENDPOINT: endpoint, AWS_REGION: region, AWS_BUCKET: Bucket, S3_CONFIGURED } = s3Configs +const { AWS_ENDPOINT: endpoint, AWS_REGION: region, AWS_BUCKET: Bucket, S3_CONFIGURED } = CONFIG export async function deleteImage(resource, relationshipType, opts = {}) { sanitizeRelationshipType(relationshipType) From 7d6643104983dbe87aa3030b2dc86b0904b2a6ad Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Thu, 14 Jan 2021 22:14:07 +0100 Subject: [PATCH 2/4] introduced config file for webapp --- webapp/config/index.js | 46 +++++++++++++++++++++++++++ webapp/nuxt.config.js | 70 +++++++++++++----------------------------- 2 files changed, 68 insertions(+), 48 deletions(-) create mode 100644 webapp/config/index.js diff --git a/webapp/config/index.js b/webapp/config/index.js new file mode 100644 index 000000000..68c220533 --- /dev/null +++ b/webapp/config/index.js @@ -0,0 +1,46 @@ +// ATTENTION: DO NOT PUT ANY SECRETS IN HERE (or the .env) + +import dotenv from 'dotenv' +dotenv.config() // we want to synchronize @nuxt-dotenv and nuxt-env + +// Load Package Details for some default values +const pkg = require('../package') + +const environment = { + NODE_ENV: process.env.NODE_ENV, + DEBUG: process.env.NODE_ENV !== 'production' || false, + PRODUCTION: process.env.NODE_ENV === 'production' || false, + NUXT_BUILD: process.env.NUXT_BUILD || '.nuxt', + RELEASE: process.env.release, + STYLEGUIDE_DEV: process.env.STYLEGUIDE_DEV, +} + +const server = { + GRAPHQL_URI: process.env.GRAPHQL_URI || 'http://localhost:4000', + BACKEND_TOKEN: process.env.BACKEND_TOKEN || 'NULL', +} + +const sentry = { + SENTRY_DSN_WEBAPP: process.env.SENTRY_DSN_WEBAPP, + COMMIT: process.env.COMMIT, +} + +const options = { + VERSION: process.env.VERSION || pkg.version, + DESCRIPTION: process.env.DESCRIPTION || pkg.description, +} + +const CONFIG = { + ...environment, + ...server, + ...sentry, + ...options, +} + +// override process.env with the values here since they contain default values +process.env = { + ...process.env, + ...CONFIG, +} + +export default CONFIG diff --git a/webapp/nuxt.config.js b/webapp/nuxt.config.js index d388d9fc1..d772eb339 100644 --- a/webapp/nuxt.config.js +++ b/webapp/nuxt.config.js @@ -1,41 +1,25 @@ import path from 'path' -import dotenv from 'dotenv' import manifest from './constants/manifest.js' import metadata from './constants/metadata.js' -dotenv.config() // we want to synchronize @nuxt-dotenv and nuxt-env - -const pkg = require('./package') -export const envWhitelist = [ - 'NODE_ENV', - 'MAPBOX_TOKEN', - 'PUBLIC_REGISTRATION', - 'WEBSOCKETS_URI', - 'GRAPHQL_URI', -] -const dev = process.env.NODE_ENV !== 'production' +const CONFIG = require('./config') // we need to use require since this is only evaluated at compile time. const styleguidePath = '../styleguide' -const styleguideStyles = process.env.STYLEGUIDE_DEV +const styleguideStyles = CONFIG.STYLEGUIDE_DEV ? [ `${styleguidePath}/src/system/styles/main.scss`, `${styleguidePath}/src/system/styles/shared.scss`, ] : '@human-connection/styleguide/dist/shared.scss' -const buildDir = process.env.NUXT_BUILD || '.nuxt' - -const additionalSentryConfig = {} -if (process.env.COMMIT) additionalSentryConfig.release = process.env.COMMIT - export default { - buildDir, + buildDir: CONFIG.NUXT_BUILD, mode: 'universal', - dev: dev, - debug: dev ? 'nuxt:*,app' : null, + dev: CONFIG.DEBUG, + debug: CONFIG.DEBUG ? 'nuxt:*,app' : null, - modern: !dev ? 'server' : false, + modern: CONFIG.PRODUCTION ? 'server' : false, pageTransition: { name: 'slide-up', @@ -43,7 +27,7 @@ export default { }, env: { - release: pkg.version, + release: CONFIG.VERSION, // pages which do NOT require a login publicPages: [ 'login', @@ -81,7 +65,7 @@ export default { { hid: 'description', name: 'description', - content: pkg.description, + content: CONFIG.DESCRIPTION, }, ], link: [ @@ -120,7 +104,7 @@ export default { plugins: [ { src: '~/plugins/base-components.js', ssr: true }, { - src: `~/plugins/styleguide${process.env.STYLEGUIDE_DEV ? '-dev' : ''}.js`, + src: `~/plugins/styleguide${CONFIG.STYLEGUIDE_DEV ? '-dev' : ''}.js`, ssr: true, }, { src: '~/plugins/i18n.js', ssr: true }, @@ -143,18 +127,8 @@ export default { ** Nuxt.js modules */ modules: [ - [ - '@nuxtjs/dotenv', - { - only: envWhitelist, - }, - ], - [ - 'nuxt-env', - { - keys: envWhitelist, - }, - ], + ['@nuxtjs/dotenv', { only: Object.keys(CONFIG) }], + ['nuxt-env', { keys: Object.keys(CONFIG) }], [ 'vue-scrollto/nuxt', { @@ -175,32 +149,32 @@ export default { */ axios: { // See https://github.com/nuxt-community/axios-module#options - debug: dev, + debug: CONFIG.DEBUG, proxy: true, }, proxy: { '/.well-known/webfinger': { - target: process.env.GRAPHQL_URI || 'http://localhost:4000', + target: CONFIG.GRAPHQL_URI, toProxy: true, // cloudflare needs that headers: { Accept: 'application/json', 'X-UI-Request': true, - 'X-API-TOKEN': process.env.BACKEND_TOKEN || 'NULL', + 'X-API-TOKEN': CONFIG.BACKEND_TOKEN, }, }, '/activitypub': { // make this configurable (nuxt-dotenv) - target: process.env.GRAPHQL_URI || 'http://localhost:4000', + target: CONFIG.GRAPHQL_URI, toProxy: true, // cloudflare needs that headers: { Accept: 'application/json', 'X-UI-Request': true, - 'X-API-TOKEN': process.env.BACKEND_TOKEN || 'NULL', + 'X-API-TOKEN': CONFIG.BACKEND_TOKEN, }, }, '/api': { // make this configurable (nuxt-dotenv) - target: process.env.GRAPHQL_URI || 'http://localhost:4000', + target: CONFIG.GRAPHQL_URI, pathRewrite: { '^/api': '', }, @@ -208,7 +182,7 @@ export default { headers: { Accept: 'application/json', 'X-UI-Request': true, - 'X-API-TOKEN': process.env.BACKEND_TOKEN || 'NULL', + 'X-API-TOKEN': CONFIG.BACKEND_TOKEN, }, }, }, @@ -235,9 +209,9 @@ export default { }, sentry: { - dsn: process.env.SENTRY_DSN_WEBAPP, - publishRelease: !!process.env.COMMIT, - config: additionalSentryConfig, + dsn: CONFIG.SENTRY_DSN_WEBAPP, + publishRelease: !!CONFIG.COMMIT, + config: CONFIG.COMMIT ? { release: CONFIG.COMMIT } : {}, }, manifest, @@ -250,7 +224,7 @@ export default { ** You can extend webpack config here */ extend(config, ctx) { - if (process.env.STYLEGUIDE_DEV) { + if (CONFIG.STYLEGUIDE_DEV) { config.resolve.alias['@@'] = path.resolve(__dirname, `${styleguidePath}/src/system`) config.module.rules.push({ resourceQuery: /blockType=docs/, From 9f549371f7d46da4e3700a8f63eda67c0de97bb8 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 20 Jan 2021 19:59:29 +0100 Subject: [PATCH 3/4] fixed dockerfile for maintenance with new config --- webapp/Dockerfile.maintenance | 1 + 1 file changed, 1 insertion(+) diff --git a/webapp/Dockerfile.maintenance b/webapp/Dockerfile.maintenance index a688e0f82..b02fe352b 100644 --- a/webapp/Dockerfile.maintenance +++ b/webapp/Dockerfile.maintenance @@ -27,6 +27,7 @@ COPY plugins/i18n.js plugins/v-tooltip.js plugins/styleguide.js plugins/ COPY static static COPY constants constants COPY nuxt.config.js nuxt.config.js +COPY config/ config/ # this will also ovewrite the existing package.json COPY maintenance/source ./ From a6bd42856afbc0e38d64ce4fc3680df0a1cee00f Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 27 Jan 2021 15:00:24 +0100 Subject: [PATCH 4/4] - fixed config import - default for STYLEGUIDE_DEV config --- webapp/config/index.js | 2 +- webapp/nuxt.config.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/config/index.js b/webapp/config/index.js index 68c220533..ccc30da73 100644 --- a/webapp/config/index.js +++ b/webapp/config/index.js @@ -11,8 +11,8 @@ const environment = { DEBUG: process.env.NODE_ENV !== 'production' || false, PRODUCTION: process.env.NODE_ENV === 'production' || false, NUXT_BUILD: process.env.NUXT_BUILD || '.nuxt', + STYLEGUIDE_DEV: process.env.STYLEGUIDE_DEV || false, RELEASE: process.env.release, - STYLEGUIDE_DEV: process.env.STYLEGUIDE_DEV, } const server = { diff --git a/webapp/nuxt.config.js b/webapp/nuxt.config.js index d772eb339..912710ad8 100644 --- a/webapp/nuxt.config.js +++ b/webapp/nuxt.config.js @@ -2,7 +2,7 @@ import path from 'path' import manifest from './constants/manifest.js' import metadata from './constants/metadata.js' -const CONFIG = require('./config') // we need to use require since this is only evaluated at compile time. +const CONFIG = require('./config').default // we need to use require since this is only evaluated at compile time. const styleguidePath = '../styleguide' const styleguideStyles = CONFIG.STYLEGUIDE_DEV