diff --git a/packages/backend/src/Kernel.js b/packages/backend/src/Kernel.js index f1366804..e1fac6f3 100644 --- a/packages/backend/src/Kernel.js +++ b/packages/backend/src/Kernel.js @@ -95,11 +95,8 @@ class Kernel extends AdvancedBase { root_context.arun(async () => { await this._install_modules(); - }); - - (async () => { await this._boot_services(); - })(); + }); // Error.stackTraceLimit = Infinity; diff --git a/packages/backend/src/services/DefaultUserService.js b/packages/backend/src/services/DefaultUserService.js index e553f7a6..424795b3 100644 --- a/packages/backend/src/services/DefaultUserService.js +++ b/packages/backend/src/services/DefaultUserService.js @@ -1,7 +1,9 @@ const { surrounding_box } = require("../fun/dev-console-ui-utils"); -const { get_user, generate_system_fsentries } = require("../helpers"); +const { get_user, generate_system_fsentries, invalidate_cached_user } = require("../helpers"); +const { Context } = require("../util/context"); const { asyncSafeSetInterval } = require("../util/promise"); const BaseService = require("./BaseService"); +const { Actor, UserActorType } = require("./auth/Actor"); const { DB_WRITE } = require("./database/consts"); const DEFAULT_PASSWORD = 'changeme'; @@ -16,13 +18,24 @@ class DefaultUserService extends BaseService { } async ['__on_ready.webserver'] () { // check if a user named `default-user` exists - let user = await get_user({ username: USERNAME }); + let user = await get_user({ username: USERNAME, cached: false }); if ( ! user ) user = await this.create_default_user_(); // check if user named `default-user` is using default password const require = this.require; + const tmp_password = await this.get_tmp_password_(user); + console.log(`second input [${tmp_password}]`); const bcrypt = require('bcrypt'); - const is_default_password = await bcrypt.compare(DEFAULT_PASSWORD, user.password); + console.log(...[ + 'THESE ARE THE ARGS', + tmp_password, + // password_hashed, + user.password + ].map(l => l + '\n')); + const is_default_password = await bcrypt.compare( + tmp_password, + user.password + ); if ( ! is_default_password ) return; // show console widget @@ -30,23 +43,26 @@ class DefaultUserService extends BaseService { const lines = [ `Your default user has been created!`, `\x1B[31;1musername:\x1B[0m ${USERNAME}`, - `\x1B[32;1mpassword:\x1B[0m ${DEFAULT_PASSWORD}`, + `\x1B[32;1mpassword:\x1B[0m ${tmp_password}`, `(change the password to remove this message)` ]; surrounding_box('31;1', lines); return lines; }; - this.start_poll_(); + this.start_poll_({ tmp_password, user }); const svc_devConsole = this.services.get('dev-console'); svc_devConsole.add_widget(this.default_user_widget); } - start_poll_ () { + start_poll_ ({ tmp_password, user }) { 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); + const is_default_password = await bcrypt.compare( + tmp_password, + user.password + ); if ( ! is_default_password ) { const svc_devConsole = this.services.get('dev-console'); svc_devConsole.remove_widget(this.default_user_widget); @@ -56,25 +72,53 @@ class DefaultUserService extends BaseService { }, 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 (?, ?, ?, ?) + INSERT INTO user (uuid, username, 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 }); + const tmp_password = await this.get_tmp_password_(user); + console.log(`first input [${tmp_password}]`); + const bcrypt = require('bcrypt'); + const password_hashed = await bcrypt.hash(tmp_password, 8); + await db.write( + `UPDATE user SET password = ? WHERE id = ?`, + [ + password_hashed, + user.id, + ], + ); + user.password = password_hashed; await generate_system_fsentries(user); + invalidate_cached_user(user); + await new Promise(rslv => setTimeout(rslv, 2000)); return user; } + async get_tmp_password_ (user) { + const actor = await Actor.create(UserActorType, { user }); + return await Context.get().sub({ actor }).arun(async () => { + const svc_driver = this.services.get('driver'); + const driver_response = await svc_driver.call( + 'puter-kvstore', 'get', { key: 'tmp_password' }); + + if ( driver_response.result ) return driver_response.result.value; + + const tmp_password = require('crypto').randomBytes(4).toString('hex'); + await svc_driver.call( + 'puter-kvstore', 'set', { + key: 'tmp_password', + value: tmp_password }); + return tmp_password; + }); + } } module.exports = DefaultUserService; diff --git a/packages/backend/src/services/drivers/implementations/DBKVStore.js b/packages/backend/src/services/drivers/implementations/DBKVStore.js index c203184e..07094c1b 100644 --- a/packages/backend/src/services/drivers/implementations/DBKVStore.js +++ b/packages/backend/src/services/drivers/implementations/DBKVStore.js @@ -84,15 +84,28 @@ class DBKVStore extends BaseImplementation { const db = this.services.get('database').get(DB_WRITE, 'kvstore'); const key_hash = this.modules.murmurhash.v3(key); - await db.write( - `INSERT INTO kv - (user_id, app, kkey_hash, kkey, value) - VALUES - (?, ?, ?, ?, ?) - ON DUPLICATE KEY UPDATE - value = ?`, - [ user.id, app?.uid ?? 'global', key_hash, key, value, value ] - ); + try { + await db.write( + `INSERT INTO kv (user_id, app, kkey_hash, kkey, value) + VALUES (?, ?, ?, ?, ?) ` + + db.case({ + mysql: 'ON DUPLICATE KEY UPDATE value = ?', + sqlite: ' ', + // sqlite: 'ON CONFLICT(user_id, app, kkey_hash) DO UPDATE SET value = ?', + }), + [ + user.id, app?.uid ?? 'global', key_hash, key, value, + ...db.case({ mysql: [value], otherwise: [] }), + ] + ); + } catch (e) { + // if ( e.code !== 'SQLITE_ERROR' && e.code !== 'SQLITE_CONSTRAINT_PRIMARYKEY' ) throw e; + // The "ON CONFLICT" clause isn't currently working. + await db.write( + `UPDATE kv SET value = ? WHERE user_id=? AND app=? AND kkey_hash=?`, + [ value, user.id, app?.uid ?? 'global', key_hash ] + ); + } return true; }, diff --git a/packages/backend/src/services/sla/MonthlyUsageService.js b/packages/backend/src/services/sla/MonthlyUsageService.js index 2a8ab7c9..015c685b 100644 --- a/packages/backend/src/services/sla/MonthlyUsageService.js +++ b/packages/backend/src/services/sla/MonthlyUsageService.js @@ -34,18 +34,41 @@ class MonthlyUsageService extends BaseService { const maybe_app_id = actor.type.app?.id; + if ( this.db.case({ sqlite: true, otherwise: false }) ) { + return; + } + // UPSERT increment count - await this.db.write( - 'INSERT INTO `service_usage_monthly` (`year`, `month`, `key`, `count`, `user_id`, `app_id`, `extra`) ' + - 'VALUES (?, ?, ?, 1, ?, ?, ?) ' + - 'ON DUPLICATE KEY UPDATE `count` = `count` + 1', - [ - year, month, key, - actor.type.user?.id || null, - maybe_app_id || null, - JSON.stringify(extra) - ] - ); + try { + await this.db.write( + 'INSERT INTO `service_usage_monthly` (`year`, `month`, `key`, `count`, `user_id`, `app_id`, `extra`) ' + + 'VALUES (?, ?, ?, 1, ?, ?, ?) ' + + this.db.case({ + mysql: 'ON DUPLICATE KEY UPDATE `count` = `count` + 1, `extra` = ?', + sqlite: ' ', + // sqlite: 'ON CONFLICT(`year`, `month`, `key`, `user_id`, `app_id`) ' + + // 'DO UPDATE SET `count` = `count` + 1 AND `extra` = ?', + }), + [ + year, month, key, actor.type.user.id, maybe_app_id, JSON.stringify(extra), + ...this.db.case({ mysql: [JSON.stringify(extra)], otherwise: [] }), + ] + ); + } catch (e) { + // if ( e.code !== 'SQLITE_ERROR' && e.code !== 'SQLITE_CONSTRAINT_PRIMARYKEY' ) throw e; + // The "ON CONFLICT" clause isn't currently working. + await this.db.write( + 'UPDATE `service_usage_monthly` ' + + 'SET `count` = `count` + 1, `extra` = ? ' + + 'WHERE `year` = ? AND `month` = ? AND `key` = ? ' + + 'AND `user_id` = ? AND `app_id` = ?', + [ + JSON.stringify(extra), + year, month, key, actor.type.user.id, maybe_app_id, + ] + ); + + } } async check (actor, specifiers) {