plugin-file-preview-auth 1.2.9 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server/plugin.js +84 -2
- package/package.json +1 -1
package/dist/server/plugin.js
CHANGED
|
@@ -377,15 +377,97 @@ class PluginFilePreviewAuthServer extends import_server.Plugin {
|
|
|
377
377
|
}
|
|
378
378
|
ctx.throw(404, "Attachment not found for this preview file");
|
|
379
379
|
}
|
|
380
|
+
getParentCollections(fileCollectionName) {
|
|
381
|
+
const parents = [];
|
|
382
|
+
for (const collection of this.db.collections.values()) {
|
|
383
|
+
if (collection.name === fileCollectionName) continue;
|
|
384
|
+
for (const field of collection.fields.values()) {
|
|
385
|
+
const options = field.options || {};
|
|
386
|
+
if (field.type === "belongsToMany" && options.target === fileCollectionName && options.through) {
|
|
387
|
+
parents.push({
|
|
388
|
+
collectionName: collection.name,
|
|
389
|
+
throughTable: options.through,
|
|
390
|
+
otherKey: options.otherKey || "attachmentId",
|
|
391
|
+
foreignKey: options.foreignKey || `${collection.model.name.toLowerCase()}Id`
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return parents;
|
|
397
|
+
}
|
|
398
|
+
async checkParentCollectionAccess(attachmentId, fileCollectionName, currentRoles, ctx) {
|
|
399
|
+
var _a, _b, _c;
|
|
400
|
+
const parents = this.getParentCollections(fileCollectionName);
|
|
401
|
+
if (parents.length === 0) {
|
|
402
|
+
const canView = this.app.acl.can({
|
|
403
|
+
roles: currentRoles,
|
|
404
|
+
resource: fileCollectionName,
|
|
405
|
+
action: "view"
|
|
406
|
+
});
|
|
407
|
+
return !!canView;
|
|
408
|
+
}
|
|
409
|
+
for (const parent of parents) {
|
|
410
|
+
const canView = this.app.acl.can({
|
|
411
|
+
roles: currentRoles,
|
|
412
|
+
resource: parent.collectionName,
|
|
413
|
+
action: "view"
|
|
414
|
+
});
|
|
415
|
+
if (!canView) continue;
|
|
416
|
+
try {
|
|
417
|
+
const throughCollection = this.db.getCollection(parent.throughTable);
|
|
418
|
+
if (throughCollection) {
|
|
419
|
+
const links = await throughCollection.repository.find({
|
|
420
|
+
filter: { [parent.otherKey]: attachmentId }
|
|
421
|
+
});
|
|
422
|
+
if (links.length > 0) {
|
|
423
|
+
const parentIds = links.map((l) => l.get(parent["foreignKey"])).filter(Boolean);
|
|
424
|
+
if (parentIds.length > 0) {
|
|
425
|
+
let dataScopeFilter = ((_a = canView.params) == null ? void 0 : _a.filter) || {};
|
|
426
|
+
if (ctx && ctx.app.environment) {
|
|
427
|
+
dataScopeFilter = ctx.app.environment.renderJsonTemplate(dataScopeFilter, {
|
|
428
|
+
$user: ((_b = ctx.state.currentUser) == null ? void 0 : _b.toJSON) ? ctx.state.currentUser.toJSON() : ctx.state.currentUser,
|
|
429
|
+
$nRole: ctx.state.currentRole
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
const parentCollection = this.db.getCollection(parent.collectionName);
|
|
433
|
+
const pk = ((_c = parentCollection == null ? void 0 : parentCollection.model) == null ? void 0 : _c.primaryKeyAttribute) || "id";
|
|
434
|
+
const count = await parentCollection.repository.count({
|
|
435
|
+
filter: {
|
|
436
|
+
$and: [
|
|
437
|
+
{ [pk]: { $in: parentIds } },
|
|
438
|
+
dataScopeFilter
|
|
439
|
+
]
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
if (count > 0) return true;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
} catch (error) {
|
|
447
|
+
this.log.warn(`[FilePreviewAuth] Failed to query through table "${parent.throughTable}":`, error.message);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
380
452
|
async assertCanAccessAttachment(ctx, attachment) {
|
|
453
|
+
var _a, _b;
|
|
381
454
|
const currentUser = this.assertAuthenticated(ctx);
|
|
382
455
|
const createdById = getAttachmentValue(attachment, "createdById");
|
|
383
456
|
const currentRoles = ctx.state.currentRoles || [];
|
|
384
457
|
const userRoles = currentUser.roles || [];
|
|
385
458
|
const isOwner = createdById != null && String(createdById) === String(currentUser.id);
|
|
386
459
|
const isAdmin = currentRoles.includes("root") || currentRoles.includes("admin") || userRoles.some((role) => role === "root" || role === "admin" || (role == null ? void 0 : role.name) === "root" || (role == null ? void 0 : role.name) === "admin");
|
|
387
|
-
if (
|
|
388
|
-
|
|
460
|
+
if (isOwner || isAdmin) {
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
const attachmentId = getAttachmentValue(attachment, "id");
|
|
464
|
+
if (!attachmentId) {
|
|
465
|
+
ctx.throw(403, "Permission denied: virtual attachment cannot be accessed");
|
|
466
|
+
}
|
|
467
|
+
const collectionName = ((_b = (_a = attachment.constructor) == null ? void 0 : _a.collection) == null ? void 0 : _b.name) || getAttachmentValue(attachment, "collectionName") || "attachments";
|
|
468
|
+
const hasParentAccess = await this.checkParentCollectionAccess(attachmentId, collectionName, currentRoles, ctx);
|
|
469
|
+
if (!hasParentAccess) {
|
|
470
|
+
ctx.throw(403, "Permission denied: you do not have permission to access this attachment");
|
|
389
471
|
}
|
|
390
472
|
}
|
|
391
473
|
assertAuthenticated(ctx) {
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"description": "Preview PDF, image, and text files with Bearer token authentication via blob URLs.",
|
|
7
7
|
"description.vi-VN": "Xem trước file PDF, hình ảnh và văn bản với xác thực Bearer token qua blob URL.",
|
|
8
8
|
"description.zh-CN": "通过 Bearer 令牌认证和 Blob URL 预览 PDF、图片和文本文件。",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.3.0",
|
|
10
10
|
"main": "dist/server/index.js",
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|