diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..485abc7
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,30 @@
+# Docker compose env
+
+MONGO_LOCAL_PORT=27017
+BACKEND_LOCAL_PORT=8080
+FRONTEND_LOCAL_PORT=3000
+VITE_BACKEND_URL=http://backend:8080
+
+# MongoDB Environment
+MONGO_INITDB_DATABASE=getaroom
+MONGO_INITDB_ROOT_USERNAME=root
+MONGO_INITDB_ROOT_PASSWORD=testroot
+MONGO_EXPRESS_USERNAME=admin
+MONGO_EXPRESS_PASSWORD=testadmin
+
+DB_OVERRIDE_URL=mongodb://getaroom:getaroom@mongodb/getaroom?retryWrites=true&w=majority
+ME_CONFIG_MONGODB_URL=mongo://root:testroot@mongodb
+
+# Secret for JWT token, could be any long random string
+JWT_SECRET="foobarbaz123foobarbaz123foobarbaz123foobarbaz123"
+
+# Client ID is found here: (https://console.cloud.google.com/apis/credentials?project=get-a-room-326217), go to "OAuth 2.0 Client IDs" -> "Get A Room!" -> "Client ID"
+GOOGLE_CLIENT_ID=""
+
+# Client secret is found here: (https://console.cloud.google.com/apis/credentials?project=get-a-room-326217), go to "OAuth 2.0 Client IDs" -> "Get A Room!" -> "Client secret"
+GOOGLE_CLIENT_SECRET=""
+
+# Google Customer ID is found here: (https://admin.google.com/ac/accountsettings/profile)
+GOOGLE_CUSTOMER_ID=""
+
+TZ=Etc/UTC
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 49905f7..aa76597 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,3 +29,4 @@ yarn-error.log*
.env
*.iml
.idea
+.vapidkey
diff --git a/README.md b/README.md
index 14b330c..328ffc3 100644
--- a/README.md
+++ b/README.md
@@ -58,3 +58,36 @@ After this you probably want to point some domain to this application. This can
As a last thing, new OAuth 2.0 Client should be created in Google Cloud -> "APIs and services" -> "CREATE CREDENTIALS" -> "OAuth Client ID". Application type is "Web Application". Authorized JavaScript origins can be left empty. And to the "Authorised redirect URIs" this URL should be added: "https://yourdomainname.com/api/auth/google/callback" And of course remember to replace "yourdomainname" with the new domain name that was reserved for this application.
Now you should have a working GitHub actions deployment and a new environment!
+
+## Running local dev environment
+
+
+
+### Docker compose
+
+ 1. Copy .env.example files to .env files in
+ /
+ /frontend
+ /backend
+ 2. Edit root env file and add GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET and GOOGLE_CUSTOMER_ID values
+ 3. Run docker compose build && docker compose up -d
+
+
+
+### Npm
+
+MongoDb needed
+
+ 1. Copy .env.example files to .env files in
+ /frontend
+ /backend
+ 2. Run npm install
+ 3. Run npm run generate_vapid_keys
+ 4. Copy VAPID keys from logged output to backend and frontend .env files
+ 5. Add GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET and GOOGLE_CUSTOMER_ID and database setting to .env-files
+ 6. Run npm run nodemon in /backend folder
+ 7. Run npm run start in /frontend folder
+
+
+
+After frontend startup go to /login page and log in with valid OAuth-user.
diff --git a/backend/Dockerfile b/backend/Dockerfile
index 8ba5315..aaba425 100644
--- a/backend/Dockerfile
+++ b/backend/Dockerfile
@@ -1,6 +1,6 @@
# Use the official lightweight Node.js 12 image.
# https://hub.docker.com/_/node
-FROM node:16-slim
+FROM node:20
# Create and change to the app directory.
WORKDIR /usr/src/app
diff --git a/backend/package-lock.json b/backend/package-lock.json
index 9658054..6e9d043 100644
--- a/backend/package-lock.json
+++ b/backend/package-lock.json
@@ -23,11 +23,11 @@
"express": "^4.19.2",
"express-unless": "^2.1.3",
"express-validator": "^7.1.0",
- "googleapis": "^88.2.0",
+ "googleapis": "^142.0.0",
"helmet": "^7.1.0",
"jsonwebtoken": "^9.0.2",
"lodash": "^4.17.21",
- "luxon": "^3.4.4",
+ "luxon": "^3.5.0",
"mongoose": "^8.4.1",
"morgan": "^1.10.0",
"node-schedule": "^2.1.1",
@@ -49,7 +49,7 @@
"web-push": "^3.6.7"
},
"engines": {
- "node": ">=20.14.0"
+ "node": ">=20.12.2"
}
},
"node_modules/@ampproject/remapping": {
@@ -2167,17 +2167,6 @@
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true
},
- "node_modules/abort-controller": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
- "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
- "dependencies": {
- "event-target-shim": "^5.0.0"
- },
- "engines": {
- "node": ">=6.5"
- }
- },
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@@ -2222,6 +2211,8 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+ "optional": true,
+ "peer": true,
"dependencies": {
"debug": "4"
},
@@ -2233,6 +2224,8 @@
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+ "optional": true,
+ "peer": true,
"dependencies": {
"ms": "2.1.2"
},
@@ -2248,7 +2241,9 @@
"node_modules/agent-base/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "optional": true,
+ "peer": true
},
"node_modules/ajv": {
"version": "6.12.6",
@@ -2358,14 +2353,6 @@
"node": ">=8"
}
},
- "node_modules/arrify": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
- "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/asn1.js": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
@@ -3575,14 +3562,6 @@
"node": ">= 0.6"
}
},
- "node_modules/event-target-shim": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
- "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/execa": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
@@ -3766,11 +3745,6 @@
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true
},
- "node_modules/fast-text-encoding": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz",
- "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig=="
- },
"node_modules/fastq": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
@@ -3919,30 +3893,74 @@
}
},
"node_modules/gaxios": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.2.tgz",
- "integrity": "sha512-T+ap6GM6UZ0c4E6yb1y/hy2UB6hTrqhglp3XfmU9qbLCGRYhLVV5aRPpC4EmoG8N8zOnkYCgoBz+ScvGAARY6Q==",
+ "version": "6.7.1",
+ "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz",
+ "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==",
"dependencies": {
- "abort-controller": "^3.0.0",
"extend": "^3.0.2",
- "https-proxy-agent": "^5.0.0",
+ "https-proxy-agent": "^7.0.1",
"is-stream": "^2.0.0",
- "node-fetch": "^2.6.1"
+ "node-fetch": "^2.6.9",
+ "uuid": "^9.0.1"
},
"engines": {
- "node": ">=10"
+ "node": ">=14"
}
},
+ "node_modules/gaxios/node_modules/agent-base": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
+ "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
+ "dependencies": {
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/gaxios/node_modules/debug": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
+ "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/gaxios/node_modules/https-proxy-agent": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",
+ "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",
+ "dependencies": {
+ "agent-base": "^7.0.2",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/gaxios/node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
"node_modules/gcp-metadata": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.1.tgz",
- "integrity": "sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz",
+ "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==",
"dependencies": {
- "gaxios": "^4.0.0",
+ "gaxios": "^6.0.0",
"json-bigint": "^1.0.0"
},
"engines": {
- "node": ">=10"
+ "node": ">=14"
}
},
"node_modules/gensync": {
@@ -4064,64 +4082,47 @@
}
},
"node_modules/google-auth-library": {
- "version": "7.10.0",
- "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.10.0.tgz",
- "integrity": "sha512-ICsqaU+lxMHVlDUzMrfVIEqnARw2AwBiZ/2KnNM6BcTf9Nott+Af87DTIzmlnW865p3REUP2MVL0xkPC3a61aQ==",
+ "version": "9.14.0",
+ "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.14.0.tgz",
+ "integrity": "sha512-Y/eq+RWVs55Io/anIsm24sDS8X79Tq948zVLGaa7+KlJYYqaGwp1YI37w48nzrNi12RgnzMrQD4NzdmCowT90g==",
"dependencies": {
- "arrify": "^2.0.0",
"base64-js": "^1.3.0",
"ecdsa-sig-formatter": "^1.0.11",
- "fast-text-encoding": "^1.0.0",
- "gaxios": "^4.0.0",
- "gcp-metadata": "^4.2.0",
- "gtoken": "^5.0.4",
- "jws": "^4.0.0",
- "lru-cache": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/google-p12-pem": {
- "version": "3.1.4",
- "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.4.tgz",
- "integrity": "sha512-HHuHmkLgwjdmVRngf5+gSmpkyaRI6QmOg77J8tkNBHhNEI62sGHyw4/+UkgyZEI7h84NbWprXDJ+sa3xOYFvTg==",
- "dependencies": {
- "node-forge": "^1.3.1"
- },
- "bin": {
- "gp12-pem": "build/src/bin/gp12-pem.js"
+ "gaxios": "^6.1.1",
+ "gcp-metadata": "^6.1.0",
+ "gtoken": "^7.0.0",
+ "jws": "^4.0.0"
},
"engines": {
- "node": ">=10"
+ "node": ">=14"
}
},
"node_modules/googleapis": {
- "version": "88.2.0",
- "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-88.2.0.tgz",
- "integrity": "sha512-z3iDvGVqaJ+4TZ7YulK530q5vkY0BifvAWqcu2JiUSgpnIHzsA89k005+McoaYB+lAgv7lPY2Y4OPMT6iloWRA==",
+ "version": "142.0.0",
+ "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-142.0.0.tgz",
+ "integrity": "sha512-LsU1ynez4/KNPwnFMSDI93pBEsETNdQPCrT3kz2qgiNg5H2pW4dKW+1VmENMkZ4u9lMxA89nnXD3nqWBJ0rruQ==",
"dependencies": {
- "google-auth-library": "^7.0.2",
- "googleapis-common": "^5.0.2"
+ "google-auth-library": "^9.0.0",
+ "googleapis-common": "^7.0.0"
},
"engines": {
- "node": ">=10"
+ "node": ">=14.0.0"
}
},
"node_modules/googleapis-common": {
- "version": "5.0.5",
- "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-5.0.5.tgz",
- "integrity": "sha512-o2dgoW4x4fLIAN+IVAOccz3mEH8Lj1LP9c9BSSvkNJEn+U7UZh0WSr4fdH08x5VH7+sstIpd1lOYFZD0g7j4pw==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-7.2.0.tgz",
+ "integrity": "sha512-/fhDZEJZvOV3X5jmD+fKxMqma5q2Q9nZNSF3kn1F18tpxmA86BcTxAGBQdM0N89Z3bEaIs+HVznSmFJEAmMTjA==",
"dependencies": {
"extend": "^3.0.2",
- "gaxios": "^4.0.0",
- "google-auth-library": "^7.0.2",
+ "gaxios": "^6.0.3",
+ "google-auth-library": "^9.7.0",
"qs": "^6.7.0",
"url-template": "^2.0.8",
- "uuid": "^8.0.0"
+ "uuid": "^9.0.0"
},
"engines": {
- "node": ">=10.10.0"
+ "node": ">=14.0.0"
}
},
"node_modules/gopd": {
@@ -4148,16 +4149,15 @@
"dev": true
},
"node_modules/gtoken": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.1.tgz",
- "integrity": "sha512-yqOREjzLHcbzz1UrQoxhBtpk8KjrVhuqPE7od1K2uhyxG2BHjKZetlbLw/SPZak/QqTIQW+addS+EcjqQsZbwQ==",
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz",
+ "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==",
"dependencies": {
- "gaxios": "^4.0.0",
- "google-p12-pem": "^3.0.3",
+ "gaxios": "^6.0.0",
"jws": "^4.0.0"
},
"engines": {
- "node": ">=10"
+ "node": ">=14.0.0"
}
},
"node_modules/has": {
@@ -4267,6 +4267,8 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
"integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
+ "optional": true,
+ "peer": true,
"dependencies": {
"agent-base": "6",
"debug": "4"
@@ -4279,6 +4281,8 @@
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+ "optional": true,
+ "peer": true,
"dependencies": {
"ms": "2.1.2"
},
@@ -4294,7 +4298,9 @@
"node_modules/https-proxy-agent/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "optional": true,
+ "peer": true
},
"node_modules/human-signals": {
"version": "2.1.0",
@@ -6034,21 +6040,10 @@
"resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz",
"integrity": "sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w=="
},
- "node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/luxon": {
- "version": "3.4.4",
- "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz",
- "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==",
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz",
+ "integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==",
"engines": {
"node": ">=12"
}
@@ -6433,14 +6428,6 @@
}
}
},
- "node_modules/node-forge": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
- "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
- "engines": {
- "node": ">= 6.13.0"
- }
- },
"node_modules/node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@@ -7667,7 +7654,7 @@
"node_modules/url-template": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz",
- "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE="
+ "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw=="
},
"node_modules/utils-merge": {
"version": "1.0.1",
@@ -7678,9 +7665,13 @@
}
},
"node_modules/uuid": {
- "version": "8.3.2",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
- "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
+ "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
"bin": {
"uuid": "dist/bin/uuid"
}
@@ -7872,11 +7863,6 @@
"node": ">=10"
}
},
- "node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
- },
"node_modules/yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
@@ -9574,14 +9560,6 @@
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true
},
- "abort-controller": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
- "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
- "requires": {
- "event-target-shim": "^5.0.0"
- }
- },
"accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@@ -9612,6 +9590,8 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+ "optional": true,
+ "peer": true,
"requires": {
"debug": "4"
},
@@ -9620,6 +9600,8 @@
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+ "optional": true,
+ "peer": true,
"requires": {
"ms": "2.1.2"
}
@@ -9627,7 +9609,9 @@
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "optional": true,
+ "peer": true
}
}
},
@@ -9710,11 +9694,6 @@
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
"dev": true
},
- "arrify": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
- "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug=="
- },
"asn1.js": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
@@ -10557,11 +10536,6 @@
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
},
- "event-target-shim": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
- "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
- },
"execa": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
@@ -10706,11 +10680,6 @@
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true
},
- "fast-text-encoding": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz",
- "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig=="
- },
"fastq": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
@@ -10827,23 +10796,55 @@
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
},
"gaxios": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.2.tgz",
- "integrity": "sha512-T+ap6GM6UZ0c4E6yb1y/hy2UB6hTrqhglp3XfmU9qbLCGRYhLVV5aRPpC4EmoG8N8zOnkYCgoBz+ScvGAARY6Q==",
+ "version": "6.7.1",
+ "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz",
+ "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==",
"requires": {
- "abort-controller": "^3.0.0",
"extend": "^3.0.2",
- "https-proxy-agent": "^5.0.0",
+ "https-proxy-agent": "^7.0.1",
"is-stream": "^2.0.0",
- "node-fetch": "^2.6.1"
+ "node-fetch": "^2.6.9",
+ "uuid": "^9.0.1"
+ },
+ "dependencies": {
+ "agent-base": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
+ "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
+ "requires": {
+ "debug": "^4.3.4"
+ }
+ },
+ "debug": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
+ "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "https-proxy-agent": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",
+ "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",
+ "requires": {
+ "agent-base": "^7.0.2",
+ "debug": "4"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ }
}
},
"gcp-metadata": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.1.tgz",
- "integrity": "sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz",
+ "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==",
"requires": {
- "gaxios": "^4.0.0",
+ "gaxios": "^6.0.0",
"json-bigint": "^1.0.0"
}
},
@@ -10927,49 +10928,38 @@
}
},
"google-auth-library": {
- "version": "7.10.0",
- "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.10.0.tgz",
- "integrity": "sha512-ICsqaU+lxMHVlDUzMrfVIEqnARw2AwBiZ/2KnNM6BcTf9Nott+Af87DTIzmlnW865p3REUP2MVL0xkPC3a61aQ==",
+ "version": "9.14.0",
+ "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.14.0.tgz",
+ "integrity": "sha512-Y/eq+RWVs55Io/anIsm24sDS8X79Tq948zVLGaa7+KlJYYqaGwp1YI37w48nzrNi12RgnzMrQD4NzdmCowT90g==",
"requires": {
- "arrify": "^2.0.0",
"base64-js": "^1.3.0",
"ecdsa-sig-formatter": "^1.0.11",
- "fast-text-encoding": "^1.0.0",
- "gaxios": "^4.0.0",
- "gcp-metadata": "^4.2.0",
- "gtoken": "^5.0.4",
- "jws": "^4.0.0",
- "lru-cache": "^6.0.0"
- }
- },
- "google-p12-pem": {
- "version": "3.1.4",
- "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.4.tgz",
- "integrity": "sha512-HHuHmkLgwjdmVRngf5+gSmpkyaRI6QmOg77J8tkNBHhNEI62sGHyw4/+UkgyZEI7h84NbWprXDJ+sa3xOYFvTg==",
- "requires": {
- "node-forge": "^1.3.1"
+ "gaxios": "^6.1.1",
+ "gcp-metadata": "^6.1.0",
+ "gtoken": "^7.0.0",
+ "jws": "^4.0.0"
}
},
"googleapis": {
- "version": "88.2.0",
- "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-88.2.0.tgz",
- "integrity": "sha512-z3iDvGVqaJ+4TZ7YulK530q5vkY0BifvAWqcu2JiUSgpnIHzsA89k005+McoaYB+lAgv7lPY2Y4OPMT6iloWRA==",
+ "version": "142.0.0",
+ "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-142.0.0.tgz",
+ "integrity": "sha512-LsU1ynez4/KNPwnFMSDI93pBEsETNdQPCrT3kz2qgiNg5H2pW4dKW+1VmENMkZ4u9lMxA89nnXD3nqWBJ0rruQ==",
"requires": {
- "google-auth-library": "^7.0.2",
- "googleapis-common": "^5.0.2"
+ "google-auth-library": "^9.0.0",
+ "googleapis-common": "^7.0.0"
}
},
"googleapis-common": {
- "version": "5.0.5",
- "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-5.0.5.tgz",
- "integrity": "sha512-o2dgoW4x4fLIAN+IVAOccz3mEH8Lj1LP9c9BSSvkNJEn+U7UZh0WSr4fdH08x5VH7+sstIpd1lOYFZD0g7j4pw==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-7.2.0.tgz",
+ "integrity": "sha512-/fhDZEJZvOV3X5jmD+fKxMqma5q2Q9nZNSF3kn1F18tpxmA86BcTxAGBQdM0N89Z3bEaIs+HVznSmFJEAmMTjA==",
"requires": {
"extend": "^3.0.2",
- "gaxios": "^4.0.0",
- "google-auth-library": "^7.0.2",
+ "gaxios": "^6.0.3",
+ "google-auth-library": "^9.7.0",
"qs": "^6.7.0",
"url-template": "^2.0.8",
- "uuid": "^8.0.0"
+ "uuid": "^9.0.0"
}
},
"gopd": {
@@ -10993,12 +10983,11 @@
"dev": true
},
"gtoken": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.1.tgz",
- "integrity": "sha512-yqOREjzLHcbzz1UrQoxhBtpk8KjrVhuqPE7od1K2uhyxG2BHjKZetlbLw/SPZak/QqTIQW+addS+EcjqQsZbwQ==",
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz",
+ "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==",
"requires": {
- "gaxios": "^4.0.0",
- "google-p12-pem": "^3.0.3",
+ "gaxios": "^6.0.0",
"jws": "^4.0.0"
}
},
@@ -11076,6 +11065,8 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
"integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
+ "optional": true,
+ "peer": true,
"requires": {
"agent-base": "6",
"debug": "4"
@@ -11085,6 +11076,8 @@
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+ "optional": true,
+ "peer": true,
"requires": {
"ms": "2.1.2"
}
@@ -11092,7 +11085,9 @@
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "optional": true,
+ "peer": true
}
}
},
@@ -12457,18 +12452,10 @@
"resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz",
"integrity": "sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w=="
},
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "requires": {
- "yallist": "^4.0.0"
- }
- },
"luxon": {
- "version": "3.4.4",
- "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz",
- "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA=="
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz",
+ "integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ=="
},
"make-dir": {
"version": "4.0.0",
@@ -12732,11 +12719,6 @@
"whatwg-url": "^5.0.0"
}
},
- "node-forge": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
- "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA=="
- },
"node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@@ -13574,7 +13556,7 @@
"url-template": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz",
- "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE="
+ "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw=="
},
"utils-merge": {
"version": "1.0.1",
@@ -13582,9 +13564,9 @@
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"uuid": {
- "version": "8.3.2",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
- "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
+ "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="
},
"v8-compile-cache-lib": {
"version": "3.0.1",
@@ -13730,11 +13712,6 @@
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"dev": true
},
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
- },
"yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
diff --git a/backend/package.json b/backend/package.json
index 4b8eaa5..59a5c8e 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -15,6 +15,7 @@
"build": "tsc --project tsconfig.production.json",
"start": "ts-node src/app.ts",
"nodemon": "nodemon -e js,ts,json src/app.ts",
+ "generate_vapid_keys": "node ../scripts/generateVAPIDKeys.js",
"start-production": "node build/app.js"
},
"author": "",
@@ -34,11 +35,11 @@
"express": "^4.19.2",
"express-unless": "^2.1.3",
"express-validator": "^7.1.0",
- "googleapis": "^88.2.0",
+ "googleapis": "^142.0.0",
"helmet": "^7.1.0",
"jsonwebtoken": "^9.0.2",
"lodash": "^4.17.21",
- "luxon": "^3.4.4",
+ "luxon": "^3.5.0",
"mongoose": "^8.4.1",
"morgan": "^1.10.0",
"node-schedule": "^2.1.1",
diff --git a/backend/src/authMiddleware.ts b/backend/src/authMiddleware.ts
index afd3a71..c03ad18 100644
--- a/backend/src/authMiddleware.ts
+++ b/backend/src/authMiddleware.ts
@@ -51,8 +51,21 @@ export const parseToken = (): ExpressMiddlewareWithUnless => {
}
const payload = readToken(TOKEN);
-
if (!payload.refreshToken) {
+ console.warn(
+ 'oAuth refresh token not found. Revoking access token',
+ payload
+ );
+
+ getOAuthClient()
+ .revokeToken(payload.accessToken)
+ .then(() => {
+ console.warn('Access token revoked', payload);
+ })
+ .catch((reason) => {
+ console.error('Error revoking access token', reason);
+ });
+
return responses.invalidToken(req, res);
}
@@ -94,7 +107,6 @@ export const validateAccessToken = (): ExpressMiddlewareWithUnless => {
});
const newToken = (await client.getAccessToken()).token;
-
if (!newToken) {
return responses.invalidToken(req, res);
}
diff --git a/dev.Dockerfile b/dev.Dockerfile
new file mode 100644
index 0000000..ebe14e3
--- /dev/null
+++ b/dev.Dockerfile
@@ -0,0 +1,20 @@
+FROM node:20
+
+ARG DIR
+ARG TZ
+WORKDIR /usr/src/app
+
+COPY . /usr/src/app
+
+WORKDIR /usr/src/app/${DIR}
+
+RUN npm install
+
+RUN npm run build
+
+ENV BACKEND_URL ${BACKEND_URL}
+
+ENV TZ=${TZ}
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+VOLUME /usr/src/app
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..4f892a5
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,107 @@
+services:
+ mongodb:
+ image: mongo:7
+ container_name: getaroom-mongodb
+ hostname: mongodb
+ volumes:
+ - ./db/mongodb-single/mongodb/initdb.d/mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
+ env_file:
+ - .env
+ environment:
+ MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME}
+ MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD}
+ MONGO_INITDB_DATABASE: ${MONGO_INITDB_DATABASE}
+ ports:
+ - '${MONGO_LOCAL_PORT}:27017'
+ networks:
+ - getaroom_network
+ healthcheck:
+ test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quiet
+ interval: 10s
+ timeout: 10s
+ retries: 2
+ start_period: 5s
+
+ mongo-express:
+ image: mongo-express:latest
+ container_name: getaroom-mongo-express
+ restart: always
+ environment:
+ - ME_CONFIG_MONGODB_SERVER=mongodb
+ - ME_CONFIG_MONGODB_URL=${ME_CONFIG_MONGODB_URL}
+ - ME_CONFIG_MONGODB_ADMINUSERNAME=${MONGO_INITDB_ROOT_USERNAME}
+ - ME_CONFIG_MONGODB_ADMINPASSWORD=${MONGO_INITDB_ROOT_PASSWORD}
+ - ME_CONFIG_BASICAUTH_PASSWORD=${MONGO_EXPRESS_PASSWORD}
+ - ME_CONFIG_MONGODB_PORT=27017
+ - ME_CONFIG_BASICAUTH_USERNAME=${MONGO_EXPRESS_USERNAME}
+ ports:
+ - 8081:8081
+ networks:
+ - getaroom_network
+ depends_on:
+ mongodb:
+ condition: service_healthy
+
+ backend:
+ env_file:
+ - .env
+ build:
+ context: .
+ dockerfile: ./dev.Dockerfile
+ args:
+ - DIR=backend
+ - TZ=${TZ}
+ container_name: getaroom-backend
+ hostname: backend
+ volumes:
+ - ./:/usr/src/app/
+ ports:
+ - '${BACKEND_LOCAL_PORT}:8080'
+ networks:
+ - getaroom_network
+ healthcheck:
+ test: curl --fail http://localhost:8080/api || exit 1
+ interval: 20s
+ retries: 5
+ start_period: 5s
+ timeout: 10s
+ depends_on:
+ mongodb:
+ condition: service_healthy
+ command: |
+ bash -c "
+ npm --prefix /usr/src/app/backend run generate_vapid_keys &&
+ export VAPID_PUBLIC_KEY="$(sed -n '1p' ../.vapidkey)" &&
+ export VAPID_PRIVATE_KEY="$(sed -n '2p' ../.vapidkey)" &&
+ npm run nodemon
+ "
+ frontend:
+ env_file:
+ - .env
+ build:
+ context: .
+ dockerfile: ./dev.Dockerfile
+ args:
+ - DIR=frontend
+ - TZ=${TZ}
+ container_name: getaroom-frontend
+ depends_on:
+ backend:
+ condition: service_healthy
+ hostname: frontend
+ volumes:
+ - ./:/usr/src/app/
+ ports:
+ - '${FRONTEND_LOCAL_PORT}:3000'
+ expose:
+ - 3000
+ networks:
+ - getaroom_network
+ command: |
+ bash -c "export VITE_REACT_APP_SERVER_KEY="$(sed -n '1p' ../.vapidkey)"
+ npm run start:docker --host"
+
+networks:
+ getaroom_network:
+ driver: bridge
+ name: getaroom_network
diff --git a/frontend/index.html b/frontend/index.html
index 85b25c9..1cb8a7b 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -3,7 +3,7 @@