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.
This commit is contained in:
KernelDeimos
2024-11-13 22:44:54 -05:00
parent 34836e374f
commit cd22425a3d
2 changed files with 49 additions and 45 deletions
@@ -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();
@@ -16,8 +16,12 @@
* 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 { 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;
}
}