"` environment variable. This can also be declared in the `.env` file.
+
+By default, the gateway uses NGINX (as a proxy) to handle requests, so you'll need to set up this dependency.
+
+It can be installed system-wide or by linking a static binary to `packages/server/nginx-bin`
+
+> On Linux you can use built-in script to statically install
+`packages/server/scripts/installNginxStatic.sh` (needs CURL)
+
+## First Setup
+This will execute some tasks to initialize for first time your resources, like S3, Databases...etc.
+If you already initialized previously, skip this step.
+
+- Run server setup script (if needed)
+```shell
+npm run setup:server
+```
+
+Also can you use the `--force` flag to force the execution of this tasks again.
+
+### Starting the development server
+- You can use the command `npm run dev` to start all development servers.
+```shell
+npm run dev
+```
diff --git a/docs/docs/client-sdk/_category_.json b/docs/docs/client-sdk/_category_.json
deleted file mode 100644
index 144d6f39..00000000
--- a/docs/docs/client-sdk/_category_.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "label": "Client SDK",
- "position": 2,
- "link": {
- "type": "generated-index"
- }
-}
diff --git a/docs/docs/comty-cli/_category_.json b/docs/docs/comty-cli/_category_.json
deleted file mode 100644
index f275b2a1..00000000
--- a/docs/docs/comty-cli/_category_.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "label": "Comtyβ’ CLI",
- "position": 3,
- "link": {
- "type": "generated-index"
- }
-}
diff --git a/docs/docs/comty-cli/getting-started.md b/docs/docs/comty-cli/getting-started.md
deleted file mode 100644
index a736f04d..00000000
--- a/docs/docs/comty-cli/getting-started.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-sidebar_position: 1
----
-
-# Getting Started
-Me pica el splungus
\ No newline at end of file
diff --git a/docs/docs/comty-js/_category_.json b/docs/docs/comty-js/_category_.json
deleted file mode 100644
index 5576be2b..00000000
--- a/docs/docs/comty-js/_category_.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "label": "Comty.JS",
- "position": 1,
- "link": {
- "type": "generated-index"
- }
-}
diff --git a/docs/docs/comty-js/getting-started.md b/docs/docs/comty-js/getting-started.md
deleted file mode 100644
index a736f04d..00000000
--- a/docs/docs/comty-js/getting-started.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-sidebar_position: 1
----
-
-# Getting Started
-Me pica el splungus
\ No newline at end of file
diff --git a/docs/docs/comty-js/installing.md b/docs/docs/comty-js/installing.md
deleted file mode 100644
index 85592d8b..00000000
--- a/docs/docs/comty-js/installing.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-sidebar_position: 2
----
-
-# Installing
\ No newline at end of file
diff --git a/docs/docs/spectrum-api/_category_.json b/docs/docs/spectrum-api/_category_.json
deleted file mode 100644
index 6ab5187c..00000000
--- a/docs/docs/spectrum-api/_category_.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "label": "Spectrumβ’ API",
- "position": 4,
- "link": {
- "type": "generated-index"
- }
-}
diff --git a/docs/docs/spectrum-api/getting-started.md b/docs/docs/spectrum-api/getting-started.md
deleted file mode 100644
index a736f04d..00000000
--- a/docs/docs/spectrum-api/getting-started.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-sidebar_position: 1
----
-
-# Getting Started
-Me pica el splungus
\ No newline at end of file
diff --git a/docs/legal/tos.md b/docs/legal/tos.md
deleted file mode 100644
index d33889c5..00000000
--- a/docs/legal/tos.md
+++ /dev/null
@@ -1 +0,0 @@
-# Meet or TOS
\ No newline at end of file
diff --git a/docs/.gitignore b/docusaurus/.gitignore
similarity index 100%
rename from docs/.gitignore
rename to docusaurus/.gitignore
diff --git a/docs/README.md b/docusaurus/README.md
similarity index 100%
rename from docs/README.md
rename to docusaurus/README.md
diff --git a/docs/babel.config.js b/docusaurus/babel.config.js
similarity index 100%
rename from docs/babel.config.js
rename to docusaurus/babel.config.js
diff --git a/docs/docusaurus.config.js b/docusaurus/docusaurus.config.js
similarity index 92%
rename from docs/docusaurus.config.js
rename to docusaurus/docusaurus.config.js
index bb89c927..767a3f28 100644
--- a/docs/docusaurus.config.js
+++ b/docusaurus/docusaurus.config.js
@@ -40,6 +40,7 @@ const config = {
/** @type {import("@docusaurus/preset-classic").Options} */
({
docs: {
+ path: "../docs",
sidebarPath: "./sidebars.js",
//editUrl: "https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/",
},
@@ -68,12 +69,12 @@ const config = {
position: "left",
label: "Docs",
},
- {
- type: "docSidebar",
- sidebarId: "legal",
- position: "left",
- label: "Legal",
- },
+ // {
+ // type: "docSidebar",
+ // sidebarId: "legal",
+ // position: "left",
+ // label: "Legal",
+ // },
{
href: "https://github.com/ragestudio/comty",
label: "GitHub",
@@ -98,7 +99,7 @@ const config = {
{
label: "Comty",
href: "https://comty.app/@ragestudio",
- }
+ },
],
},
],
@@ -108,6 +109,9 @@ const config = {
theme: prismThemes.github,
darkTheme: prismThemes.dracula,
},
+ colorMode: {
+ defaultMode: "dark",
+ },
}),
}
diff --git a/docs/package.json b/docusaurus/package.json
similarity index 100%
rename from docs/package.json
rename to docusaurus/package.json
diff --git a/docs/sidebars.js b/docusaurus/sidebars.js
similarity index 65%
rename from docs/sidebars.js
rename to docusaurus/sidebars.js
index 02a5810c..77b13f1f 100644
--- a/docs/sidebars.js
+++ b/docusaurus/sidebars.js
@@ -13,9 +13,8 @@
/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
const sidebars = {
- // By default, Docusaurus generates a sidebar from the docs folder structure
- docs: [{type: 'autogenerated', dirName: '.'}],
- legal: [{type: 'autogenerated', dirName: '.'}],
+ // By default, Docusaurus generates a sidebar from the docs folder structure
+ docs: [{ type: "autogenerated", dirName: "." }],
}
-export default sidebars;
+export default sidebars
diff --git a/docs/src/components/HomepageFeatures/index.js b/docusaurus/src/components/HomepageFeatures/index.js
similarity index 100%
rename from docs/src/components/HomepageFeatures/index.js
rename to docusaurus/src/components/HomepageFeatures/index.js
diff --git a/docs/src/components/HomepageFeatures/styles.module.css b/docusaurus/src/components/HomepageFeatures/styles.module.css
similarity index 100%
rename from docs/src/components/HomepageFeatures/styles.module.css
rename to docusaurus/src/components/HomepageFeatures/styles.module.css
diff --git a/docs/src/css/custom.css b/docusaurus/src/css/custom.css
similarity index 100%
rename from docs/src/css/custom.css
rename to docusaurus/src/css/custom.css
diff --git a/docs/src/pages/index.js b/docusaurus/src/pages/index.js
similarity index 100%
rename from docs/src/pages/index.js
rename to docusaurus/src/pages/index.js
diff --git a/docs/src/pages/index.module.css b/docusaurus/src/pages/index.module.css
similarity index 100%
rename from docs/src/pages/index.module.css
rename to docusaurus/src/pages/index.module.css
diff --git a/docs/src/pages/markdown-page.md b/docusaurus/src/pages/markdown-page.md
similarity index 100%
rename from docs/src/pages/markdown-page.md
rename to docusaurus/src/pages/markdown-page.md
diff --git a/docs/static/.nojekyll b/docusaurus/static/.nojekyll
similarity index 100%
rename from docs/static/.nojekyll
rename to docusaurus/static/.nojekyll
diff --git a/docs/static/img/docusaurus-social-card.jpg b/docusaurus/static/img/docusaurus-social-card.jpg
similarity index 100%
rename from docs/static/img/docusaurus-social-card.jpg
rename to docusaurus/static/img/docusaurus-social-card.jpg
diff --git a/docs/static/img/docusaurus.png b/docusaurus/static/img/docusaurus.png
similarity index 100%
rename from docs/static/img/docusaurus.png
rename to docusaurus/static/img/docusaurus.png
diff --git a/docs/static/img/favicon.ico b/docusaurus/static/img/favicon.ico
similarity index 100%
rename from docs/static/img/favicon.ico
rename to docusaurus/static/img/favicon.ico
diff --git a/docs/static/img/logo.svg b/docusaurus/static/img/logo.svg
similarity index 100%
rename from docs/static/img/logo.svg
rename to docusaurus/static/img/logo.svg
diff --git a/docs/static/img/undraw_docusaurus_mountain.svg b/docusaurus/static/img/undraw_docusaurus_mountain.svg
similarity index 100%
rename from docs/static/img/undraw_docusaurus_mountain.svg
rename to docusaurus/static/img/undraw_docusaurus_mountain.svg
diff --git a/docs/static/img/undraw_docusaurus_react.svg b/docusaurus/static/img/undraw_docusaurus_react.svg
similarity index 100%
rename from docs/static/img/undraw_docusaurus_react.svg
rename to docusaurus/static/img/undraw_docusaurus_react.svg
diff --git a/docs/static/img/undraw_docusaurus_tree.svg b/docusaurus/static/img/undraw_docusaurus_tree.svg
similarity index 100%
rename from docs/static/img/undraw_docusaurus_tree.svg
rename to docusaurus/static/img/undraw_docusaurus_tree.svg
diff --git a/package.json b/package.json
index bcb18ae5..92ee4c2f 100755
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
"dev": "npm run dev:client & npm run dev:server",
"dev:server": "cd packages/server && npm run dev",
"dev:client": "cd packages/app && npm run dev",
+ "setup:server": "cd packages/server && npm run setup",
"postinstall": "cd packages/app && npm install && cd ../server && npm install"
},
"_web_app_path": "packages/app"
diff --git a/packages/app/src/layouts/components/@mobile/bottomBar/index.jsx b/packages/app/src/layouts/components/@mobile/bottomBar/index.jsx
index a15ddca1..301819c1 100755
--- a/packages/app/src/layouts/components/@mobile/bottomBar/index.jsx
+++ b/packages/app/src/layouts/components/@mobile/bottomBar/index.jsx
@@ -84,7 +84,7 @@ const PlayerButton = (props) => {
}
}, [currentManifest])
- const isPlaying = player?.playback_status === "playing" ?? false
+ const isPlaying = player && player?.playback_status === "playing"
return (
path.replace(/^\/api/, ""),
hostRewrite: true,
changeOrigin: true,
@@ -50,11 +48,23 @@ const config = {
},
}
-// if (fs.existsSync(sslDirPath)) {
-// config.server.https = {
-// key: path.join(__dirname, ".ssl", "privkey.pem"),
-// cert: path.join(__dirname, ".ssl", "cert.pem"),
-// }
-// }
+if (fs.existsSync(sslDirPath)) {
+ const keyPath = path.join(sslDirPath, "privkey.pem")
+ const certPath = path.join(sslDirPath, "cert.pem")
+
+ if (fs.existsSync(keyPath) && fs.existsSync(certPath)) {
+ console.info(`Starting server on SSL mode > [${sslDirPath}]`)
+
+ config.server.proxy["/api"].target = "https://0.0.0.0:9000"
+ config.server.https = {
+ key: keyPath,
+ cert: certPath,
+ }
+ } else {
+ console.error(
+ `SSL path finded, but some files are missing. Disabling ssl mode.\nRequired files:\n\t${keyPath}\n\t${certPath}`,
+ )
+ }
+}
export default defineConfig(config)
diff --git a/packages/server/.env-example b/packages/server/.env-example
index 991ba4a9..2b651942 100755
--- a/packages/server/.env-example
+++ b/packages/server/.env-example
@@ -38,4 +38,7 @@ SMTP_HOSTNAME="mail.example.com"
SMTP_PASSWORD=""
SMTP_PORT=587
SMTP_SECURE=false
-SMTP_USERNAME="noreply@example.com"
\ No newline at end of file
+SMTP_USERNAME="noreply@example.com"
+
+# Gateway configuration
+GATEWAY_MODE=nginx
diff --git a/packages/server/classes/ComtyClient/index.js b/packages/server/classes/ComtyClient/index.js
deleted file mode 100755
index 0a8fbfdf..00000000
--- a/packages/server/classes/ComtyClient/index.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import createClient from "comty.js"
-
-export default (params = {}) => {
- return createClient({
- ...params,
- accessKey: process.env.COMTY_ACCESS_KEY,
- privateKey: process.env.COMTY_PRIVATE_KEY,
- })
-}
\ No newline at end of file
diff --git a/packages/server/classes/Errors/index.js b/packages/server/classes/Errors/index.js
deleted file mode 100755
index bc95a60e..00000000
--- a/packages/server/classes/Errors/index.js
+++ /dev/null
@@ -1,84 +0,0 @@
-export class AuthorizationError extends Error {
- constructor(req, res, message = "This endpoint requires authorization") {
- super(message)
- this.name = "AuthorizationError"
-
- if (req && res) {
- return res.status(this.constructor.statusCode).json({
- error: message,
- })
- }
- }
-
- static get statusCode() {
- return 401
- }
-}
-
-export class NotFoundError extends Error {
- constructor(req, res, message = "Not found") {
- super(message)
- this.name = "NotFoundError"
-
- if (req && res) {
- return res.status(this.constructor.statusCode).json({
- error: message,
- })
- }
- }
-
- static get statusCode() {
- return 404
- }
-}
-
-export class PermissionError extends Error {
- constructor(req, res, message = "You don't have permission to do this") {
- super(message)
- this.name = "PermissionError"
-
- if (req && res) {
- return res.status(this.constructor.statusCode).json({
- error: message,
- })
- }
- }
-
- static get statusCode() {
- return 403
- }
-}
-
-export class BadRequestError extends Error {
- constructor(req, res, message = "Bad request") {
- super(message)
- this.name = "BadRequestError"
-
- if (req && res) {
- return res.status(this.constructor.statusCode).json({
- error: message,
- })
- }
- }
-
- static get statusCode() {
- return 400
- }
-}
-
-export class InternalServerError extends Error {
- constructor(req, res, message = "Internal server error") {
- super(message)
- this.name = "InternalServerError"
-
- if (req && res) {
- return res.status(this.constructor.statusCode).json({
- error: message,
- })
- }
- }
-
- static get statusCode() {
- return 500
- }
-}
\ No newline at end of file
diff --git a/packages/server/classes/SecureEntry/index.js b/packages/server/classes/SecureEntry/index.js
deleted file mode 100644
index e7591da0..00000000
--- a/packages/server/classes/SecureEntry/index.js
+++ /dev/null
@@ -1,133 +0,0 @@
-import crypto from "crypto"
-
-export default class SecureEntry {
- constructor(model, params = {}) {
- this.params = params
-
- if (!model) {
- throw new Error("Missing model")
- }
-
- this.model = model
- }
-
- static get encrytionAlgorithm() {
- return "aes-256-cbc"
- }
-
- async set(key, value, {
- keyName = "key",
- valueName = "value",
- }) {
- if (!keyName) {
- throw new Error("Missing keyName")
- }
-
- if (!valueName) {
- throw new Error("Missing valueName")
- }
-
- if (!key) {
- throw new Error("Missing key")
- }
-
- if (!value) {
- throw new Error("Missing value")
- }
-
- let entry = await this.model.findOne({
- [keyName]: key,
- [valueName]: value,
- }).catch(() => null)
-
- const encryptionKey = Buffer.from(process.env.SYNC_ENCRIPT_SECRET, "hex")
- const iv = crypto.randomBytes(16)
-
- const cipher = crypto.createCipheriv(SecureEntry.encrytionAlgorithm, encryptionKey, iv)
-
- let encryptedData
-
- try {
- encryptedData = cipher.update(value)
- }
- catch (error) {
- console.error(error)
- }
-
- encryptedData = Buffer.concat([encryptedData, cipher.final()])
-
- value = iv.toString("hex") + ":" + encryptedData.toString("hex")
-
- if (entry) {
- entry[valueName] = value
-
- await entry.save()
-
- return entry
- }
-
- entry = new this.model({
- [keyName]: key,
- [valueName]: value,
- })
-
- await entry.save()
-
- return entry
- }
-
- async get(key, value, {
- keyName = "key",
- valueName = "value",
- }) {
- if (!keyName) {
- throw new Error("Missing keyName")
- }
- if (!key) {
- throw new Error("Missing key")
- }
-
- const searchQuery = {
- [keyName]: key,
- }
-
- if (value) {
- searchQuery[valueName] = value
- }
-
- const entry = await this.model.findOne(searchQuery).catch(() => null)
-
- if (!entry || !entry[valueName]) {
- return null
- }
-
- const encryptionKey = Buffer.from(process.env.SYNC_ENCRIPT_SECRET, "hex")
-
- const iv = Buffer.from(entry[valueName].split(":")[0], "hex")
- const encryptedText = Buffer.from(entry[valueName].split(":")[1], "hex")
-
- const decipher = crypto.createDecipheriv(SecureEntry.encrytionAlgorithm, encryptionKey, iv)
-
- let decrypted = decipher.update(encryptedText)
-
- decrypted = Buffer.concat([decrypted, decipher.final()])
-
- return decrypted.toString()
- }
-
- async deleteByID(_id) {
- if (!_id) {
- throw new Error("Missing _id")
- }
-
- const entry = await this.model.findById(_id).catch(() => null)
-
- if (!entry) {
- return null
- }
-
- await entry.delete()
-
- return entry
- }
-}
\ No newline at end of file
diff --git a/packages/server/classes/SecureSyncEntry/index.js b/packages/server/classes/SecureSyncEntry/index.js
deleted file mode 100755
index 3bd86c48..00000000
--- a/packages/server/classes/SecureSyncEntry/index.js
+++ /dev/null
@@ -1,134 +0,0 @@
-import { SyncEntry } from "../../db_models"
-
-import crypto from "crypto"
-
-export default class SecureSyncEntry {
- static get encrytionAlgorithm() {
- return "aes-256-cbc"
- }
-
- static async set(user_id, key, value) {
- if (!user_id) {
- throw new Error("Missing user_id")
- }
-
- if (!key) {
- throw new Error("Missing key")
- }
-
- if (!value) {
- throw new Error("Missing value")
- }
-
- let entry = await SyncEntry.findOne({
- user_id,
- key,
- }).catch(() => null)
-
- const encryptionKey = Buffer.from(process.env.SYNC_ENCRIPT_SECRET, "hex")
- const iv = crypto.randomBytes(16)
-
- const cipher = crypto.createCipheriv(SecureSyncEntry.encrytionAlgorithm, encryptionKey, iv)
-
- let encrypted
-
- try {
- encrypted = cipher.update(value)
- }
- catch (error) {
- console.error(error)
- }
-
- encrypted = Buffer.concat([encrypted, cipher.final()])
-
- if (entry) {
- entry.value = iv.toString("hex") + ":" + encrypted.toString("hex")
-
- await entry.save()
-
- return entry
- }
-
- entry = new SyncEntry({
- user_id,
- key,
- value: iv.toString("hex") + ":" + encrypted.toString("hex"),
- })
-
- await entry.save()
-
- return entry
- }
-
- static async get(user_id, key) {
- if (!user_id) {
- throw new Error("Missing user_id")
- }
-
- if (!key) {
- throw new Error("Missing key")
- }
-
- const entry = await SyncEntry.findOne({
- user_id,
- key,
- }).catch(() => null)
-
- if (!entry) {
- return null
- }
-
- const encryptionKey = Buffer.from(process.env.SYNC_ENCRIPT_SECRET, "hex")
-
- const iv = Buffer.from(entry.value.split(":")[0], "hex")
- const encryptedText = Buffer.from(entry.value.split(":")[1], "hex")
-
- const decipher = crypto.createDecipheriv(SecureSyncEntry.encrytionAlgorithm, encryptionKey, iv)
-
- let decrypted = decipher.update(encryptedText)
-
- decrypted = Buffer.concat([decrypted, decipher.final()])
-
- return decrypted.toString()
- }
-
- static async delete(user_id, key) {
- if (!user_id) {
- throw new Error("Missing user_id")
- }
-
- if (!key) {
- throw new Error("Missing key")
- }
-
- const entry = await SyncEntry.findOne({
- user_id,
- key,
- }).catch(() => null)
-
- if (!entry) {
- return null
- }
-
- await entry.delete()
-
- return entry
- }
-
- static async has(user_id, key) {
- if (!user_id) {
- throw new Error("Missing user_id")
- }
-
- if (!key) {
- throw new Error("Missing key")
- }
-
- const entry = await SyncEntry.findOne({
- user_id,
- key,
- }).catch(() => null)
-
- return !!entry
- }
-}
\ No newline at end of file
diff --git a/packages/server/gateway/index.js b/packages/server/gateway/index.js
index e6c30a52..42f4f4e2 100755
--- a/packages/server/gateway/index.js
+++ b/packages/server/gateway/index.js
@@ -20,15 +20,12 @@ import * as Managers from "./managers"
global.debugFlag = process.env.DEBUG === "true"
const isProduction = process.env.NODE_ENV === "production"
-const sslKey = path.resolve(process.cwd(), ".ssl", "privkey.pem")
-const sslCert = path.resolve(process.cwd(), ".ssl", "cert.pem")
-
/**
* Gateway class - Main entry point for the service orchestrator
* Manages service discovery, spawning, and communication
*/
export default class Gateway {
- static gatewayMode = process.env.GATEWAY_MODE ?? "http_proxy"
+ static gatewayMode = process.env.GATEWAY_MODE ?? "nginx"
eventBus = new EventEmitter()
@@ -382,8 +379,8 @@ export default class Gateway {
this.gateway = new Managers[this.constructor.gatewayMode]({
port: this.state.proxyPort,
internalIp: this.state.internalIp,
- cert_file_name: sslCert,
- key_file_name: sslKey,
+ key_file_name: process.env.GATEWAY_SSL_KEY,
+ cert_file_name: process.env.GATEWAY_SSL_CERT,
})
if (typeof this.gateway.initialize === "function") {
diff --git a/packages/server/gateway/managers/nginx/index.js b/packages/server/gateway/managers/nginx/index.js
index 8511c16d..8681c088 100755
--- a/packages/server/gateway/managers/nginx/index.js
+++ b/packages/server/gateway/managers/nginx/index.js
@@ -7,10 +7,6 @@ import defaults from "linebridge/dist/defaults"
const localNginxBinary = path.resolve(process.cwd(), "nginx-bin")
const serverPkg = require("../../../package.json")
-/**
- * NginxManager - Optimized version that batches configurations
- * Waits for all services to register before applying configuration
- */
export default class NginxManager {
constructor(options = {}) {
this.options = options
diff --git a/packages/server/package.json b/packages/server/package.json
index 76062234..9a63d142 100755
--- a/packages/server/package.json
+++ b/packages/server/package.json
@@ -7,8 +7,9 @@
"services/*"
],
"scripts": {
- "start:prod": "cross-env NODE_ENV=production linebridge-boot ./start.js",
- "dev": "cross-env NODE_ENV=development hermes-node ./start.js"
+ "start:prod": "cross-env NODE_ENV=production hermes-node ./start.js",
+ "dev": "cross-env NODE_ENV=development hermes-node ./start.js",
+ "setup": "./boot scripts/setup/index.js"
},
"dependencies": {
"@grpc/grpc-js": "^1.13.2",
@@ -23,7 +24,6 @@
"bullmq": "^5.41.5",
"chalk": "^5.4.1",
"chokidar": "^4.0.3",
- "comty.js": "^0.61.0",
"cross-env": "^7.0.3",
"http-proxy": "^1.18.1",
"jsonwebtoken": "^9.0.2",
diff --git a/packages/server/scripts/installNginxStatic.sh b/packages/server/scripts/installNginxStatic.sh
new file mode 100755
index 00000000..9b694461
--- /dev/null
+++ b/packages/server/scripts/installNginxStatic.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+FORCE_OVERWRITE=false
+for arg in "$@"; do
+ if [ "$arg" == "-y" ]; then
+ FORCE_OVERWRITE=true
+ break
+ fi
+done
+
+NGINX_VERSION="1.26.3"
+ARCH="$(dpkg --print-architecture)"
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+OUTPUTBIN="${SCRIPT_DIR}/../nginx-bin"
+
+if [ "$ARCH" = "arm64" ]; then
+ NGINX_ARCH="aarch64";
+elif [ "$ARCH" = "amd64" ]; then
+ NGINX_ARCH="x86_64";
+else
+ echo "Unsupported architecture: $ARCH";
+ exit 1;
+fi
+
+NGINX_BINARY_URL="https://jirutka.github.io/nginx-binaries/nginx-${NGINX_VERSION}-${NGINX_ARCH}-linux"
+
+if [ -f "${OUTPUTBIN}" ]; then
+ if [ "$FORCE_OVERWRITE" = true ]; then
+ echo "'-y' flag detected. Overwriting '${OUTPUTBIN}'."
+ else
+ read -r -p "File '${OUTPUTBIN}' already exists. Overwrite? (y/N) " response
+ if [[ ! "$response" =~ ^([yY])$ ]]; then
+ echo "Skipping download."
+ exit 0
+ fi
+ fi
+fi
+
+curl -L "${NGINX_BINARY_URL}" -o "${OUTPUTBIN}"
+
+chmod +x "${OUTPUTBIN}"
+
+"${OUTPUTBIN}" -v;
diff --git a/packages/server/scripts/migrations/removeDuplicateTracks.js b/packages/server/scripts/migrations/removeDuplicateTracks.js
index 4b954192..f3687406 100644
--- a/packages/server/scripts/migrations/removeDuplicateTracks.js
+++ b/packages/server/scripts/migrations/removeDuplicateTracks.js
@@ -22,7 +22,7 @@ async function main() {
!track.source.startsWith("http")
) {
console.warn(
- ` Skipping track ID ${track._id} due to invalid or missing source URL: "${track.source}"`,
+ `Skipping track ID ${track._id} due to invalid or missing source URL: "${track.source}"`,
)
continue
}
@@ -31,19 +31,18 @@ async function main() {
try {
console.log(
- ` [${index + 1}/${tracks.length}] Fetching ETag for source: ${track.source} (Track ID: ${track._id})`,
+ `[${index + 1}/${tracks.length}] Fetching ETag for source: ${track.source} (Track ID: ${track._id})`,
)
+
const response = await axios.head(track.source, {
timeout: 10000, // 10 seconds timeout
- // Add headers to mimic a browser to avoid some 403s or other blocks
headers: {
- "User-Agent":
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
- Accept: "*/*", // More generic accept for HEAD
+ Accept: "*/*",
"Accept-Encoding": "gzip, deflate, br",
Connection: "keep-alive",
},
})
+
// ETag header can be 'etag' or 'ETag' (case-insensitive)
const etag = response.headers["etag"] || response.headers["ETag"]
@@ -52,7 +51,6 @@ async function main() {
tracksByETag.set(etag, [])
}
tracksByETag.get(etag).push(track)
- // console.log(` ETag: ${etag} found for source: ${track.source}`)
} else {
console.warn(
` No ETag found for source: ${track.source} (Track ID: ${track._id})`,
@@ -60,19 +58,16 @@ async function main() {
}
} catch (error) {
let errorMessage = error.message
+
if (error.response) {
- // The request was made and the server responded with a status code
- // that falls out of the range of 2xx
errorMessage = `Server responded with status ${error.response.status} ${error.response.statusText}`
} else if (error.request) {
- // The request was made but no response was received
errorMessage =
"No response received from server (e.g., timeout, network error)"
}
- // else: Something happened in setting up the request that triggered an Error
console.error(
- ` Error fetching ETag for ${track.source} (Track ID: ${track._id}): ${errorMessage}`,
+ `Error fetching ETag for ${track.source} (Track ID: ${track._id}): ${errorMessage}`,
)
}
}
@@ -97,21 +92,21 @@ async function main() {
)
const trackToKeep = tracksForETag[0]
- const tracksToDelete = tracksForETag.slice(1) // All tracks except the newest one
+ const tracksToDelete = tracksForETag.slice(1)
if (tracksToDelete.length > 0) {
const idsToDelete = tracksToDelete.map((track) => track._id)
console.log(
- ` Keeping Track ID: ${trackToKeep._id} (Source: ${trackToKeep.source}) - selected due to largest _id (assumed newer).`,
+ `Keeping Track ID: ${trackToKeep._id} (Source: ${trackToKeep.source}) - selected due to largest _id (assumed newer).`,
)
tracksToDelete.forEach((t) => {
console.log(
- ` Marking for deletion: Track ID: ${t._id} (Source: ${t.source})`,
+ `Marking for deletion: Track ID: ${t._id} (Source: ${t.source})`,
)
})
console.log(
- ` Attempting to delete ${idsToDelete.length} duplicate tracks for ETag: "${etag}"`,
+ `Attempting to delete ${idsToDelete.length} duplicate tracks for ETag: "${etag}"`,
)
try {
@@ -121,22 +116,23 @@ async function main() {
if (deleteResult.deletedCount > 0) {
console.log(
- ` Successfully deleted ${deleteResult.deletedCount} tracks for ETag: "${etag}"`,
+ `Successfully deleted ${deleteResult.deletedCount} tracks for ETag: "${etag}"`,
)
deletedCount += deleteResult.deletedCount
} else {
console.warn(
- ` Deletion command executed for ETag "${etag}", but no tracks were deleted. IDs: ${idsToDelete.join(", ")}`,
+ `Deletion command executed for ETag "${etag}", but no tracks were deleted. IDs: ${idsToDelete.join(", ")}`,
)
}
} catch (dbError) {
console.error(
- ` Database error deleting tracks for ETag "${etag}": ${dbError.message}`,
+ `Database error deleting tracks for ETag "${etag}": ${dbError.message}`,
)
}
}
}
}
+
console.log(`Finished processing. Total tracks deleted: ${deletedCount}.`)
}
diff --git a/packages/server/scripts/setup/index.js b/packages/server/scripts/setup/index.js
new file mode 100644
index 00000000..3d4f7f77
--- /dev/null
+++ b/packages/server/scripts/setup/index.js
@@ -0,0 +1,119 @@
+import DbManager from "@shared-classes/DbManager"
+import { Config } from "@db_models"
+
+import fs from "node:fs/promises"
+import path from "node:path"
+
+const forceFlag = process.argv.includes("--force")
+
+const tasksPath = path.resolve(__dirname, "./tasks")
+
+async function main() {
+ if (
+ process.env.INFISICAL_CLIENT_ID &&
+ process.env.INFISICAL_CLIENT_SECRET
+ ) {
+ console.log(
+ `[BOOT] INFISICAL Credentials found, injecting env variables from INFISICAL...`,
+ )
+ await global.injectEnvFromInfisical()
+ }
+
+ // create the context for tasks
+ global.db = new DbManager()
+
+ await global.db.initialize()
+
+ let serverConfig = await Config.findOne({ key: "server" }).catch(() => {
+ return false
+ })
+
+ if (serverConfig && serverConfig.value.setup === true && !forceFlag) {
+ console.log(
+ `Server is already setup (last run at ${serverConfig.value.updated_at}), skipping setup...\nUse --force to force setup.`,
+ )
+ return process.exit(0)
+ }
+
+ let tasks = await fs.readdir(tasksPath)
+
+ // filter only files ends with .js
+ tasks = tasks.filter((task) => task.endsWith(".js"))
+
+ // sort by first numbers in file
+ tasks = tasks.sort((a, b) => {
+ const aNum = parseInt(a.split(".")[0])
+ const bNum = parseInt(b.split(".")[0])
+
+ return aNum - bNum
+ })
+
+ console.log(`Total (${tasks.length}) tasks...`)
+
+ for await (const task of tasks) {
+ const taskIndex = tasks.indexOf(task) + 1
+
+ let taskObj = await import(path.resolve(tasksPath, task))
+
+ taskObj = taskObj.default ?? taskObj
+
+ if (typeof taskObj.fn !== "function") {
+ console.log(`[ERROR] [${task}] has not a function, skipping...`)
+ continue
+ }
+
+ try {
+ console.log(
+ `[INFO] Executing [${taskIndex}/${tasks.length}](${task})`,
+ )
+
+ if (taskObj.description) {
+ console.log(`[INFO] ${taskObj.description}`)
+ }
+
+ await taskObj.fn()
+ } catch (error) {
+ console.log(`[ERROR] ${task} failed to execute`)
+ console.log(error)
+
+ if (taskObj.crashOnError === true) {
+ console.log(`[ERROR] ${task} crashed, exiting...`)
+ process.exit(1)
+ }
+
+ continue
+ }
+
+ console.log(`[SUCCESS] ${task} executed successfully`)
+ }
+
+ console.log("All tasks executed successfully!")
+
+ if (serverConfig) {
+ console.log("Updating server configuration document...")
+
+ await Config.findOneAndUpdate(
+ { _id: serverConfig._id.toString() },
+ {
+ key: "server",
+ value: {
+ setup: true,
+ updated_at: new Date(),
+ },
+ },
+ )
+ } else {
+ console.log("Creating server configuration document...")
+
+ await Config.create({
+ key: "server",
+ value: {
+ setup: false,
+ },
+ })
+ }
+
+ process.exit(0)
+}
+
+main()
diff --git a/packages/server/scripts/setup/tasks/00.root-user.js b/packages/server/scripts/setup/tasks/00.root-user.js
new file mode 100644
index 00000000..779787f2
--- /dev/null
+++ b/packages/server/scripts/setup/tasks/00.root-user.js
@@ -0,0 +1,39 @@
+import { User } from "@db_models"
+import bcrypt from "bcrypt"
+
+export default {
+ description: "Create first root user",
+ fn: async () => {
+ // check if any user with includes admin role exists
+ const adminUser = await User.find({
+ $or: [{ roles: { $in: ["admin"] } }],
+ })
+
+ if (adminUser.length > 0) {
+ console.log("Admin user already exists")
+ return true
+ }
+
+ const defaultUsername = "root"
+ const defaultPwd = "changemeorgethacked"
+
+ let user = new User({
+ username: defaultUsername,
+ password: await bcrypt.hash(defaultPwd, 6),
+ email: "example@comty.app",
+ roles: ["admin"],
+ created_at: new Date().getTime(),
+ accept_tos: true,
+ activated: true,
+ })
+
+ await user.save()
+
+ console.log(
+ `Root user created. Username: ${defaultUsername}, password: ${defaultPwd}\nPlease change the password after first login!!.`,
+ )
+
+ return true
+ },
+ crashOnFail: true,
+}
diff --git a/packages/server/services/main/main.service.js b/packages/server/services/main/main.service.js
index 817f6a22..6fdbe9c9 100755
--- a/packages/server/services/main/main.service.js
+++ b/packages/server/services/main/main.service.js
@@ -1,8 +1,6 @@
import { Server } from "linebridge"
import DbManager from "@shared-classes/DbManager"
-import StartupDB from "./startup_db"
-
import SharedMiddlewares from "@shared-middlewares"
export default class API extends Server {
@@ -25,7 +23,6 @@ export default class API extends Server {
async onInitialize() {
await this.contexts.db.initialize()
- await StartupDB()
}
}
diff --git a/packages/server/services/main/setup/authorizeSelfServerToken/index.js b/packages/server/services/main/setup/authorizeSelfServerToken/index.js
deleted file mode 100755
index 84087e0b..00000000
--- a/packages/server/services/main/setup/authorizeSelfServerToken/index.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import SecureEntry from "@lib/secureEntry"
-import { authorizedServerTokens } from "@db_models"
-
-const rootClientID = "00000000-0000-0000-000000000000"
-
-export default async () => {
- // check if process.env.SERVER_TOKEN is included in authorizedServerKeys
- if (process.env.SERVER_TOKEN) {
- console.log("Checking if server token is authorized on server tokens list...")
-
- const secureEntries = new SecureEntry(authorizedServerTokens)
-
- const currentServerToken = await secureEntries.get(rootClientID, undefined, {
- keyName: "client_id",
- })
-
- // check if match or not exist, if not, update
- if (currentServerToken !== process.env.SERVER_TOKEN) {
- console.log("Server token is not authorized on server tokens list, updating...")
-
- await secureEntries.set(rootClientID, process.env.SERVER_TOKEN, {
- keyName: "client_id",
- valueName: "token",
- })
- }
-
- return true
- }
-}
\ No newline at end of file
diff --git a/packages/server/services/main/setup/dbAdmin/index.js b/packages/server/services/main/setup/dbAdmin/index.js
deleted file mode 100755
index de513af3..00000000
--- a/packages/server/services/main/setup/dbAdmin/index.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import { User } from "@db_models"
-import createUser from "@controllers/UserController/services/createUser"
-
-export default async () => {
- // check if any user with includes admin role exists
- const adminUser = await User.find({
- $or: [
- { roles: { $in: ["admin"] } },
- ],
- })
-
- // if no user with admin role exists, create one
- if (adminUser.length === 0) {
- console.log("Creating admin user...")
-
- await createUser({
- username: "admin",
- password: "admin",
- email: "admin@admin.com",
- roles: ["admin"],
- })
-
- console.log("Admin user created!")
- }
-}
\ No newline at end of file
diff --git a/packages/server/services/main/setup/index.js b/packages/server/services/main/setup/index.js
deleted file mode 100755
index 6692cffd..00000000
--- a/packages/server/services/main/setup/index.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { default as dbAdmin } from "./dbAdmin"
-import { default as authorizeSelfServerToken } from "./authorizeSelfServerToken"
-
-// set here the setup functions
-export default [
- dbAdmin,
- authorizeSelfServerToken,
-]
\ No newline at end of file
diff --git a/packages/server/services/main/startup_db.js b/packages/server/services/main/startup_db.js
deleted file mode 100644
index e43a7835..00000000
--- a/packages/server/services/main/startup_db.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import { Config } from "@db_models"
-
-export default async () => {
- let serverConfig = await Config.findOne({ key: "server" }).catch(() => {
- return false
- })
-
- if (!serverConfig) {
- console.log("Server config DB is not created, creating it...")
-
- serverConfig = new Config({
- key: "server",
- value: {
- setup: false,
- },
- })
-
- await serverConfig.save()
- }
-
- const setupScriptsCompleted = (serverConfig.value?.setup) ?? false
-
- if (!setupScriptsCompleted) {
- console.log("β οΈ Server setup is not complete, running setup proccess.")
-
- let setupScript = await import("./setup")
- setupScript = setupScript.default ?? setupScript
-
- try {
- for await (let script of setupScript) {
- await script()
- }
-
- console.log("β
Server setup complete.")
-
- await Config.updateOne({ key: "server" }, { value: { setup: true } })
-
- serverConfig = await Config.findOne({ key: "server" })
-
- return resolve()
- } catch (error) {
- console.log("β Server setup failed.")
- console.error(error)
- process.exit(1)
- }
- }
-}
\ No newline at end of file
diff --git a/packages/server/start.js b/packages/server/start.js
index 86275ddb..f3686dd2 100644
--- a/packages/server/start.js
+++ b/packages/server/start.js
@@ -1,3 +1,24 @@
+import fs from "node:fs"
+import path from "node:path"
+
import Gateway from "./gateway"
-new Gateway().initialize()
\ No newline at end of file
+const rootSSLDirPath = path.resolve(__dirname, "../../", ".ssl")
+const cwdSSLDirPath = path.resolve(__dirname, ".ssl")
+
+if (fs.existsSync(rootSSLDirPath) || fs.existsSync(cwdSSLDirPath)) {
+ const rootKeyPath = path.resolve(rootSSLDirPath, "privkey.pem")
+ const rootCertPath = path.resolve(rootSSLDirPath, "cert.pem")
+ const cwdKeyPath = path.resolve(cwdSSLDirPath, "privkey.pem")
+ const cwdCertPath = path.resolve(cwdSSLDirPath, "cert.pem")
+
+ if (fs.existsSync(rootKeyPath) && fs.existsSync(rootCertPath)) {
+ process.env.GATEWAY_SSL_KEY = rootKeyPath
+ process.env.GATEWAY_SSL_CERT = rootCertPath
+ } else if (fs.existsSync(cwdKeyPath) && fs.existsSync(cwdCertPath)) {
+ process.env.GATEWAY_SSL_KEY = cwdKeyPath
+ process.env.GATEWAY_SSL_CERT = cwdCertPath
+ }
+}
+
+new Gateway().initialize()