feat: grant user driver perms from admin

This commit is contained in:
KernelDeimos
2024-07-20 00:55:26 -04:00
committed by Eric Dubé
parent f0c36a1cdf
commit c9ded89b22
6 changed files with 241 additions and 2 deletions

View File

@@ -28,6 +28,9 @@ config.servers = [];
// Will disable the auto-generated temp users. If a user lands on the site, they will be required to sign up or log in.
config.disable_temp_users = false;
config.default_user_group = '78b1b1dd-c959-44d2-b02c-8735671f9997';
config.default_temp_group = 'b7220104-7905-4985-b996-649fdcdb3c8f';
config.max_file_size = 100_000_000_000,
config.max_thumb_size = 1_000,
config.max_fsentry_name_length = 767,

View File

@@ -214,6 +214,14 @@ module.exports = eggspress(['/signup'], {
'UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1',
[insert_res.insertId]
);
// TODO: cache group id
const svc_group = req.services.get('group');
await svc_group.add_users({
uid: req.body.is_temp ?
config.default_temp_group : config.default_user_group,
users: [req.body.username]
});
}
// -----------------------------------
// Pseudo User converting
@@ -244,6 +252,17 @@ module.exports = eggspress(['/signup'], {
]
);
// TODO: cache group ids
const svc_group = req.services.get('group');
await svc_group.remove_users({
uid: config.default_temp_group,
users: [req.body.username],
});
await svc_group.add_users({
uid: config.default_user_group,
users: [req.body.username]
});
// record activity
db.write('UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', [pseudo_user.id]);
invalidate_cached_user_by_id(pseudo_user.id);

View File

