From 4845bd28a13ee9b56fea89696178f7e9c6438b2a Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sun, 31 Mar 2024 21:21:10 -0400 Subject: [PATCH] Create default user --- package-lock.json | 40 ++++++++++ packages/backend/package.json | 1 + packages/backend/src/CoreModule.js | 3 + packages/backend/src/Kernel.js | 1 + .../backend/src/fun/dev-console-ui-utils.js | 32 ++++++++ .../src/services/DefaultUserService.js | 80 +++++++++++++++++++ .../backend/src/services/WebServerService.js | 16 +--- 7 files changed, 161 insertions(+), 12 deletions(-) create mode 100644 packages/backend/src/fun/dev-console-ui-utils.js create mode 100644 packages/backend/src/services/DefaultUserService.js diff --git a/package-lock.json b/package-lock.json index e1fbd60dd..0b1c28248 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9637,6 +9637,45 @@ "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", "integrity": "sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==" }, + "node_modules/string-length": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-6.0.0.tgz", + "integrity": "sha512-1U361pxZHEQ+FeSjzqRpV+cu2vTzYeWeafXFLykiFlv4Vc0n3njgU8HrMbyik5uwm77naWMuVG8fhEF+Ovb1Kg==", + "dependencies": { + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-length/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -10807,6 +10846,7 @@ "socket.io": "^4.6.2", "ssh2": "^1.13.0", "string-hash": "^1.1.3", + "string-length": "^6.0.0", "svgo": "^3.0.2", "tiktoken": "^1.0.11", "uglify-js": "^3.17.4", diff --git a/packages/backend/package.json b/packages/backend/package.json index 01c4678a2..eb18aa61b 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -61,6 +61,7 @@ "socket.io": "^4.6.2", "ssh2": "^1.13.0", "string-hash": "^1.1.3", + "string-length": "^6.0.0", "svgo": "^3.0.2", "tiktoken": "^1.0.11", "uglify-js": "^3.17.4", diff --git a/packages/backend/src/CoreModule.js b/packages/backend/src/CoreModule.js index 5357b3e82..105edb5e8 100644 --- a/packages/backend/src/CoreModule.js +++ b/packages/backend/src/CoreModule.js @@ -182,6 +182,9 @@ const install = async ({ services, app }) => { const { EventService } = require('./services/EventService'); services.registerService('event', EventService); + const DefaultUserService = require('./services/DefaultUserService'); + services.registerService('__default-user', DefaultUserService); + } const install_legacy = async ({ services }) => { diff --git a/packages/backend/src/Kernel.js b/packages/backend/src/Kernel.js index 4f7cef535..f13668047 100644 --- a/packages/backend/src/Kernel.js +++ b/packages/backend/src/Kernel.js @@ -183,6 +183,7 @@ class Kernel extends AdvancedBase { await services.emit('start.webserver'); + await services.emit('ready.webserver'); } } diff --git a/packages/backend/src/fun/dev-console-ui-utils.js b/packages/backend/src/fun/dev-console-ui-utils.js new file mode 100644 index 000000000..db9ac2a47 --- /dev/null +++ b/packages/backend/src/fun/dev-console-ui-utils.js @@ -0,0 +1,32 @@ +const { TeePromise } = require('../util/promise'); + +const es_import_promise = new TeePromise(); +let stringLength; +(async () => { + stringLength = (await import('string-length')).default; + es_import_promise.resolve(); + // console.log('STRING LENGTH', stringLength); + // process.exit(0); +})(); +const surrounding_box = (col, lines, lengths) => { + if ( ! lengths ) { + lengths = lines.map(line => stringLength(line)); + } + + const max_length = Math.max(...lengths); + const c = str => `\x1b[${col}m${str}\x1b[0m`; + const bar = c(Array(max_length + 4).fill('━').join('')); + for ( let i = 0 ; i < lines.length ; i++ ) { + while ( stringLength(lines[i]) < max_length ) { + lines[i] += ' '; + } + lines[i] = `${c('┃ ')} ${lines[i]} ${c(' ┃')}`; + } + lines.unshift(`${c('┏')}${bar}${c('┓')}`); + lines.push(`${c('┗')}${bar}${c('┛')}`); +}; + +module.exports = { + surrounding_box, + es_import_promise, +}; diff --git a/packages/backend/src/services/DefaultUserService.js b/packages/backend/src/services/DefaultUserService.js new file mode 100644 index 000000000..e553f7a64 --- /dev/null +++ b/packages/backend/src/services/DefaultUserService.js @@ -0,0 +1,80 @@ +const { surrounding_box } = require("../fun/dev-console-ui-utils"); +const { get_user, generate_system_fsentries } = require("../helpers"); +const { asyncSafeSetInterval } = require("../util/promise"); +const BaseService = require("./BaseService"); +const { DB_WRITE } = require("./database/consts"); + +const DEFAULT_PASSWORD = 'changeme'; +const USERNAME = 'default_user'; + +class DefaultUserService extends BaseService { + static MODULES = { + bcrypt: require('bcrypt'), + uuidv4: require('uuid').v4, + } + async _init () { + } + async ['__on_ready.webserver'] () { + // check if a user named `default-user` exists + let user = await get_user({ username: USERNAME }); + if ( ! user ) user = await this.create_default_user_(); + + // check if user named `default-user` is using default password + const require = this.require; + const bcrypt = require('bcrypt'); + const is_default_password = await bcrypt.compare(DEFAULT_PASSWORD, user.password); + if ( ! is_default_password ) return; + + // show console widget + this.default_user_widget = () => { + const lines = [ + `Your default user has been created!`, + `\x1B[31;1musername:\x1B[0m ${USERNAME}`, + `\x1B[32;1mpassword:\x1B[0m ${DEFAULT_PASSWORD}`, + `(change the password to remove this message)` + ]; + surrounding_box('31;1', lines); + return lines; + }; + this.start_poll_(); + const svc_devConsole = this.services.get('dev-console'); + svc_devConsole.add_widget(this.default_user_widget); + } + start_poll_ () { + const interval = 1000 * 3; // 3 seconds + const poll_interval = asyncSafeSetInterval(async () => { + const user = await get_user({ username: USERNAME }); + const require = this.require; + const bcrypt = require('bcrypt'); + const is_default_password = await bcrypt.compare(DEFAULT_PASSWORD, user.password); + if ( ! is_default_password ) { + const svc_devConsole = this.services.get('dev-console'); + svc_devConsole.remove_widget(this.default_user_widget); + clearInterval(poll_interval); + return; + } + }, interval); + } + async create_default_user_ () { + const require = this.require; + const bcrypt = require('bcrypt'); + const db = this.services.get('database').get(DB_WRITE, 'default-user'); + await db.write( + ` + INSERT INTO user (uuid, username, password, free_storage) + VALUES (?, ?, ?, ?) + `, + [ + this.modules.uuidv4(), + USERNAME, + await bcrypt.hash(DEFAULT_PASSWORD, 8), + 1024 * 1024 * 1024 * 10, // 10 GB + ], + ); + const user = await get_user({ username: USERNAME }); + await generate_system_fsentries(user); + return user; + } +} + +module.exports = DefaultUserService; diff --git a/packages/backend/src/services/WebServerService.js b/packages/backend/src/services/WebServerService.js index 4c9870741..07337e7b6 100644 --- a/packages/backend/src/services/WebServerService.js +++ b/packages/backend/src/services/WebServerService.js @@ -27,6 +27,7 @@ var http = require('http'); const fs = require('fs'); const auth = require('../middleware/auth'); const { osclink } = require('../util/strutil'); +const { surrounding_box, es_import_promise } = require('../fun/dev-console-ui-utils'); class WebServerService extends BaseService { static MODULES = { @@ -42,6 +43,7 @@ class WebServerService extends BaseService { }; async ['__on_start.webserver'] () { + await es_import_promise; // error handling middleware goes last, as per the // expressjs documentation: @@ -122,17 +124,7 @@ class WebServerService extends BaseService { lines[2].length, 0, ]; - const max_length = Math.max(...lengths); - const c = str => `\x1b[34;1m${str}\x1b[0m`; - const bar = c(Array(max_length + 4).fill('━').join('')); - for ( let i = 0 ; i < lines.length ; i++ ) { - while ( lines[i].length < max_length ) { - lines[i] += ' '; - } - lines[i] = `${c('┃ ')} ${lines[i]} ${c(' ┃')}`; - } - lines.unshift(`${c('┏')}${bar}${c('┓')}`); - lines.push(`${c('┗')}${bar}${c('┛')}`); + surrounding_box('34;1', lines, lengths); return lines; }; { @@ -360,7 +352,7 @@ class WebServerService extends BaseService { const pad = (width - last_logo.sz) / 2; const asymmetrical = pad % 1 !== 0; const pad_left = Math.floor(pad); - const pad_right = Math.ceil(pad) + (asymmetrical ? 1 : 0); + const pad_right = Math.ceil(pad); for ( let i = 0 ; i < lines.length ; i++ ) { lines[i] = ' '.repeat(pad_left) + lines[i] + ' '.repeat(pad_right); }