mirror of
https://github.com/HeyPuter/puter.git
synced 2026-01-08 14:10:41 -06:00
feat: grant user driver perms from admin
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
}
|
||||
}),
|
||||
]
|
||||
);
|
||||
*/
|
||||
35
src/backend/src/util/structutil.js
Normal file
35
src/backend/src/util/structutil.js
Normal 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,
|
||||
};
|
||||
Reference in New Issue
Block a user