mirror of
https://github.com/HeyPuter/puter.git
synced 2026-09-22 21:26:04 +00:00
fix(security): always use actor
This commit is contained in:
@@ -213,17 +213,16 @@ class FilesystemService extends BaseService {
|
||||
return this.systemfs_;
|
||||
}
|
||||
|
||||
async owrite ({
|
||||
node, user, immutable,
|
||||
file, tmp, fsentry_tmp,
|
||||
message,
|
||||
}) {
|
||||
// NOTE: these are the parameters being passed
|
||||
// (assuming this comment is up-to-date)
|
||||
// {
|
||||
// node, actor, immutable,
|
||||
// file, tmp, fsentry_tmp,
|
||||
// message,
|
||||
// }
|
||||
async owrite (parameters) {
|
||||
const ll_owrite = new LLOWrite();
|
||||
return await ll_owrite.run({
|
||||
node, user, immutable,
|
||||
file, tmp, fsentry_tmp,
|
||||
message,
|
||||
});
|
||||
return await ll_owrite.run(parameters);
|
||||
}
|
||||
|
||||
// REMINDER: There was an idea that FilesystemService implements
|
||||
@@ -235,9 +234,9 @@ class FilesystemService extends BaseService {
|
||||
return await ll_cwrite.run(parameters);
|
||||
}
|
||||
|
||||
async mkdir_2 ({parent, name, user, immutable}) {
|
||||
async mkdir_2 ({parent, name, actor, immutable}) {
|
||||
const ll_mkdir = new LLMkdir();
|
||||
return await ll_mkdir.run({ parent, name, user, immutable });
|
||||
return await ll_mkdir.run({ parent, name, actor, immutable });
|
||||
}
|
||||
|
||||
async mkshortcut ({ parent, name, user, target }) {
|
||||
|
||||
@@ -26,11 +26,11 @@ const config = require('../../config');
|
||||
const { TeePromise } = require('../../util/promise');
|
||||
|
||||
class BatchExecutor extends AdvancedBase {
|
||||
constructor (x, { user, log, errors }) {
|
||||
constructor (x, { actor, log, errors }) {
|
||||
super();
|
||||
this.x = x;
|
||||
this.user = user;
|
||||
this.pathResolver = new PathResolver({ user });
|
||||
this.actor = actor
|
||||
this.pathResolver = new PathResolver({ actor });
|
||||
this.expectations = x.get('services').get('expectations');
|
||||
this.log = log;
|
||||
this.errors = errors;
|
||||
@@ -100,7 +100,7 @@ class BatchExecutor extends AdvancedBase {
|
||||
const command_ins = await command_cls.run({
|
||||
getFile: () => file,
|
||||
pathResolver: this.pathResolver,
|
||||
user: this.user
|
||||
actor: this.actor,
|
||||
}, op);
|
||||
workUnit.checkpoint('operation invoked');
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ class MkdirCommand extends BatchCommand {
|
||||
parameters.create_missing_parents ??
|
||||
false,
|
||||
shortcut_to: parameters.shortcut_to,
|
||||
user: executor.user,
|
||||
actor: executor.actor,
|
||||
});
|
||||
if ( parameters.as ) {
|
||||
executor.pathResolver.putSelector(
|
||||
@@ -133,6 +133,9 @@ class WriteCommand extends BatchCommand {
|
||||
}
|
||||
|
||||
const hl_write = new HLWrite();
|
||||
if ( ! executor.actor ) {
|
||||
throw new Error('Actor is missing here');
|
||||
}
|
||||
const response = await hl_write.run({
|
||||
destination_or_parent: destinationOrParent,
|
||||
specified_name: parameters.name,
|
||||
@@ -145,7 +148,7 @@ class WriteCommand extends BatchCommand {
|
||||
parameters.create_missing_ancestors ??
|
||||
parameters.create_missing_parents ??
|
||||
false,
|
||||
user: executor.user,
|
||||
actor: executor.actor,
|
||||
|
||||
file: uploaded_file,
|
||||
offset: parameters.offset,
|
||||
@@ -208,7 +211,7 @@ class ShortcutCommand extends BatchCommand {
|
||||
const response = await hl_mkShortcut.run({
|
||||
parent: destinationOrParent,
|
||||
name: parameters.name,
|
||||
user: executor.user,
|
||||
actor: executor.actor,
|
||||
target: shortcut_to,
|
||||
|
||||
// TODO: handle these with event service instead
|
||||
@@ -241,7 +244,7 @@ class SymlinkCommand extends BatchCommand {
|
||||
const response = await hl_mkLink.run({
|
||||
parent: destinationOrParent,
|
||||
name: parameters.name,
|
||||
user: executor.user,
|
||||
actor: executor.actor,
|
||||
target: parameters.target,
|
||||
|
||||
// TODO: handle these with event service instead
|
||||
@@ -266,7 +269,7 @@ class DeleteCommand extends BatchCommand {
|
||||
const hl_remove = new HLRemove();
|
||||
const response = await hl_remove.run({
|
||||
target,
|
||||
user: executor.user,
|
||||
actor: executor.actor,
|
||||
recursive: parameters.recursive ?? false,
|
||||
descendants_only: parameters.descendants_only ?? false,
|
||||
});
|
||||
|
||||
@@ -76,7 +76,7 @@ class MkTree extends HLFilesystemOperation {
|
||||
const { context, values } = this;
|
||||
const { _path } = this.modules;
|
||||
const fs = context.get('services').get('filesystem');
|
||||
const user = context.get('user');
|
||||
const actor = context.get('actor');
|
||||
|
||||
const trunk = tree[0];
|
||||
const branches = tree.slice(1);
|
||||
@@ -124,7 +124,7 @@ class MkTree extends HLFilesystemOperation {
|
||||
|
||||
if ( parent_did_exist && ! parent_exists ) {
|
||||
const node = await fs.node(current);
|
||||
const has_perm = await chkperm(await node.get('entry'), user.id, 'write');
|
||||
const has_perm = await chkperm(await node.get('entry'), actor.type.user.id, 'write');
|
||||
if ( ! has_perm ) throw APIError.create('permission_denied');
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ class MkTree extends HLFilesystemOperation {
|
||||
const node = await fs.mkdir_2({
|
||||
parent: await fs.node(currentParent),
|
||||
name: current.name,
|
||||
user,
|
||||
actor,
|
||||
})
|
||||
|
||||
current = node.selector;
|
||||
@@ -179,7 +179,7 @@ class QuickMkdir extends HLFilesystemOperation {
|
||||
let { parent, path } = values;
|
||||
const { _path } = this.modules;
|
||||
const fs = context.get('services').get('filesystem');
|
||||
const user = context.get('user');
|
||||
const actor = context.get('actor');
|
||||
|
||||
parent = parent || await fs.node(new RootNodeSelector());
|
||||
|
||||
@@ -206,7 +206,7 @@ class QuickMkdir extends HLFilesystemOperation {
|
||||
const node = await fs.mkdir_2({
|
||||
parent: await fs.node(currentParent),
|
||||
name: current.name,
|
||||
user,
|
||||
actor,
|
||||
})
|
||||
|
||||
current = node.selector;
|
||||
@@ -285,10 +285,12 @@ class HLMkdir extends HLFilesystemOperation {
|
||||
// specified under `path`.
|
||||
parent_node = await this._create_parents({
|
||||
parent_node: top_parent,
|
||||
user: values.user,
|
||||
actor: values.actor,
|
||||
});
|
||||
|
||||
const has_perm = await chkperm(await parent_node.get('entry'), values.user.id, 'write');
|
||||
const user_id = values.actor.type.user.id;
|
||||
|
||||
const has_perm = await chkperm(await parent_node.get('entry'), user_id, 'write');
|
||||
if ( ! has_perm ) throw APIError.create('permission_denied');
|
||||
|
||||
const existing = await fs.node(
|
||||
@@ -301,12 +303,12 @@ class HLMkdir extends HLFilesystemOperation {
|
||||
const { overwrite, dedupe_name, create_missing_parents } = values;
|
||||
if ( overwrite ) {
|
||||
// TODO: tag rm operation somehow
|
||||
const has_perm = await chkperm(await existing.get('entry'), values.user.id, 'write');
|
||||
const has_perm = await chkperm(await existing.get('entry'), user_id, 'write');
|
||||
if ( ! has_perm ) throw APIError.create('permission_denied');
|
||||
const hl_remove = new HLRemove();
|
||||
await hl_remove.run({
|
||||
target: existing,
|
||||
user: values.user,
|
||||
actor: values.actor,
|
||||
recursive: true,
|
||||
});
|
||||
}
|
||||
@@ -345,13 +347,13 @@ class HLMkdir extends HLFilesystemOperation {
|
||||
if ( ! shortcut_to.entry.is_dir ) {
|
||||
throw APIError.create('shortcut_target_is_a_directory');
|
||||
}
|
||||
const has_perm = await chkperm(shortcut_to.entry, values.user.id, 'read');
|
||||
const has_perm = await chkperm(shortcut_to.entry, user_id, 'read');
|
||||
if ( ! has_perm ) throw APIError.create('forbidden');
|
||||
|
||||
this.created = await fs.mkshortcut({
|
||||
parent: parent_node,
|
||||
name: target_basename,
|
||||
user: values.user,
|
||||
actor: values.actor,
|
||||
target: shortcut_to,
|
||||
});
|
||||
|
||||
@@ -362,7 +364,7 @@ class HLMkdir extends HLFilesystemOperation {
|
||||
this.created = await fs.mkdir_2({
|
||||
parent: parent_node,
|
||||
name: target_basename,
|
||||
user: values.user,
|
||||
actor: values.actor,
|
||||
});
|
||||
|
||||
const all_nodes = [
|
||||
@@ -382,7 +384,7 @@ class HLMkdir extends HLFilesystemOperation {
|
||||
return response;
|
||||
}
|
||||
|
||||
async _create_parents ({ parent_node, user }) {
|
||||
async _create_parents ({ parent_node }) {
|
||||
const { context, values } = this;
|
||||
const { _path } = this.modules;
|
||||
const fs = context.get('services').get('filesystem');
|
||||
|
||||
@@ -59,7 +59,10 @@ class WriteCommonFeature {
|
||||
if ( ! this.values.file ) return;
|
||||
|
||||
const sizeService = this.context.get('services').get('sizeService');
|
||||
const { file, user } = this.values;
|
||||
const { file, user: user_let } = this.values;
|
||||
let user = user_let;
|
||||
|
||||
if ( ! user ) user = this.values.actor.type.user;
|
||||
|
||||
const usage = await sizeService.get_usage(user.id);
|
||||
let capacity = config.is_storage_limited ? user.free_storage == undefined
|
||||
@@ -281,13 +284,14 @@ class HLWrite extends HLFilesystemOperation {
|
||||
if ( await shortcut_to.get('type') === TYPE_DIRECTORY ) {
|
||||
throw APIError.create('shortcut_target_is_a_directory');
|
||||
}
|
||||
const has_perm = await chkperm(shortcut_to.entry, values.user.id, 'read');
|
||||
// TODO: legacy check - likely not needed
|
||||
const has_perm = await chkperm(shortcut_to.entry, values.actor.type.user.id, 'read');
|
||||
if ( ! has_perm ) throw APIError.create('permission_denied');
|
||||
|
||||
this.created = await fs.mkshortcut({
|
||||
parent,
|
||||
name: target_name,
|
||||
user: values.user,
|
||||
actor: values.actor,
|
||||
target: shortcut_to,
|
||||
});
|
||||
|
||||
@@ -381,7 +385,7 @@ class HLWrite extends HLFilesystemOperation {
|
||||
if ( is_overwrite ) {
|
||||
this.written = await fs.owrite({
|
||||
node: destination,
|
||||
user: values.user,
|
||||
actor: values.actor,
|
||||
file: values.file,
|
||||
tmp: {
|
||||
socket_id: values.socket_id,
|
||||
@@ -397,7 +401,7 @@ class HLWrite extends HLFilesystemOperation {
|
||||
this.written = await fs.cwrite({
|
||||
parent,
|
||||
name: target_name,
|
||||
user: values.user,
|
||||
actor: values.actor,
|
||||
file: values.file,
|
||||
tmp: {
|
||||
socket_id: values.socket_id,
|
||||
|
||||
@@ -55,7 +55,7 @@ class LLMkdir extends LLFilesystemOperation {
|
||||
async _locked_run () {
|
||||
const { _path, uuidv4 } = this.modules;
|
||||
const { context } = this;
|
||||
const { parent, name, user, immutable, actor } = this.values;
|
||||
const { parent, name, immutable, actor } = this.values;
|
||||
|
||||
const ts = Math.round(Date.now() / 1000);
|
||||
const uid = uuidv4();
|
||||
@@ -95,7 +95,7 @@ class LLMkdir extends LLFilesystemOperation {
|
||||
uuid: uid,
|
||||
parent_uid: await parent.get('uid'),
|
||||
path: _path.join(await parent.get('path'), name),
|
||||
user_id: user.id,
|
||||
user_id: actor.type.user.id,
|
||||
name,
|
||||
created: ts,
|
||||
accessed: ts,
|
||||
|
||||
@@ -128,13 +128,11 @@ class LLWriteBase extends LLFilesystemOperation {
|
||||
class LLOWrite extends LLWriteBase {
|
||||
async _run () {
|
||||
const {
|
||||
node, user, immutable,
|
||||
node, actor, immutable,
|
||||
file, tmp, fsentry_tmp,
|
||||
message,
|
||||
} = this.values;
|
||||
|
||||
let { actor } = this.values;
|
||||
|
||||
const svc = Context.get('services');
|
||||
const sizeService = svc.get('sizeService');
|
||||
const resourceService = svc.get('resourceService');
|
||||
@@ -152,8 +150,6 @@ class LLOWrite extends LLWriteBase {
|
||||
throw APIError.create('subject_does_not_exist');
|
||||
}
|
||||
|
||||
actor = actor ?? Actor.adapt(user);
|
||||
|
||||
const svc_acl = this.context.get('services').get('acl');
|
||||
if ( ! await svc_acl.check(actor, node, 'write') ) {
|
||||
throw await svc_acl.get_safe_acl_error(actor, node, 'write');
|
||||
@@ -190,7 +186,7 @@ class LLOWrite extends LLWriteBase {
|
||||
});
|
||||
|
||||
const filesize = file.size;
|
||||
sizeService.change_usage(user.id, filesize);
|
||||
sizeService.change_usage(actor.type.user.id, filesize);
|
||||
|
||||
const entryOp = await systemFSEntryService.update(uid, raw_fsentry_delta);
|
||||
|
||||
@@ -202,7 +198,7 @@ class LLOWrite extends LLWriteBase {
|
||||
})();
|
||||
|
||||
state_upload.post_insert({
|
||||
db, user, node, uid, message, ts,
|
||||
db, user: actor.type.user, node, uid, message, ts,
|
||||
});
|
||||
|
||||
const svc_fileCache = this.context.get('services').get('file-cache');
|
||||
@@ -227,7 +223,7 @@ class LLCWrite extends LLWriteBase {
|
||||
async _run () {
|
||||
const { _path, uuidv4, config } = this.modules;
|
||||
const {
|
||||
parent, name, user, immutable,
|
||||
parent, name, immutable,
|
||||
file, tmp, fsentry_tmp,
|
||||
message,
|
||||
|
||||
@@ -261,7 +257,7 @@ class LLCWrite extends LLWriteBase {
|
||||
}
|
||||
|
||||
const svc_acl = this.context.get('services').get('acl');
|
||||
actor = actor ?? Actor.adapt(user) ?? Context.get('actor');
|
||||
actor = actor ?? Context.get('actor');
|
||||
if ( ! await svc_acl.check(actor, parent, 'write') ) {
|
||||
throw await svc_acl.get_safe_acl_error(actor, parent, 'write');
|
||||
}
|
||||
@@ -288,7 +284,7 @@ class LLCWrite extends LLWriteBase {
|
||||
const raw_fsentry = {
|
||||
uuid: uid,
|
||||
is_dir: 0,
|
||||
user_id: user.id,
|
||||
user_id: actor.type.user.id,
|
||||
created: ts,
|
||||
accessed: ts,
|
||||
modified: ts,
|
||||
@@ -317,7 +313,7 @@ class LLCWrite extends LLWriteBase {
|
||||
});
|
||||
|
||||
const filesize = file.size;
|
||||
sizeService.change_usage(user.id, filesize);
|
||||
sizeService.change_usage(actor.type.user.id, filesize);
|
||||
|
||||
this.checkpoint('after change_usage');
|
||||
|
||||
@@ -338,7 +334,7 @@ class LLCWrite extends LLWriteBase {
|
||||
db.write(
|
||||
"INSERT INTO `fsentry_versions` (`user_id`, `fsentry_id`, `fsentry_uuid`, `version_id`, `message`, `ts_epoch`) VALUES (?, ?, ?, ?, ?, ?)",
|
||||
[
|
||||
user.id,
|
||||
actor.type.user.id,
|
||||
new_item.id,
|
||||
new_item.uuid,
|
||||
store_version_id,
|
||||
|
||||
@@ -33,11 +33,11 @@ const ERR_UNKNOWN_PATHREF = 'Unknown path reference in path: ';
|
||||
* that was returned by the `mkdir` operation.
|
||||
*/
|
||||
module.exports = class PathResolver {
|
||||
constructor ({ user }) {
|
||||
constructor ({ actor }) {
|
||||
this.references = {};
|
||||
this.selectors = {};
|
||||
this.meta = {};
|
||||
this.user = user;
|
||||
this.actor = actor;
|
||||
|
||||
this.listeners = {};
|
||||
|
||||
@@ -88,11 +88,13 @@ module.exports = class PathResolver {
|
||||
}
|
||||
|
||||
async awaitSelector (inputPath) {
|
||||
// TODO: I feel like there's a better way to get username
|
||||
const username = this.actor.type.user.username;
|
||||
if ( inputPath.startsWith('~/') ) {
|
||||
return `/${this.user.username}/${inputPath.substring(2)}`;
|
||||
return `/${username}/${inputPath.substring(2)}`;
|
||||
}
|
||||
if ( inputPath === '~' ) {
|
||||
return `/${this.user.username}`;
|
||||
return `/${username}`;
|
||||
}
|
||||
const refName = this.getReferenceUsed(inputPath);
|
||||
if ( refName === null ) return inputPath;
|
||||
|
||||
@@ -127,9 +127,12 @@ module.exports = eggspress('/batch', {
|
||||
if ( op_spec.op === 'write' ) return true;
|
||||
return false;
|
||||
}
|
||||
if ( ! req.actor ) {
|
||||
throw new Error('Actor is missing here');
|
||||
}
|
||||
const batch_exe = new BatchExecutor(x, {
|
||||
log, errors,
|
||||
user: req.user,
|
||||
actor: req.actor,
|
||||
});
|
||||
// --- state
|
||||
const pending_operations = [];
|
||||
|
||||
Reference in New Issue
Block a user