From 049282187860833863b864afdabd69115006b4c4 Mon Sep 17 00:00:00 2001 From: Luke Bettridge Date: Sun, 15 Mar 2020 21:45:51 +0000 Subject: [PATCH] Dockerize application (#52) * Remove dangling env variables and add Dockerfile * Main workflow added * Add checkout to deploy job * Update deploy and verify command * Add separate workflows for environments * Prevent cypress install in CI workflow * Remove .env.ci * Remove deploy script --- .dockerignore | 25 ++++ .env.ci | 7 - .env.example | 17 ++- .github/workflows/{main.yml => ci.yml} | 6 +- .github/workflows/e2e.yml | 20 --- .github/workflows/production.yml | 44 ++++++ .github/workflows/staging.yml | 45 ++++++ Dockerfile | 22 +++ README.md | 2 +- .../components/pages/auth/login/utils.test.js | 5 - .../pages/auth/register/utils.test.js | 21 +-- .../pages/auth/reset-password/utils.test.js | 17 +-- .../server/routes/auth/reset-password.test.js | 8 +- client/components/App.jsx | 2 +- client/components/pages/auth/login/utils.js | 2 - .../components/pages/auth/register/utils.js | 12 +- .../pages/auth/reset-password/utils.js | 14 +- config/deployment.yml | 140 ++++++++++++++++++ docker-compose.yml | 40 +++++ scripts/deploy.sh | 34 ----- server/config/db.js | 20 +++ server/index.js | 6 +- server/init.dev.js | 7 +- server/routes/auth/reset-password.js | 10 +- webpack.config.js | 10 -- 25 files changed, 394 insertions(+), 142 deletions(-) create mode 100644 .dockerignore delete mode 100644 .env.ci rename .github/workflows/{main.yml => ci.yml} (77%) delete mode 100644 .github/workflows/e2e.yml create mode 100644 .github/workflows/production.yml create mode 100644 .github/workflows/staging.yml create mode 100644 Dockerfile create mode 100644 config/deployment.yml create mode 100644 docker-compose.yml delete mode 100644 scripts/deploy.sh create mode 100644 server/config/db.js diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a9cdcb6 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,25 @@ +.DS_Store +.env + +# logs +logs +*.log +npm-debug.log.* + +# dependencies +node_modules + +# test coverage +coverage + +# cypress +cypress +cypress.env.json + +# git +.git +.gitignore + +# docker +Dockerfile +.dockerignore \ No newline at end of file diff --git a/.env.ci b/.env.ci deleted file mode 100644 index ec994ce..0000000 --- a/.env.ci +++ /dev/null @@ -1,7 +0,0 @@ -BASE_URL=http://localhost:5000 -PORT=5000 -NODE_ENV=production -MONGO_URI=mongodb://testing:stuckshine@68.183.43.15:27017/portal_staging?authSource=admin -SECRET_OR_KEY=G8Q2m8IhKP -EXPIRE_PASSWORD_RESET_DAYS=1 -HAS_SSL=false diff --git a/.env.example b/.env.example index 326492f..daf71ee 100644 --- a/.env.example +++ b/.env.example @@ -1,14 +1,21 @@ -BASE_URL=# server URL -CORS_ORIGIN=# not required if same as BASE_URL -NODE_ENV=# environment (e.g. development) PORT=# server port (e.g. 5000) -MONGO_URI=# db connection (e.g. mongodb://:@:/ +NODE_ENV=# environment (e.g. development) + +MONGO_USERNAME=# host username +MONGO_PASSWORD=# host password +MONGO_HOSTNAME=# host name +MONGO_PORT=# host port (e.g. 27017) +MONGO_DB=# db name +MONGO_REPLICASET=# db replica set + SECRET_OR_KEY=# JWT secret EXPIRE_PASSWORD_RESET_DAYS=# days for password reset requests to expire in HAS_SSL=# hosted with an SSL certificate + APP_NAME=# used in outgoing email + MAIL_HOST=# smtp host -MAIL_PORT=# smtp port (465) +MAIL_PORT=# smtp port (e.g. 465) MAIL_FROM=# from email address MAIL_USERNAME=# smtp host username MAIL_PASSWORD=# smtp host password \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/ci.yml similarity index 77% rename from .github/workflows/main.yml rename to .github/workflows/ci.yml index 4933a8e..33a4f68 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/ci.yml @@ -7,13 +7,15 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 + - name: Use Node.js 8.x uses: actions/setup-node@v1 with: node-version: "8.x" - - name: Install dependencies, build, and test + + - name: Install dependencies, build and test run: | - npm ci + CYPRESS_INSTALL_BINARY=0 npm ci npm run build --if-present npm test env: diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml deleted file mode 100644 index 9a9ed1a..0000000 --- a/.github/workflows/e2e.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Cypress E2E -on: - pull_request: - branches: - - staging -jobs: - cypress-run: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v1 - - name: Copy ENV configuration for CI - run: cp .env.ci .env - - name: Cypress run - uses: cypress-io/github-action@v1 - with: - build: npm run build - start: npm start - wait-on: http://localhost:5000 - env: apiUrl=http://localhost:5000,baseUrl=http://localhost:5000 diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml new file mode 100644 index 0000000..1f27dc7 --- /dev/null +++ b/.github/workflows/production.yml @@ -0,0 +1,44 @@ +name: K8S PROD + +on: + release: + types: [published] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + + - name: Build container image + run: docker build -t registry.paddl.co.uk/mern-auth-boilerplate:$GITHUB_REF . + + - name: Registry authentication + env: + REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }} + REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} + run: docker login -u $REGISTRY_USERNAME -p $REGISTRY_PASSWORD registry.paddl.co.uk + + - name: Push image + run: docker push registry.paddl.co.uk/mern-auth-boilerplate + deploy: + runs-on: ubuntu-latest + needs: build + steps: + - uses: actions/checkout@v1 + + - name: Update deployment file + run: sed -i 's||registry.paddl.co.uk/mern-auth-boilerplate:$GITHUB_REF|' $GITHUB_WORKSPACE/config/deployment.yml + + - name: Save DigitalOcean kubeconfig + uses: digitalocean/action-doctl@master + env: + DIGITALOCEAN_ACCESS_TOKEN: ${{ secrets.DO_ACCESS_TOKEN }} + with: + args: kubernetes cluster kubeconfig show k8s-1-16-6-do-0-lon1-1584220776791 > $GITHUB_WORKSPACE/.kubeconfig + + - name: Deploy to cluster + run: kubectl --kubeconfig=$GITHUB_WORKSPACE/.kubeconfig apply -f $GITHUB_WORKSPACE/config/deployment.yml -n prod + + - name: Verify deployment + run: kubectl --kubeconfig=$GITHUB_WORKSPACE/.kubeconfig rollout status deployment/mern-auth-boilerplate-nodeapp -n prod diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml new file mode 100644 index 0000000..72ed354 --- /dev/null +++ b/.github/workflows/staging.yml @@ -0,0 +1,45 @@ +name: K8S STG + +on: + push: + branches: + - staging + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + + - name: Build container image + run: docker build -t registry.paddl.co.uk/mern-auth-boilerplate:$(echo $GITHUB_SHA | head -c7) . + + - name: Registry authentication + env: + REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }} + REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} + run: docker login -u $REGISTRY_USERNAME -p $REGISTRY_PASSWORD registry.paddl.co.uk + + - name: Push image + run: docker push registry.paddl.co.uk/mern-auth-boilerplate + deploy: + runs-on: ubuntu-latest + needs: build + steps: + - uses: actions/checkout@v1 + + - name: Update deployment file + run: TAG=$(echo $GITHUB_SHA | head -c7) && sed -i 's||registry.paddl.co.uk/mern-auth-boilerplate:'${TAG}'|' $GITHUB_WORKSPACE/config/deployment.yml + + - name: Save DigitalOcean kubeconfig + uses: digitalocean/action-doctl@master + env: + DIGITALOCEAN_ACCESS_TOKEN: ${{ secrets.DO_ACCESS_TOKEN }} + with: + args: kubernetes cluster kubeconfig show k8s-1-16-6-do-0-lon1-1584220776791 > $GITHUB_WORKSPACE/.kubeconfig + + - name: Deploy to cluster + run: kubectl --kubeconfig=$GITHUB_WORKSPACE/.kubeconfig apply -f $GITHUB_WORKSPACE/config/deployment.yml -n stg + + - name: Verify deployment + run: kubectl --kubeconfig=$GITHUB_WORKSPACE/.kubeconfig rollout status deployment/mern-auth-boilerplate-nodeapp -n stg diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..418b738 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM node:8-alpine + +RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app + +# Create app directory +WORKDIR /home/node/app + +COPY package*.json ./ +USER node + +# Install app dependencies +RUN CYPRESS_INSTALL_BINARY=0 npm install + +# Bundle app source +COPY --chown=node:node . . + +# Test and build +RUN npm run test +RUN npm run build && npm prune --production + +EXPOSE 5000 +CMD npm start \ No newline at end of file diff --git a/README.md b/README.md index 44f23e4..b11830f 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ npm run dev Which can now be viewed in the browser at: ``` -http://localhost:3000/ +http://localhost:5000/ ``` ## Testing diff --git a/__tests__/client/components/pages/auth/login/utils.test.js b/__tests__/client/components/pages/auth/login/utils.test.js index 8ec135e..8c3b48d 100644 --- a/__tests__/client/components/pages/auth/login/utils.test.js +++ b/__tests__/client/components/pages/auth/login/utils.test.js @@ -9,9 +9,6 @@ jest.mock("axios", () => ({ catch: jest.fn() })); -global.process.env = { - BASE_URL: "foo" -}; const success = jest.fn(); const error = jest.fn(); @@ -35,7 +32,6 @@ describe("Login utility methods", () => { "/api/auth/login", { email: "hello@example.com", password: "password" }, { - baseURL: "foo", withCredentials: true } ); @@ -51,7 +47,6 @@ describe("Login utility methods", () => { expect(axios.get).toHaveBeenCalledWith( "/api/auth/reset-password?email=hello@example.com", { - baseURL: "foo", withCredentials: true } ); diff --git a/__tests__/client/components/pages/auth/register/utils.test.js b/__tests__/client/components/pages/auth/register/utils.test.js index 7cb3df0..557e80e 100644 --- a/__tests__/client/components/pages/auth/register/utils.test.js +++ b/__tests__/client/components/pages/auth/register/utils.test.js @@ -8,9 +8,6 @@ jest.mock("axios", () => ({ catch: jest.fn() })); -global.process.env = { - BASE_URL: "foo" -}; const success = jest.fn(); const error = jest.fn(); @@ -35,17 +32,13 @@ describe("Register utility methods", () => { error ); - expect(axios.post).toHaveBeenCalledWith( - "/api/auth/register", - { - forename: "John", - surname: "Doe", - email: "hello@example.com", - password: "password", - password2: "password" - }, - { baseURL: "foo" } - ); + expect(axios.post).toHaveBeenCalledWith("/api/auth/register", { + forename: "John", + surname: "Doe", + email: "hello@example.com", + password: "password", + password2: "password" + }); expect(axios.then).toHaveBeenCalledWith(success); expect(axios.catch).toHaveBeenCalledWith(error); }); diff --git a/__tests__/client/components/pages/auth/reset-password/utils.test.js b/__tests__/client/components/pages/auth/reset-password/utils.test.js index 80fe9bb..cc48695 100644 --- a/__tests__/client/components/pages/auth/reset-password/utils.test.js +++ b/__tests__/client/components/pages/auth/reset-password/utils.test.js @@ -8,9 +8,6 @@ jest.mock("axios", () => ({ catch: jest.fn() })); -global.process.env = { - BASE_URL: "foo" -}; const success = jest.fn(); const error = jest.fn(); @@ -33,15 +30,11 @@ describe("ResetPassword utility methods", () => { error ); - expect(axios.post).toHaveBeenCalledWith( - "/api/auth/reset-password", - { - resetKey: "bar", - newPassword: "password", - newPassword2: "password" - }, - { baseURL: "foo" } - ); + expect(axios.post).toHaveBeenCalledWith("/api/auth/reset-password", { + resetKey: "bar", + newPassword: "password", + newPassword2: "password" + }); expect(axios.then).toHaveBeenCalledWith(success); expect(axios.catch).toHaveBeenCalledWith(error); }); diff --git a/__tests__/server/routes/auth/reset-password.test.js b/__tests__/server/routes/auth/reset-password.test.js index 22a56f5..1b7faa9 100644 --- a/__tests__/server/routes/auth/reset-password.test.js +++ b/__tests__/server/routes/auth/reset-password.test.js @@ -31,8 +31,7 @@ const oldDate = new Date(0); const newDate = new Date(1); global.process.env = { - APP_NAME: "app", - BASE_URL: "http://example.com" + APP_NAME: "app" }; describe("routes reset password (get)", () => { @@ -46,6 +45,7 @@ describe("routes reset password (get)", () => { res.status.mockReturnValue(res); baseUser.updateOne.mockReturnValue(baseUser); baseUser.then.mockReturnValue(baseUser); + req.get.mockReturnValue("example.com"); }); it("request password reset successfully", () => { @@ -123,7 +123,9 @@ The app Team` const req = { query: { email: "hello@example.com" - } + }, + protocol: "http", + get: jest.fn() }; }); diff --git a/client/components/App.jsx b/client/components/App.jsx index 966e24e..71c81f6 100644 --- a/client/components/App.jsx +++ b/client/components/App.jsx @@ -20,7 +20,7 @@ import { Accounts } from "./pages/admin"; import Home from "./pages/home"; const httpLink = createHttpLink({ - uri: `${process.env.BASE_URL}/graphql`, + uri: "/graphql", credentials: "include" }); diff --git a/client/components/pages/auth/login/utils.js b/client/components/pages/auth/login/utils.js index 5174ab3..6759107 100644 --- a/client/components/pages/auth/login/utils.js +++ b/client/components/pages/auth/login/utils.js @@ -6,7 +6,6 @@ const login = ({ email, password }, success, error) => { "/api/auth/login", { email, password }, { - baseURL: process.env.BASE_URL, withCredentials: true } ) @@ -17,7 +16,6 @@ const login = ({ email, password }, success, error) => { const resetPassword = (email, success, error) => { axios .get(`/api/auth/reset-password?email=${email}`, { - baseURL: process.env.BASE_URL, withCredentials: true }) .then(success) diff --git a/client/components/pages/auth/register/utils.js b/client/components/pages/auth/register/utils.js index abd6bc7..eeb4851 100644 --- a/client/components/pages/auth/register/utils.js +++ b/client/components/pages/auth/register/utils.js @@ -6,11 +6,13 @@ const register = ( error ) => { axios - .post( - "/api/auth/register", - { forename, surname, email, password, password2 }, - { baseURL: process.env.BASE_URL } - ) + .post("/api/auth/register", { + forename, + surname, + email, + password, + password2 + }) .then(success) .catch(error); }; diff --git a/client/components/pages/auth/reset-password/utils.js b/client/components/pages/auth/reset-password/utils.js index b822dee..8e55a92 100644 --- a/client/components/pages/auth/reset-password/utils.js +++ b/client/components/pages/auth/reset-password/utils.js @@ -6,15 +6,11 @@ const resetPassword = ( error ) => { axios - .post( - "/api/auth/reset-password", - { - resetKey, - newPassword, - newPassword2 - }, - { baseURL: process.env.BASE_URL } - ) + .post("/api/auth/reset-password", { + resetKey, + newPassword, + newPassword2 + }) .then(success) .catch(error); }; diff --git a/config/deployment.yml b/config/deployment.yml new file mode 100644 index 0000000..2cbf2ca --- /dev/null +++ b/config/deployment.yml @@ -0,0 +1,140 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + deployment.kubernetes.io/revision: "1" + creationTimestamp: null + generation: 1 + labels: + app.kubernetes.io/instance: mern-auth-boilerplate + app.kubernetes.io/managed-by: Tiller + app.kubernetes.io/name: nodeapp + app.kubernetes.io/version: "1.0" + helm.sh/chart: nodeapp-0.1.0 + name: mern-auth-boilerplate-nodeapp +spec: + progressDeadlineSeconds: 600 + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + app.kubernetes.io/instance: mern-auth-boilerplate + app.kubernetes.io/name: nodeapp + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + creationTimestamp: null + labels: + app.kubernetes.io/instance: mern-auth-boilerplate + app.kubernetes.io/name: nodeapp + spec: + containers: + - env: + - name: MONGO_USERNAME + valueFrom: + secretKeyRef: + key: MONGO_USERNAME + name: mern-auth-boilerplate-mongo-auth + - name: MONGO_PASSWORD + valueFrom: + secretKeyRef: + key: MONGO_PASSWORD + name: mern-auth-boilerplate-mongo-auth + - name: MAIL_USERNAME + valueFrom: + secretKeyRef: + key: MAIL_USERNAME + name: mern-auth-boilerplate-mail-auth + - name: MAIL_PASSWORD + valueFrom: + secretKeyRef: + key: MAIL_PASSWORD + name: mern-auth-boilerplate-mail-auth + - name: SECRET_OR_KEY + valueFrom: + secretKeyRef: + key: SECRET_OR_KEY + name: mern-auth-boilerplate-jwt-key + - name: MONGO_HOSTNAME + valueFrom: + configMapKeyRef: + key: MONGO_HOSTNAME + name: mern-auth-boilerplate-config + - name: MONGO_PORT + valueFrom: + configMapKeyRef: + key: MONGO_PORT + name: mern-auth-boilerplate-config + - name: MONGO_DB + valueFrom: + configMapKeyRef: + key: MONGO_DB + name: mern-auth-boilerplate-config + - name: MONGO_REPLICASET + valueFrom: + configMapKeyRef: + key: MONGO_REPLICASET + name: mern-auth-boilerplate-config + - name: MAIL_HOST + valueFrom: + configMapKeyRef: + key: MAIL_HOST + name: mern-auth-boilerplate-config + - name: MAIL_PORT + valueFrom: + configMapKeyRef: + key: MAIL_PORT + name: mern-auth-boilerplate-config + - name: MAIL_FROM + valueFrom: + configMapKeyRef: + key: MAIL_FROM + name: mern-auth-boilerplate-config + - name: APP_NAME + valueFrom: + configMapKeyRef: + key: APP_NAME + name: mern-auth-boilerplate-config + image: + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 3 + httpGet: + path: / + port: http + scheme: HTTP + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + name: nodeapp + ports: + - containerPort: 5000 + name: http + protocol: TCP + readinessProbe: + failureThreshold: 3 + httpGet: + path: / + port: http + scheme: HTTP + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + resources: {} + securityContext: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + dnsPolicy: ClusterFirst + imagePullSecrets: + - name: regcred + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + serviceAccount: mern-auth-boilerplate-nodeapp + serviceAccountName: mern-auth-boilerplate-nodeapp + terminationGracePeriodSeconds: 30 +status: {} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a1b4999 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,40 @@ +version: "3" + +services: + node: + build: + context: . + dockerfile: Dockerfile + image: lukebettridge/mern-auth-boilerplate + container_name: app + restart: always + env_file: .env + environment: + - MONGO_USERNAME=$MONGO_USERNAME + - MONGO_PASSWORD=$MONGO_PASSWORD + - MONGO_HOSTNAME=db + - MONGO_PORT=$MONGO_PORT + - MONGO_DB=$MONGO_DB + - SECRET_OR_KEY=$SECRET_OR_KEY + ports: + - "80:5000" + networks: + - app-network + db: + image: mongo:4.1.8-xenial + container_name: db + restart: always + environment: + - MONGO_INITDB_ROOT_USERNAME=$MONGO_USERNAME + - MONGO_INITDB_ROOT_PASSWORD=$MONGO_PASSWORD + volumes: + - dbdata:/data/db + networks: + - app-network + +networks: + app-network: + driver: bridge + +volumes: + dbdata: diff --git a/scripts/deploy.sh b/scripts/deploy.sh deleted file mode 100644 index 4ad5549..0000000 --- a/scripts/deploy.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -set -e - -PROCESS_NAME=$1 -APP_DIR=$2 -GIT_URL=$3 - -set -x -if [[ -e $APP_DIR ]]; then - cd $APP_DIR - git pull -else - if [[ -n $APP_URL ]]; then - git clone $GIT_URL $APP_DIR - cd $APP_DIR - else - exit 1 - fi -fi - -# Install dependencies -npm install - -# Build application -npm run build - -# Remove dev dependencies -npm prune --production - -# Undo any local changes -git reset --hard - -# Restart app -pm2 restart $PROCESS_NAME \ No newline at end of file diff --git a/server/config/db.js b/server/config/db.js new file mode 100644 index 0000000..0d3bd87 --- /dev/null +++ b/server/config/db.js @@ -0,0 +1,20 @@ +const { + MONGO_USERNAME, + MONGO_PASSWORD, + MONGO_HOSTNAME, + MONGO_PORT, + MONGO_DB, + MONGO_AUTHSOURCE, + MONGO_REPLICASET +} = process.env; + +module.exports = { + url: `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=${MONGO_AUTHSOURCE || + "admin"}${MONGO_REPLICASET ? `&replicaSet=${MONGO_REPLICASET}` : ""}`, + options: { + connectTimeoutMS: 10000, + reconnectTries: 10, + reconnectInterval: 500, + useNewUrlParser: true + } +}; diff --git a/server/index.js b/server/index.js index e271e1a..3031b87 100644 --- a/server/index.js +++ b/server/index.js @@ -8,6 +8,7 @@ const router = express.Router(); require("dotenv").config(); +const db = require("./config/db"); const routes = { auth: require("./routes/auth") }; @@ -19,10 +20,7 @@ const typeDefs = require("./src/types"); const PORT = process.env.PORT || 5000; mongoose - .connect(process.env.MONGO_URI, { - useNewUrlParser: true, - useUnifiedTopology: true - }) + .connect(db.url, db.options) .then(() => console.log("MongoDB successfully connected")) .catch(err => console.log(err)); diff --git a/server/init.dev.js b/server/init.dev.js index 683a4ed..c6d858e 100644 --- a/server/init.dev.js +++ b/server/init.dev.js @@ -7,12 +7,7 @@ const { graphiqlExpress } = require("graphql-server-express"); const compiler = webpack(config); module.exports = app => { - app.use( - cors({ - origin: process.env.CORS_ORIGIN || process.env.BASE_URL, - credentials: true - }) - ); + app.use(cors({ origin: true, credentials: true })); app.use( "/graphiql", graphiqlExpress({ diff --git a/server/routes/auth/reset-password.js b/server/routes/auth/reset-password.js index 4dd0218..fb40c19 100644 --- a/server/routes/auth/reset-password.js +++ b/server/routes/auth/reset-password.js @@ -1,3 +1,5 @@ +const url = require("url"); + const { mail, passwordHash, randomString } = require("../../utils"); const validate = require("../../validation/reset-password"); const User = require("../../src/models/User"); @@ -26,13 +28,17 @@ module.exports = { user .updateOne({ resetKey }) .then(() => { - const url = `${process.env.BASE_URL}/auth/reset-password/${resetKey}`; + const baseUrl = url.format({ + protocol: req.protocol, + host: req.get("host") + }); + const path = `${baseUrl}/auth/reset-password/${resetKey}`; mail({ to: email, subject: `${process.env.APP_NAME} - Your password reset request`, text: `Hello ${user.forename}, -So, you've forgotten your password... no biggie, follow this link to set a new one: ${url} +So, you've forgotten your password... no biggie, follow this link to set a new one: ${path} Thanks, The ${process.env.APP_NAME} Team` diff --git a/webpack.config.js b/webpack.config.js index 4351076..f7a3c53 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,14 +1,7 @@ -const fs = require("fs"); -const dotenv = require("dotenv"); - const path = require("path"); const webpack = require("webpack"); const HtmlWebpackPlugin = require("html-webpack-plugin"); -let env = {}; -if (fs.existsSync(`${__dirname}/.env`)) - env = dotenv.parse(fs.readFileSync(`${__dirname}/.env`)); - module.exports = { entry: { app: "./client/app.js" @@ -61,9 +54,6 @@ module.exports = { new webpack.ProvidePlugin({ React: "react" }), - new webpack.DefinePlugin({ - "process.env.BASE_URL": JSON.stringify(env.BASE_URL) - }), new HtmlWebpackPlugin({ template: "client/index.html", minify: {