From d310895fcb9c39485845fc7e8100d8f7226e9ebb Mon Sep 17 00:00:00 2001
From: mrfry <mr.fry@tutanota.com>
Date: Tue, 11 Apr 2023 10:33:52 +0200
Subject: [PATCH] added support for DOMAIN env var insted of file

---
 README.md                                | 25 ++++++++++++++----------
 scripts/setup.sh                         | 17 ++++++++++++----
 src/constants.json                       |  3 ---
 src/constants.ts                         | 15 ++++++++++++++
 src/middlewares/auth.middleware.ts       |  7 ++-----
 src/modules/api/submodules/p2p.ts        |  3 +++
 src/modules/api/submodules/qminingapi.ts |  2 +-
 src/server.ts                            |  7 +++----
 src/utils/files.ts                       |  3 +--
 9 files changed, 53 insertions(+), 29 deletions(-)
 delete mode 100644 src/constants.json
 create mode 100644 src/constants.ts

diff --git a/README.md b/README.md
index 8bfd120..ce553e8 100755
--- a/README.md
+++ b/README.md
@@ -38,17 +38,21 @@ threads, and serve more requests at once. The used cores can be limited with env
 
 Run `./scripts/setup.sh`, then `npm run dev` for development, or `npm run start` for prod.
 
-**Gitlab specific notes**: You need a gitlab account with SSH keys set up in order to be able to use
-SSH for cloning this (and any) project. This includes git modules of this project. See
-`CLONE_WITH_HTTPS` in environment variables below.
-
 On the first run there will be a number of errors, that some files weren't found. Please create them
 according to the messages, these are necessary for the server to function.
 
 There will be also a lot of information about files and other necessary things being created. **Please
 read them very carefully, you should know about what was created!**
 
-The setup script can be also used to update and rebuild all git modules.
+### Setup notes
+
+ * **Gitlab specific notes**: You need a gitlab account with SSH keys set up in order to be able to use
+   SSH for cloning this (and any) project. This includes git modules of this project. See
+   `CLONE_WITH_HTTPS` in environment variables below.
+ * The `DOMAIN` env var can be replaced by making the file `./data/domain`. This is necesarry, to make
+   xmlhttp requests and some redirects work in statically built HTML files (by next.js), in the
+   userscript, and in the server itself.
+ * The setup script can be also used to update and rebuild all git modules.
 
 ## Web server paths
 
@@ -63,12 +67,12 @@ server instances, and merge the response data to its own databases.
 To setup P2P functionality you have to create a few files in `./data/p2p`:
 
  * `selfInfo.json`: information of this peer. Required:
-    ```
+    ```json
     {
         "name": "any name you choose",
         "contact": "contact to server administrator (irc server, e-mail, anything)",
         "host": "server host (like somesite.com, without 'http(s):// and /-s')",
-        "pw": "password to the host, so the server can log in there",
+        "pw": "password to the host, so the server can log in there. Please use a dedicated password, that only the server uses!",
         "port": "server port, number"
     }
     ```
@@ -153,13 +157,14 @@ result can be found in the directory it was ran.
  | NS_LOGLEVEL | number | Debug log level, 0 is the least verbose |
  | NS_NOLOG | boolean | If logging should be skipped |
  | NS_SQL_DEBUG_LOG | boolean | If the SQL queries should be logged |
+ | DOMAIN | string | The domain that the server should use for redirects, cookies, etc. ex.: `qmining.com`, without 'https://', and '/'-s. If not specified `./data/domain` will be used |
 
-### For the setup script
+### For the setup script (`./scripts/setup.sh`)
 
  | Name | Type | Description |
  | --- | --- | --- |
  | CLONE_WITH_HTTPS | boolean | By default git clones with ssh, which can cause troubles. Set this
- to use https for git modules |
+ | DOMAIN | string | The domain that the server should use for redirects, cookies, etc. ex.: `qmining.com`, without 'https://', and '/'-s. If not specified `./data/domain` will be used |
 
 ## npm scripts
 
@@ -209,7 +214,7 @@ https://gitlab.com/MrFry/moodle-test-userscript
 │   ├── admins.json                forum admins. should be removed and should use admin column from user db
 │   ├── apiRootRedirectTo          url where domain/api should redirect to
 │   ├── dbs/                       directory for databases, and for their backups
-│   ├── domain                     the domain the server is hosted on
+│   ├── domain                     the domain the server is hosted on. Used when `DOMAIN` env var is empty
 │   ├── f/                         user files received TODO: check if this is needed
 │   ├── links.json                 urls for irc, patreon and donate
 │   ├── nolog                      ids of users separated by new lines to ignore on logging
diff --git a/scripts/setup.sh b/scripts/setup.sh
index 431be56..939689b 100755
--- a/scripts/setup.sh
+++ b/scripts/setup.sh
@@ -38,10 +38,18 @@ makeNextSubmodule() {
 checkFile "$PWD/src/server.ts"
 checkFile "$PWD/package.json"
 checkFile "$PWD/package-lock.json"
-if [ ! -f "${domainPath}" ]; then
-    error "${domainPath} does not exist!"
-    echo "Please create it, and re-run this script."
-    echo "Expected content: domain, ex.:'frylabs.net' (without http:// and /)"
+
+domain="${DOMAIN}"
+
+if [ -z "${domain}" ] && [ -f "${domainPath}" ]; then
+    domain=$(cat "${domainPath}")
+fi
+
+if [ -z "${domain}" ]; then
+    error "DOMAIN is not set, and ${domainPath} does not exist!"
+    echo "Set DOMAIN to the preferred domain"
+    echo "Or please create the file ${domainPath}, and re-run this script"
+    echo "Expected content: domain, ex.:'frylabs.net' (without 'http://' and '/')"
     exit 1
 fi
 
@@ -113,3 +121,4 @@ fi
 
 # ------------------------------------------------------------------------------------
 log "Done! development mode: 'npm run dev', prod mode: 'npm run start', tests: 'npm run test'"
+exit 0
diff --git a/src/constants.json b/src/constants.json
deleted file mode 100644
index 8a940bd..0000000
--- a/src/constants.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-    "savedQuestionsFileName": "savedQuestions.json"
-}
diff --git a/src/constants.ts b/src/constants.ts
new file mode 100644
index 0000000..eb90e87
--- /dev/null
+++ b/src/constants.ts
@@ -0,0 +1,15 @@
+import { paths } from './utils/files'
+import utils from './utils/utils'
+
+const domain = process.env.DOMAIN || utils.ReadFile(paths.domainFile).trim()
+
+if (!domain) {
+    throw new Error(
+        `Domain is undefined! Should be set with 'DOMAIN' environment variable, or written to '${paths.domainFile}'`
+    )
+}
+
+export default {
+    savedQuestionsFileName: 'savedQuestions.json',
+    domain: domain,
+}
diff --git a/src/middlewares/auth.middleware.ts b/src/middlewares/auth.middleware.ts
index 916cfb6..e9a559a 100644
--- a/src/middlewares/auth.middleware.ts
+++ b/src/middlewares/auth.middleware.ts
@@ -24,10 +24,7 @@ import type { Database } from 'better-sqlite3'
 
 import logger from '../utils/logger'
 import dbtools from '../utils/dbtools'
-import { paths } from '../utils/files'
-import utils from '../utils/utils'
-
-const domain = utils.ReadFile(paths.domainFile).trim()
+import constants from '../constants'
 
 interface Options {
     userDB: Database
@@ -56,7 +53,7 @@ function renderLogin(req: Request, res: Response) {
     } else {
         res.render('login', {
             useHttp: process.env.NS_NO_HTTPS_FORCE,
-            domain: domain,
+            domain: constants.domain,
         })
     }
 }
diff --git a/src/modules/api/submodules/p2p.ts b/src/modules/api/submodules/p2p.ts
index f3bcee2..69cbbf4 100644
--- a/src/modules/api/submodules/p2p.ts
+++ b/src/modules/api/submodules/p2p.ts
@@ -96,6 +96,7 @@ interface SyncDataRes {
 function updateThirdPartyPeers(
     newVal: Omit<PeerInfo, 'publicKey' | 'name' | 'contact'>[]
 ) {
+    // TODO: check if thirdPartyPeersFile exists!
     const prevVal = utils.ReadJSON<PeerInfo[]>(paths.thirdPartyPeersFile)
     const dataToWrite = newVal.reduce((acc, peer) => {
         const isIncluded = acc.find((x) => {
@@ -963,6 +964,7 @@ function setup(data: SubmoduleData): Submodule {
             remoteInfo: getSelfInfo(),
         }
 
+        // TODO: hostname is invalid, should be remote host?
         let hostToLog = req.hostname
         if (remoteHost) {
             const remotePeerInfo = peers.find((peer) => {
@@ -998,6 +1000,7 @@ function setup(data: SubmoduleData): Submodule {
                 )
                 if (remoteHost.includes(':')) {
                     const [host, port] = remoteHost.split(':')
+                    // TODO: add public key
                     updateThirdPartyPeers([
                         {
                             host: host,
diff --git a/src/modules/api/submodules/qminingapi.ts b/src/modules/api/submodules/qminingapi.ts
index fd12029..16313f5 100644
--- a/src/modules/api/submodules/qminingapi.ts
+++ b/src/modules/api/submodules/qminingapi.ts
@@ -60,7 +60,7 @@ import {
     SearchResultQuestion,
 } from '../../../utils/qdbUtils'
 import { paths } from '../../../utils/files'
-import constants from '../../../constants.json'
+import constants from '../../../constants'
 import {
     isJsonValidAndLogError,
     TestUsersSchema,
diff --git a/src/server.ts b/src/server.ts
index 5631b83..4f8ef43 100755
--- a/src/server.ts
+++ b/src/server.ts
@@ -42,6 +42,7 @@ import dbtools from './utils/dbtools'
 import reqlogger from './middlewares/reqlogger.middleware'
 import idStats from './utils/ids'
 import { paths, validateFiles } from './utils/files'
+import constants from './constants'
 
 const logFile = paths.logDir + logger.logFileName
 const vlogFile = paths.vlogDir + logger.logFileName
@@ -226,8 +227,6 @@ app.use(
     })
 )
 
-const domain = utils.ReadFile(paths.domainFile).trim()
-
 Object.keys(modules).forEach(function (key) {
     const module = modules[key]
     try {
@@ -240,7 +239,7 @@ Object.keys(modules).forEach(function (key) {
 
         if (mod.setup) {
             mod.setup({
-                url: domain,
+                url: constants.domain,
                 userDB: userDB,
                 publicdirs: module.publicdirs,
                 nextdir: module.nextdir,
@@ -268,7 +267,7 @@ app.get('*', (req, res) => {
     if (req.is('application/json')) {
         res.status(404).end()
     } else {
-        res.status(404).render('404', { domain: domain })
+        res.status(404).render('404', { domain: constants.domain })
     }
 })
 
diff --git a/src/utils/files.ts b/src/utils/files.ts
index ad1edfa..8910077 100644
--- a/src/utils/files.ts
+++ b/src/utils/files.ts
@@ -124,9 +124,8 @@ export const files = {
 
     domainFile: {
         path: 'data/domain',
-        errorIfMissing: true,
         description:
-            'server domain for cookies and stuff, for ex.: "frylabs.net", no "http://" and things like that, just the domain',
+            'server domain for cookies and stuff, for ex.: "qmining.com", no "http://" and things like that, just the domain',
     },
     // --------------------------------------------------------------------------------
     // stats files