diff --git a/@types/Other.ts b/@types/Other.ts index d325e80..20c451d 100644 --- a/@types/Other.ts +++ b/@types/Other.ts @@ -48,5 +48,5 @@ export type SignupCode = { export type IPCMessage = { _id?: string, - [key: string]: string | number | object | undefined + [key: string]: string | number | object | boolean | undefined } \ No newline at end of file diff --git a/package.json b/package.json index a79d947..3084931 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "@types/cors": "^2.8.13", "@types/express-fileupload": "^1.4.1", "@types/express-session": "^1.17.7", - "@types/node": "^18.15.11", + "@types/node": "^20.4.2", "@types/passport-local": "^1.0.35", "@types/qrcode": "^1.5.0", "argon2": "^0.30.3", diff --git a/src/controller/BaseCommand.ts b/src/controller/BaseCommand.ts index 9934bb3..2294e18 100644 --- a/src/controller/BaseCommand.ts +++ b/src/controller/BaseCommand.ts @@ -4,13 +4,17 @@ import Controller from './Controller.js'; abstract class BaseCommand extends Command { - controller: Controller; + #controller: Controller; constructor (controller: Controller, opts: CommandDefinition) { super(opts); - this.controller = controller; + this.#controller = controller; } abstract override execute(message: unknown, args?: unknown): Promise; + protected get controller () + { + return this.#controller; + } } export default BaseCommand; \ No newline at end of file diff --git a/src/controller/Controller.ts b/src/controller/Controller.ts index 0ddd8f1..09e84b2 100644 --- a/src/controller/Controller.ts +++ b/src/controller/Controller.ts @@ -69,6 +69,9 @@ class Controller extends EventEmitter this.#serverFilePath = path.resolve(this.#srcDir, options.serverFilePath); this.#shards = new Collection(); + if (options.env.HTTP_PORT) + this.#options.serverOptions.http.port = parseInt(options.env.HTTP_PORT); + process.on('warning', (warn) => { this.#logger.warn(warn.stack || warn.message); @@ -115,6 +118,21 @@ class Controller extends EventEmitter return this.#srcDir; } + get domain () + { + return this.#options.serverOptions.domain ?? `localhost:${this.port}`; + } + + get protocol () + { + return this.#options.serverOptions.domain ? 'https' : 'http'; + } + + get port () + { + return this.#options.serverOptions.http.port; + } + async init (): Promise { diff --git a/src/controller/commands/Bootstrap.ts b/src/controller/commands/Bootstrap.ts deleted file mode 100644 index 0c319a0..0000000 --- a/src/controller/commands/Bootstrap.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ArgsResult } from '@navy.gif/commandparser'; -import BaseCommand from '../BaseCommand.js'; -import Controller from '../Controller.js'; - -class BootstrapCommand extends BaseCommand -{ - - constructor (controller: Controller) - { - super(controller, { - name: 'bootstrap', - options: [] - }); - } - - override execute (_message: unknown, _args?: ArgsResult): Promise - { - throw new Error('Method not implemented.'); - } - -} - -export default BootstrapCommand; \ No newline at end of file diff --git a/src/controller/commands/Create.ts b/src/controller/commands/Create.ts index d59d97d..1cc13f4 100644 --- a/src/controller/commands/Create.ts +++ b/src/controller/commands/Create.ts @@ -23,7 +23,7 @@ class CreateCommand extends BaseCommand defaultValue: 1 }] }, { - name: 'account', + name: 'user', type: OptionType.SUB_COMMAND, options: [{ name: 'name', @@ -31,6 +31,12 @@ class CreateCommand extends BaseCommand }, { name: 'password', type: OptionType.STRING + }, { + name: 'admin', + type: OptionType.BOOLEAN, + flag: true, + valueOptional: true, + defaultValue: true }] }] }); @@ -42,7 +48,7 @@ class CreateCommand extends BaseCommand if (subcommand === 'registration-code') return this.#code(args); - else if (subcommand === 'account') + else if (subcommand === 'user') return this.#account(args); return 'Unknown subcommand'; @@ -50,13 +56,16 @@ class CreateCommand extends BaseCommand async #account (args: ArgsResult) { - const { name, password } = args; - let accountName = 'admin'; - let accountPass = Util.randomString(); + const { name, password, admin } = args; + let accountName = 'admin', + accountPass = Util.randomString(), + isAdmin = false; if (name) accountName = name.value as string; if (password) accountPass = password.value as string; + if (admin) + isAdmin = admin.value as boolean; const shard = this.controller.shards.random(); if (!shard) @@ -65,7 +74,8 @@ class CreateCommand extends BaseCommand const msg = { type: 'account-create', accountName, - accountPass + accountPass, + isAdmin }; const response = await shard.send(msg, true) as IPCMessage; if (response.success) @@ -87,11 +97,12 @@ class CreateCommand extends BaseCommand return 'Did not get a response from shard'; const codes = response.codes as SignupCode[]; - let out = `Created codes, valid until ${new Date(codes[0].created + codes[0].validFor).toUTCString()}:\n`; + const out = `Created codes, valid until ${new Date(codes[0].created + codes[0].validFor).toUTCString()}:\n`; + const codesOut = []; for (const invite of codes) - out += `${invite.code}\n`; + codesOut.push(`${this.controller.protocol}://${this.controller.domain}/register?code=${invite.code}`); - return out; + return out + codesOut.join('\n'); } } diff --git a/src/server/Server.ts b/src/server/Server.ts index 267f803..1c76976 100644 --- a/src/server/Server.ts +++ b/src/server/Server.ts @@ -86,7 +86,6 @@ class Server extends EventEmitter MONGO_MEMORY_URI, MONGO_MEMORY_HOST, MONGO_MEMORY_USER, MONGO_MEMORY_PORT, MONGO_MEMORY_PASS, MONGO_MEMORY_DB, MONGO_MEMORY_AUTH_DB, RABBIT_HOST, RABBIT_USER, RABBIT_PASS, RABBIT_VHOST, RABBIT_PORT, - PORT } = process.env as { [key: string]: string }; const { http: httpOpts, databases, name } = options; @@ -108,8 +107,7 @@ class Server extends EventEmitter this.#logger = new LoggerClient({ ...options.logger, name: this.constructor.name }); // Port number is automatically incremented based on shard # - const _port = parseInt(PORT); - this.#port = isNaN(_port) ? httpOpts.port + this.#shardId : _port; + this.#port = httpOpts.port + this.#shardId; // Primarily used by the OAuth methods for the callback url if (NODE_ENV === 'development') { @@ -409,11 +407,14 @@ class Server extends EventEmitter { const name = msg.accountName as string; const pass = msg.accountPass as string; + const admin = msg.isAdmin as boolean; this.#logger.info(`Creating account ${name}`); try { - await this.users.createUser(name, pass); + const user = await this.users.createUser(name, pass); process.send({ _id: msg._id, success: true }); + if (admin) + await user.updatePermissions({ administrator: { default: 10 } }); } catch (err) { diff --git a/yarn.lock b/yarn.lock index 2bed498..b468340 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2087,13 +2087,20 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:^18.15.11": +"@types/node@npm:*": version: 18.15.11 resolution: "@types/node@npm:18.15.11" checksum: 977b4ad04708897ff0eb049ecf82246d210939c82461922d20f7d2dcfd81bbc661582ba3af28869210f7e8b1934529dcd46bff7d448551400f9d48b9d3bddec3 languageName: node linkType: hard +"@types/node@npm:^20.4.2": + version: 20.4.2 + resolution: "@types/node@npm:20.4.2" + checksum: 99e544ea7560d51f01f95627fc40394c24a13da8f041121a0da13e4ef0a2aa332932eaf9a5e8d0e30d1c07106e96a183be392cbba62e8cf0bf6a085d5c0f4149 + languageName: node + linkType: hard + "@types/passport-local@npm:^1.0.35": version: 1.0.35 resolution: "@types/passport-local@npm:1.0.35" @@ -7042,7 +7049,7 @@ __metadata: "@types/cors": ^2.8.13 "@types/express-fileupload": ^1.4.1 "@types/express-session": ^1.17.7 - "@types/node": ^18.15.11 + "@types/node": ^20.4.2 "@types/passport-local": ^1.0.35 "@types/qrcode": ^1.5.0 "@typescript-eslint/eslint-plugin": ^5.58.0