diff --git a/.env.example b/.env.example index 0a2067458..22780e8ca 100644 --- a/.env.example +++ b/.env.example @@ -27,6 +27,7 @@ OKTA_AUDIENCE= OKTA_KEY= OKTA_SECRET= BASE_URL=http://localhost:3000 +SECURE_COOKIES=false SENDGRID_API_KEY= SENDGRID_SENDER= SENDGRID_VERIFICATION_EMAIL_TID= diff --git a/Makefile b/Makefile index 2f98f596e..45f87d1d6 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,10 @@ single-build: docker build -f ./backend/Dockerfile -t retrospected/backend:${PACKAGE_VERSION} ./backend docker build -f ./frontend/Dockerfile -t retrospected/frontend:${PACKAGE_VERSION} ./frontend +local: + docker build -f ./backend/Dockerfile -t retrospected/backend:local ./backend + docker build -f ./frontend/Dockerfile -t retrospected/frontend:local ./frontend + install-trivy: brew install trivy diff --git a/README.md b/README.md index 66aebefdd..97220e7d8 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,10 @@ This will run a demo version, which you can turn into a fully licenced version b ## Versions History +### Version 4.11.5 (hotfix) + +- Making secure cookies an optional setting, as they won't work unless it is hosted on HTTPS. + ### Version 4.11.4 (hotfix) - Fixing a migration issue when installing from scratch diff --git a/backend/package.json b/backend/package.json index 6ca416cf9..22c73a793 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "@retrospected/backend", - "version": "4.11.4", + "version": "4.11.5", "license": "GNU GPLv3", "private": true, "scripts": { diff --git a/backend/src/config.ts b/backend/src/config.ts index fbf8c9908..94b5dff19 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -63,6 +63,7 @@ const config: BackendConfig = { SQL_LOG: defaultsBool('SQL_LOG', false), SENTRY_URL: defaults('SENTRY_URL', ''), BASE_URL: defaults('BASE_URL', 'http://localhost:80'), + SECURE_COOKIES: defaultsBool('SECURE_COOKIES', false), TWITTER_KEY: defaults('TWITTER_KEY', ''), TWITTER_SECRET: defaults('TWITTER_SECRET', ''), GOOGLE_KEY: defaults('GOOGLE_KEY', ''), diff --git a/backend/src/index.ts b/backend/src/index.ts index f3a3e106f..203358bd0 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -64,7 +64,7 @@ import { QueryFailedError } from 'typeorm'; import { deleteAccount } from './db/actions/delete'; const realIpHeader = 'X-Forwarded-For'; -const isProduction = process.env.NODE_ENV === 'production'; +const sessionSecret = `${config.SESSION_SECRET!}-4.11.5`; // Increment to force re-auth isLicenced().then((hasLicence) => { if (!hasLicence) { @@ -164,12 +164,12 @@ if (config.REDIS_ENABLED) { }); sessionMiddleware = session({ - secret: `${config.SESSION_SECRET!}-6`, // Increment to force re-auth + secret: sessionSecret, resave: true, saveUninitialized: true, store: new RedisStore({ client: redisClient }), cookie: { - secure: isProduction, + secure: config.SECURE_COOKIES, }, }); @@ -186,11 +186,11 @@ if (config.REDIS_ENABLED) { ); } else { sessionMiddleware = session({ - secret: `${config.SESSION_SECRET!}-9`, // Increment to force re-auth + secret: sessionSecret, resave: true, saveUninitialized: true, cookie: { - secure: isProduction, + secure: config.SECURE_COOKIES, }, }); } diff --git a/backend/src/security/is-licenced.ts b/backend/src/security/is-licenced.ts index 485d2b796..574d0d0dc 100644 --- a/backend/src/security/is-licenced.ts +++ b/backend/src/security/is-licenced.ts @@ -17,11 +17,16 @@ const hardcodedLicences: HardcodedLicence[] = [ encryptedOwner: 'U2FsdGVkX18/e8sfZ3bpjz3pLQkCxloH8nuniFdU+vo=', }, { - // Pear + // Parson hash: '$2a$10$33O/3uuETs0hKNIRWQzH5uQ8LgvZKhZumDcfy.izLLIzwqXmHRFu2', encryptedOwner: 'U2FsdGVkX1/weIyFN+TJEPkM0YF08D5CSD0vgrDOnouEveyXG2K/TurX63pBrhuR', }, + { + // Retrospected.com + hash: '$2a$10$hLlxhJ8yDp1lQJtTLePJr.SDuWFHSX4Kat8NHUgqPoKgRGLbZWy26', + encryptedOwner: 'U2FsdGVkX19b7JIgy/QrMncC1JjoVmBJ5EUo4AcGIkA=', + }, ]; export function isSelfHostedAndLicenced() { @@ -57,6 +62,9 @@ async function checkHardcodedLicence( async function isLicencedBase(): Promise { const licenceKey = config.LICENCE_KEY; + // Checking hardcoded licence as a last resort + const hardcodedLicence = await checkHardcodedLicence(licenceKey); + const payload: SelfHostedCheckPayload = { key: licenceKey }; try { const response = await fetch( @@ -73,6 +81,9 @@ async function isLicencedBase(): Promise { const result = (await response.json()) as LicenceMetadata; return result; } else { + if (hardcodedLicence) { + return hardcodedLicence; + } if (response.status === 403) { console.error( 'The licence key is not recognised. If you have a valid licence, please contact support@retrospected.com for support.' @@ -85,16 +96,17 @@ async function isLicencedBase(): Promise { } } } catch (err) { + if (hardcodedLicence) { + return hardcodedLicence; + } console.error( 'Could not contact the licence server. If you have a valid licence, please contact support@retrospected.com for support.' ); console.log(err); } - // Checking hardcoded licence as a last resort - const hardcoded = await checkHardcodedLicence(licenceKey); - if (hardcoded) { - return hardcoded; + if (hardcodedLicence) { + return hardcodedLicence; } return null; diff --git a/backend/src/types.ts b/backend/src/types.ts index 06c1a9cd4..3cb786b09 100644 --- a/backend/src/types.ts +++ b/backend/src/types.ts @@ -15,6 +15,7 @@ export interface BackendConfig { BACKEND_PORT: number; SQL_LOG: boolean; BASE_URL: string; + SECURE_COOKIES: boolean; SENTRY_URL: string; TWITTER_KEY: string; TWITTER_SECRET: string; diff --git a/docs/docs/self-hosting/optionals.md b/docs/docs/self-hosting/optionals.md index 2a780b6a5..4265ce097 100644 --- a/docs/docs/self-hosting/optionals.md +++ b/docs/docs/self-hosting/optionals.md @@ -38,6 +38,7 @@ services: REDIS_HOST: redis # Must be the name of the Redis service above SENTRY_URL: '' # Optional, Sentry URL (https://1234567890abcdef12345@sentry.io/1234567) BASE_URL: http://localhost:80 # This must be the URL of the frontend app once deployed. Only useful if you need OAuth, SendGrid or Stripe + SECURE_COOKIES: 'false' # You can set this to true if you are using HTTPS. This is more secure. # -- OAuth: Set these to enable OAuth authentication for one or more provider. This is optional. -- TWITTER_KEY: diff --git a/docs/package.json b/docs/package.json index f1e398a56..be7435876 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "docs", - "version": "4.11.4", + "version": "4.11.5", "private": true, "scripts": { "docusaurus": "docusaurus", diff --git a/frontend/package.json b/frontend/package.json index 5911a6004..93001db0d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "@retrospected/frontend", - "version": "4.11.4", + "version": "4.11.5", "license": "GNU GPLv3", "private": true, "dependencies": { diff --git a/package.json b/package.json index 238990c34..14d77aa36 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "retrospected", - "version": "4.11.4", + "version": "4.11.5", "description": "An agile retrospective board - Powering www.retrospected.com", "private": true, "scripts": { diff --git a/self-hosting/docker-compose.full.yml b/self-hosting/docker-compose.full.yml index e680d2bad..a21accd91 100644 --- a/self-hosting/docker-compose.full.yml +++ b/self-hosting/docker-compose.full.yml @@ -66,6 +66,7 @@ services: REDIS_HOST: redis # Must be the name of the Redis service above SENTRY_URL: '' # Optional, Sentry URL (https://1234567890abcdef12345@sentry.io/1234567) BASE_URL: http://localhost:80 # This must be the URL of the frontend app once deployed. Only useful if you need OAuth, SendGrid or Stripe + SECURE_COOKIES: 'false' # You can set this to true if you are using HTTPS. This is more secure. # -- OAuth: Set these to enable OAuth authentication for one or more provider. This is optional. -- TWITTER_KEY: