From cd22425a3d363f6008b3d07f40a082769ee22a14 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 13 Nov 2024 22:44:54 -0500 Subject: [PATCH] fix: replace ll_readshares with better approach Recursively checking for files with 'see' permission? What was I thinking? This replaces the disasterously awful approach of scanning a user's entire file tree to find shares, with an approach which instead selects on the permissions table and extracts file UUIDs from permissions. --- .../filesystem/hl_operations/hl_readdir.js | 3 +- .../filesystem/ll_operations/ll_readshares.js | 91 ++++++++++--------- 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/src/backend/src/filesystem/hl_operations/hl_readdir.js b/src/backend/src/filesystem/hl_operations/hl_readdir.js index a6bb9c0eb..32061f028 100644 --- a/src/backend/src/filesystem/hl_operations/hl_readdir.js +++ b/src/backend/src/filesystem/hl_operations/hl_readdir.js @@ -64,7 +64,8 @@ class HLReadDir extends HLFilesystemOperation { const ll_listusers = new LLListUsers(); children = await ll_listusers.run(this.values); } else if ( - await subject.getUserPart() !== user.username + await subject.getUserPart() !== user.username && + await subject.isUserDirectory() ) { this.log.noticeme('THIS HAPPEN'); const ll_readshares = new LLReadShares(); diff --git a/src/backend/src/filesystem/ll_operations/ll_readshares.js b/src/backend/src/filesystem/ll_operations/ll_readshares.js index a27e31d5e..c797d65f0 100644 --- a/src/backend/src/filesystem/ll_operations/ll_readshares.js +++ b/src/backend/src/filesystem/ll_operations/ll_readshares.js @@ -16,8 +16,12 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +const { get_user } = require("../../helpers"); +const { PermissionUtil } = require("../../services/auth/PermissionService"); +const { DB_WRITE } = require("../../services/database/consts"); const { Context } = require("../../util/context"); const { TYPE_DIRECTORY } = require("../FSNodeContext"); +const { NodeUIDSelector } = require("../node/selectors"); const { LLFilesystemOperation } = require("./definitions"); const { LLReadDir } = require("./ll_readdir"); @@ -32,57 +36,56 @@ class LLReadShares extends LLFilesystemOperation { `; async _run () { + const { subject, user, actor, depth = 0 } = this.values; + + const svc = this.context.get('services'); + + const svc_fs = svc.get('filesystem'); + const svc_acl = svc.get('acl'); + const db = svc.get('database').get(DB_WRITE, 'll_readshares'); + + const issuer_username = await subject.getUserPart(); + const issuer_user = await get_user({ username: issuer_username }); + const rows = await db.read( + 'SELECT DISTINCT permission FROM `user_to_user_permissions` ' + + 'WHERE `holder_user_id` = ? AND `issuer_user_id` = ? ' + + 'AND `permission` LIKE ?', + [user.id, issuer_user.id, 'fs:%'] + ); + + const fsentry_uuids = []; + for ( const row of rows ) { + const parts = PermissionUtil.split(row.permission); + fsentry_uuids.push(parts[1]); + } + const results = []; - const stats = await this.recursive_part(results, this.values); - // console.log('LL_READ_SHARES_STATS !!!!!', stats); - - return results; - } - - async recursive_part (results, { subject, user, actor, depth = 0 }) { - actor = actor || Context.get('actor'); + const ll_readdir = new LLReadDir(); - const children = await ll_readdir.run({ - subject, user, + let interm_results = await ll_readdir.run({ + subject, + actor, + user, no_thumbs: true, no_assocs: true, no_acl: true, }); - - const svc = Context.get('services'); - const svc_acl = svc.get('acl'); - - const promises = []; - - for ( const child of children ) { - // If we have at least see permission: terminal node - const acl_result = await svc_acl.check(actor, child, 'see'); - console.log( - '\x1B[31;1mWHAT DIS?\x1B[0m', - actor, - child.entry?.path, - child.selectors_[0].describe(), - acl_result, - ) - if ( acl_result ) { - results.push(child); - continue; - } - - if ( await child.get('type') !== TYPE_DIRECTORY ) { - continue; - } - - const p = this.recursive_part(results, { - subject: child, - user, - depth: depth + 1, - }); - promises.push(p); + + // Clone interm_results in case ll_readdir ever implements caching + interm_results = interm_results.slice(); + + for ( const fsentry_uuid of fsentry_uuids ) { + const node = await svc_fs.node(new NodeUIDSelector(fsentry_uuid)); + if ( ! node ) continue; + interm_results.push(node); } - - const stats = await Promise.all(promises); - return Math.max(depth, ...stats); + + for ( const node of interm_results ) { + if ( ! await svc_acl.check(actor, node, 'see') ) continue; + results.push(node); + } + + return results; } }