Skip to content

Commit cd22425

Browse files
committed
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.
1 parent 34836e3 commit cd22425

File tree

2 files changed

+49
-45
lines changed

2 files changed

+49
-45
lines changed

src/backend/src/filesystem/hl_operations/hl_readdir.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ class HLReadDir extends HLFilesystemOperation {
6464
const ll_listusers = new LLListUsers();
6565
children = await ll_listusers.run(this.values);
6666
} else if (
67-
await subject.getUserPart() !== user.username
67+
await subject.getUserPart() !== user.username &&
68+
await subject.isUserDirectory()
6869
) {
6970
this.log.noticeme('THIS HAPPEN');
7071
const ll_readshares = new LLReadShares();

src/backend/src/filesystem/ll_operations/ll_readshares.js

+47-44
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@
1616
* You should have received a copy of the GNU Affero General Public License
1717
* along with this program. If not, see <https://www.gnu.org/licenses/>.
1818
*/
19+
const { get_user } = require("../../helpers");
20+
const { PermissionUtil } = require("../../services/auth/PermissionService");
21+
const { DB_WRITE } = require("../../services/database/consts");
1922
const { Context } = require("../../util/context");
2023
const { TYPE_DIRECTORY } = require("../FSNodeContext");
24+
const { NodeUIDSelector } = require("../node/selectors");
2125
const { LLFilesystemOperation } = require("./definitions");
2226
const { LLReadDir } = require("./ll_readdir");
2327

@@ -32,57 +36,56 @@ class LLReadShares extends LLFilesystemOperation {
3236
`;
3337

3438
async _run () {
39+
const { subject, user, actor, depth = 0 } = this.values;
40+
41+
const svc = this.context.get('services');
42+
43+
const svc_fs = svc.get('filesystem');
44+
const svc_acl = svc.get('acl');
45+
const db = svc.get('database').get(DB_WRITE, 'll_readshares');
46+
47+
const issuer_username = await subject.getUserPart();
48+
const issuer_user = await get_user({ username: issuer_username });
49+
const rows = await db.read(
50+
'SELECT DISTINCT permission FROM `user_to_user_permissions` ' +
51+
'WHERE `holder_user_id` = ? AND `issuer_user_id` = ? ' +
52+
'AND `permission` LIKE ?',
53+
[user.id, issuer_user.id, 'fs:%']
54+
);
55+
56+
const fsentry_uuids = [];
57+
for ( const row of rows ) {
58+
const parts = PermissionUtil.split(row.permission);
59+
fsentry_uuids.push(parts[1]);
60+
}
61+
3562
const results = [];
36-
const stats = await this.recursive_part(results, this.values);
37-
// console.log('LL_READ_SHARES_STATS !!!!!', stats);
38-
39-
return results;
40-
}
41-
42-
async recursive_part (results, { subject, user, actor, depth = 0 }) {
43-
actor = actor || Context.get('actor');
63+
4464
const ll_readdir = new LLReadDir();
45-
const children = await ll_readdir.run({
46-
subject, user,
65+
let interm_results = await ll_readdir.run({
66+
subject,
67+
actor,
68+
user,
4769
no_thumbs: true,
4870
no_assocs: true,
4971
no_acl: true,
5072
});
51-
52-
const svc = Context.get('services');
53-
const svc_acl = svc.get('acl');
54-
55-
const promises = [];
56-
57-
for ( const child of children ) {
58-
// If we have at least see permission: terminal node
59-
const acl_result = await svc_acl.check(actor, child, 'see');
60-
console.log(
61-
'\x1B[31;1mWHAT DIS?\x1B[0m',
62-
actor,
63-
child.entry?.path,
64-
child.selectors_[0].describe(),
65-
acl_result,
66-
)
67-
if ( acl_result ) {
68-
results.push(child);
69-
continue;
70-
}
71-
72-
if ( await child.get('type') !== TYPE_DIRECTORY ) {
73-
continue;
74-
}
75-
76-
const p = this.recursive_part(results, {
77-
subject: child,
78-
user,
79-
depth: depth + 1,
80-
});
81-
promises.push(p);
73+
74+
// Clone interm_results in case ll_readdir ever implements caching
75+
interm_results = interm_results.slice();
76+
77+
for ( const fsentry_uuid of fsentry_uuids ) {
78+
const node = await svc_fs.node(new NodeUIDSelector(fsentry_uuid));
79+
if ( ! node ) continue;
80+
interm_results.push(node);
8281
}
83-
84-
const stats = await Promise.all(promises);
85-
return Math.max(depth, ...stats);
82+
83+
for ( const node of interm_results ) {
84+
if ( ! await svc_acl.check(actor, node, 'see') ) continue;
85+
results.push(node);
86+
}
87+
88+
return results;
8689
}
8790
}
8891

0 commit comments

Comments
 (0)