@@ -16,16 +16,55 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { QuickMkdir } = require("../filesystem/hl_operations/hl_mkdir");
const { HLWrite } = require("../filesystem/hl_operations/hl_write");
const { NodePathSelector } = require("../filesystem/node/selectors");
const { surrounding_box } = require("../fun/dev-console-ui-utils");
const { get_user, generate_system_fsentries, invalidate_cached_user } = require("../helpers");
const { Context } = require("../util/context");
const { asyncSafeSetInterval } = require("../util/promise");
const { buffer_to_stream } = require("../util/streamutil");
const BaseService = require("./BaseService");
const { Actor, UserActorType } = require("./auth/Actor");
const { DB_WRITE } = require("./database/consts");
const USERNAME = 'admin';
const DEFAULT_FILES = {
'.policy': {
'drivers.json': JSON.stringify({
"temp": {
"kv": {
"rate-limit": {
"max": 1000,
"period": 30000
}
},
"es": {
"date-limit": {
"max": 1000,
"period": 30000
}
},
},
"user": {
"kv": {
"rate-limit": {
"max": 3000,
"period": 30000
}
},
"es": {
"rate-limit": {
"max": 3000,
"period": 30000
}
}
}
}, undefined, ' '),
}
};
class DefaultUserService extends BaseService {
static MODULES = {
bcrypt: require('bcrypt'),
@@ -100,6 +139,7 @@ class DefaultUserService extends BaseService {
users: [USERNAME]
});
const user = await get_user({ username: USERNAME, cached: false });
const actor = Actor.adapt(user);
const tmp_password = await this.get_tmp_password_(user);
const bcrypt = require('bcrypt');
const password_hashed = await bcrypt.hash(tmp_password, 8);
@@ -112,6 +152,46 @@ class DefaultUserService extends BaseService {
);
user.password = password_hashed;
await generate_system_fsentries(user);
// generate default files for admin user
const svc_fs = this.services.get('filesystem');
const make_tree_ = async ({ components, tree }) => {
const parent = await svc_fs.node(
new NodePathSelector('/'+components.join('/')),
);
for ( const k in tree ) {
if ( typeof tree[k] === 'string' ) {
const buffer = Buffer.from(tree[k], 'utf-8');
const hl_write = new HLWrite();
await hl_write.run({
destination_or_parent: parent,
specified_name: k,
file: {
size: buffer.length,
stream: buffer_to_stream(buffer),
},
user,
});
} else {
const hl_qmkdir = new QuickMkdir();
await hl_qmkdir.run({
parent,
path: k,
});
const components_ = [...components, k];
await make_tree_({
components: components_,
tree: tree[k],
});
}
}
};
await Context.get().sub({ user, actor }).arun(async () => {
await make_tree_({
components: ['admin'],
tree: DEFAULT_FILES
});
});
invalidate_cached_user(user);
await new Promise(rslv => setTimeout(rslv, 2000));
return user;

View File

@@ -18,6 +18,7 @@
*/
const { es_import_promise } = require("../../fun/dev-console-ui-utils");
const { surrounding_box } = require("../../fun/dev-console-ui-utils");
const structutil = require("../../util/structutil");
const { BaseDatabaseAccessService } = require("./BaseDatabaseAccessService");
class SqliteDatabaseAccessService extends BaseDatabaseAccessService {
@@ -42,7 +43,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService {
this.db = new Database(this.config.path);
// Database upgrade logic
const TARGET_VERSION = 23;
const TARGET_VERSION = 24;
if ( do_setup ) {
this.log.noticeme(`SETUP: creating database at ${this.config.path}`);
@@ -71,7 +72,8 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService {
'0022_dev-center-max.sql',
'0023_fix-kv.sql',
'0024_default-groups.sql',
'0025_system-user.dbmig.js'
'0025_system-user.dbmig.js',
'0026_user-groups.dbmig.js',
].map(p => path_.join(__dirname, 'sqlite_setup', p));
const fs = require('fs');
for ( const filename of sql_files ) {
@@ -180,6 +182,10 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService {
upgrade_files.push('0025_system-user.dbmig.js');
}
if ( user_version <= 23 ) {
upgrade_files.push('0026_user-groups.dbmig.js');
}
if ( upgrade_files.length > 0 ) {
this.log.noticeme(`Database out of date: ${this.config.path}`);
this.log.noticeme(`UPGRADING DATABASE: ${user_version} -> ${TARGET_VERSION}`);
@@ -299,6 +305,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService {
read: this.read.bind(this),
write: this.write.bind(this),
log: this.log,
structutil,
});
await vm.runInContext(contents, context);
}

View File

@@ -0,0 +1,95 @@
const { insertId: temp_group_id } = await write(
'INSERT INTO `group` (`uid`, `owner_user_id`, `extra`, `metadata`) '+
'VALUES (?, ?, ?, ?)',
[
'b7220104-7905-4985-b996-649fdcdb3c8f',
1,
'{"critical": true, "type": "default", "name": "temp"}',
'{"title": "Guest", "color": "#777777"}'
]
);
const [{id: system_user_id}] = await read(
"SELECT id FROM `user` WHERE username='system'"
);
const [{id: user_group_id}] = await read(
'SELECT id FROM `group` WHERE uid=?',
['78b1b1dd-c959-44d2-b02c-8735671f9997']
);
const user_types = structutil.apply_keys(
['name', 'group_id'],
['temp', temp_group_id],
['user', user_group_id],
);
const drivers = structutil.apply_keys(
['driver_id', 'selector'],
['driver:puter-kvstore', 'kv'],
['driver:puter-notifications', 'es'],
['driver:puter-apps', 'es'],
['driver:puter-subdomains', 'es'],
);
const perms = structutil.cart_product(
[user_types, drivers]);
for ( const perm of perms ) {
const [user_type, driver] = perm;
log.info('permission info', { user_type, driver });
debugger;
// temp user drivers
await write(
'INSERT INTO `user_to_group_permissions` ' +
'(`user_id`, `group_id`, `permission`, `extra`) ' +
'VALUES (?, ?, ?, ?)',
[
system_user_id, user_type.group_id,
driver.driver_id,
JSON.stringify({
policy: {
$: 'json-address',
path: '/admin/.policy/drivers.json',
selector: user_type.name + '.' +
driver.selector,
}
}),
]
);
}
/*
// temp user drivers
await write(
'INSERT INTO `user_to_group_permissions` ' +
'(`user_id`, `group_id`, `permission`, `extra`) ' +
'VALUES (?, ?, ?, ?)',
[
system_user_id, temp_group_id,
'driver:puter-kvstore',
JSON.stringify({
policy: {
$: 'json-address',
path: '/admin/.policy/drivers.json',
selector: 'temp.kv',
}
}),
]
);
// registered user drivers
await write(
'INSERT INTO `user_to_group_permissions` ' +
'(`user_id`, `group_id`, `permission`, `extra`) ' +
'VALUES (?, ?, ?, ?)',
[
system_user_id, user_group_id,
'driver:puter-kvstore',
JSON.stringify({
policy: {
$: 'json-address',
path: '/admin/.policy/drivers.json',
selector: 'user.kv',
}
}),
]
);
*/

View File

@@ -0,0 +1,35 @@
const cart_product = (obj) => {
// Get array of keys
let keys = Object.keys(obj);
// Generate the Cartesian Product
return keys.reduce((acc, key) => {
let appendArrays = Array.isArray(obj[key]) ? obj[key] : [obj[key]];
let newAcc = [];
acc.forEach(arr => {
appendArrays.forEach(item => {
newAcc.push([...arr, item]);
});
});
return newAcc;
}, [[]]); // start with the "empty product"
}
const apply_keys = (keys, ...entries) => {
const l = [];
for ( const entry of entries ) {
const o = {};
for ( let i=0 ; i < keys.length ; i++ ) {
o[keys[i]] = entry[i];
}
l.push(o);
}
return l;
}
module.exports = {
cart_product,
apply_keys,
};