forked from wangziqi/gongxue-base
feat: harden content asset access
This commit is contained in:
@@ -3148,11 +3148,29 @@ async function testTenantContentAssetsAndImports() {
|
||||
regionId: ids.region,
|
||||
subjectId: ids.subject,
|
||||
categoryId: ids.category,
|
||||
metadata: { source: 'api-integration' },
|
||||
metadata: { source: 'api-integration', providerManagedAccess: true },
|
||||
},
|
||||
});
|
||||
assert.equal(asset.item?.visibility, 'svip', 'tenant admin should create svip asset');
|
||||
|
||||
const lockedCdnAsset = await request('/api/tenant-content/assets', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
method: 'PUT',
|
||||
body: {
|
||||
title: '集成测试未授权 CDN SVIP 资料',
|
||||
assetType: 'pdf',
|
||||
storageProvider: 'external_url',
|
||||
cdnUrl: 'https://example.test/resources/locked-without-provider-managed.pdf',
|
||||
fileName: 'locked-without-provider-managed.pdf',
|
||||
mimeType: 'application/pdf',
|
||||
visibility: 'svip',
|
||||
regionId: ids.region,
|
||||
subjectId: ids.subject,
|
||||
categoryId: ids.category,
|
||||
metadata: { source: 'api-integration' },
|
||||
},
|
||||
});
|
||||
|
||||
const adminAssets = await request('/api/tenant-content/assets', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
query: { assetType: 'pdf', regionId: ids.region },
|
||||
@@ -3178,6 +3196,31 @@ async function testTenantContentAssetsAndImports() {
|
||||
assert.equal(download.access?.svip, true, 'asset download should report svip access');
|
||||
assert.equal(download.download?.url, 'https://example.test/resources/integration.pdf', 'external asset download should use cdn url');
|
||||
assert.equal(download.download?.signatureMode, 'public-or-provider-managed', 'external asset should be marked provider managed');
|
||||
assert.equal(download.download?.expiresInSec, 300, 'locked student asset downloads should use short TTL');
|
||||
|
||||
const deniedLockedCdn = await request('/api/catalog/assets/download', {
|
||||
query: { assetId: lockedCdnAsset.item.id },
|
||||
expectStatus: 409,
|
||||
});
|
||||
assert.equal(deniedLockedCdn.code, 'ASSET_CDN_ACCESS_NOT_ALLOWED', 'locked cdn asset should require explicit provider-managed access');
|
||||
|
||||
const accessEventsAfterLockedDeny = await request('/api/tenant-content/assets/access-events', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
query: { assetId: lockedCdnAsset.item.id },
|
||||
});
|
||||
assert.ok(
|
||||
accessEventsAfterLockedDeny.items?.some(item => item.result === 'denied' && item.denyCode === 'ASSET_CDN_ACCESS_NOT_ALLOWED'),
|
||||
'locked cdn denial should be recorded as an asset access event',
|
||||
);
|
||||
|
||||
const accessEventsAfterDownload = await request('/api/tenant-content/assets/access-events', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
query: { assetId: asset.item.id },
|
||||
});
|
||||
assert.ok(
|
||||
accessEventsAfterDownload.items?.some(item => item.accessType === 'download' && item.result === 'granted'),
|
||||
'successful student asset download should be recorded as an access event',
|
||||
);
|
||||
|
||||
const localAsset = await request('/api/tenant-content/assets', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
@@ -3233,6 +3276,7 @@ async function testTenantContentAssetsAndImports() {
|
||||
assert.equal(localPreview.preview?.method, 'GET', 'asset preview should sign GET');
|
||||
assert.equal(localPreview.preview?.signatureMode, 'local-placeholder', 'local asset preview should use local placeholder signer');
|
||||
assert.ok(localPreview.preview?.url?.includes('disposition=inline'), 'asset preview should request inline disposition');
|
||||
assert.equal(localPreview.preview?.expiresInSec, 300, 'student inline previews should use short TTL');
|
||||
|
||||
const adminPreview = await request('/api/tenant-content/assets/sign-preview', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
@@ -3241,6 +3285,15 @@ async function testTenantContentAssetsAndImports() {
|
||||
});
|
||||
assert.ok(adminPreview.preview?.url?.includes('disposition=inline'), 'admin preview should request inline disposition');
|
||||
|
||||
const localAccessEvents = await request('/api/tenant-content/assets/access-events', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
query: { assetId: localAsset.item.id },
|
||||
});
|
||||
assert.ok(
|
||||
localAccessEvents.items?.some(item => item.accessType === 'preview' && item.expiresInSec === 300),
|
||||
'student preview access event should include short TTL',
|
||||
);
|
||||
|
||||
const failedAsset = await request('/api/tenant-content/assets', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
method: 'PUT',
|
||||
|
||||
Reference in New Issue
Block a user