@payloadcms/storage-vercel-blob 4.0.0-canary.33 → 4.0.0-canary.34
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/adapter.d.ts +3 -1
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +54 -24
- package/dist/adapter.js.map +1 -1
- package/dist/adapter.spec.js +124 -0
- package/dist/adapter.spec.js.map +1 -0
- package/dist/authorizeFileOverwrite.d.ts +16 -0
- package/dist/authorizeFileOverwrite.d.ts.map +1 -0
- package/dist/authorizeFileOverwrite.js +117 -0
- package/dist/authorizeFileOverwrite.js.map +1 -0
- package/dist/authorizeFileOverwrite.spec.js +92 -0
- package/dist/authorizeFileOverwrite.spec.js.map +1 -0
- package/dist/deleteFile.d.ts +2 -5
- package/dist/deleteFile.d.ts.map +1 -1
- package/dist/deleteFile.js +3 -10
- package/dist/deleteFile.js.map +1 -1
- package/dist/generateURL.d.ts +1 -0
- package/dist/generateURL.d.ts.map +1 -1
- package/dist/generateURL.js +13 -9
- package/dist/generateURL.js.map +1 -1
- package/dist/getCollectionSources.d.ts +20 -0
- package/dist/getCollectionSources.d.ts.map +1 -0
- package/dist/getCollectionSources.js +27 -0
- package/dist/getCollectionSources.js.map +1 -0
- package/dist/getCollectionSources.spec.js +67 -0
- package/dist/getCollectionSources.spec.js.map +1 -0
- package/dist/getFile.d.ts +3 -3
- package/dist/getFile.d.ts.map +1 -1
- package/dist/getFile.js +9 -7
- package/dist/getFile.js.map +1 -1
- package/dist/index.d.ts +8 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -5
- package/dist/index.js.map +1 -1
- package/dist/staticHandler.spec.js +71 -0
- package/dist/staticHandler.spec.js.map +1 -0
- package/dist/uploadFile.d.ts +2 -5
- package/dist/uploadFile.d.ts.map +1 -1
- package/dist/uploadFile.js +2 -9
- package/dist/uploadFile.js.map +1 -1
- package/package.json +4 -4
package/dist/adapter.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import type { Adapter, ClientUploadsConfig } from '@payloadcms/plugin-cloud-storage/types';
|
|
2
|
+
import type { VercelBlobCollectionSource } from './authorizeFileOverwrite.js';
|
|
2
3
|
interface CreateVercelBlobAdapterArgs {
|
|
3
4
|
access: 'public';
|
|
4
5
|
addRandomSuffix?: boolean;
|
|
5
6
|
baseUrl: string;
|
|
6
7
|
cacheControlMaxAge: number;
|
|
7
8
|
clientUploads?: ClientUploadsConfig;
|
|
9
|
+
collectionSources: VercelBlobCollectionSource[];
|
|
8
10
|
token: string;
|
|
9
11
|
useCompositePrefixes?: boolean;
|
|
10
12
|
}
|
|
11
|
-
export declare function createVercelBlobAdapter({ access, addRandomSuffix, baseUrl, cacheControlMaxAge, clientUploads, token, useCompositePrefixes, }: CreateVercelBlobAdapterArgs): Adapter;
|
|
13
|
+
export declare function createVercelBlobAdapter({ access, addRandomSuffix, baseUrl, cacheControlMaxAge, clientUploads, collectionSources, token, useCompositePrefixes, }: CreateVercelBlobAdapterArgs): Adapter;
|
|
12
14
|
export {};
|
|
13
15
|
//# sourceMappingURL=adapter.d.ts.map
|
package/dist/adapter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,mBAAmB,EAEpB,MAAM,wCAAwC,CAAA;
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,mBAAmB,EAEpB,MAAM,wCAAwC,CAAA;AAU/C,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAA;AAQ7E,UAAU,2BAA2B;IACnC,MAAM,EAAE,QAAQ,CAAA;IAChB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,kBAAkB,EAAE,MAAM,CAAA;IAC1B,aAAa,CAAC,EAAE,mBAAmB,CAAA;IACnC,iBAAiB,EAAE,0BAA0B,EAAE,CAAA;IAC/C,KAAK,EAAE,MAAM,CAAA;IACb,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAED,wBAAgB,uBAAuB,CAAC,EACtC,MAAM,EACN,eAAe,EACf,OAAO,EACP,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,KAAK,EACL,oBAA4B,GAC7B,EAAE,2BAA2B,GAAG,OAAO,CAgJvC"}
|
package/dist/adapter.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { resolveSignedURLKey } from '@payloadcms/plugin-cloud-storage/utilities';
|
|
1
|
+
import { buildUploadStoragePathData, resolveSignedURLKey } from '@payloadcms/plugin-cloud-storage/utilities';
|
|
2
2
|
import { generateClientTokenFromReadWriteToken } from '@vercel/blob/client';
|
|
3
3
|
import { Forbidden } from 'payload';
|
|
4
|
+
import { assertClientUploadAllowed, createClientUploadReceipt } from 'payload/internal';
|
|
5
|
+
import { authorizeClientOverwrite } from './authorizeFileOverwrite.js';
|
|
4
6
|
import { deleteFile } from './deleteFile.js';
|
|
5
7
|
import { generateURL } from './generateURL.js';
|
|
6
8
|
import { getFile } from './getFile.js';
|
|
7
9
|
import { uploadFile } from './uploadFile.js';
|
|
8
|
-
export function createVercelBlobAdapter({ access, addRandomSuffix, baseUrl, cacheControlMaxAge, clientUploads, token, useCompositePrefixes = false }) {
|
|
10
|
+
export function createVercelBlobAdapter({ access, addRandomSuffix, baseUrl, cacheControlMaxAge, clientUploads, collectionSources, token, useCompositePrefixes = false }) {
|
|
9
11
|
const clientUploadsAccess = typeof clientUploads === 'object' ? clientUploads.access : undefined;
|
|
10
12
|
return ({ collection, prefix = '' })=>({
|
|
11
13
|
name: 'vercel-blob',
|
|
@@ -21,7 +23,40 @@ export function createVercelBlobAdapter({ access, addRandomSuffix, baseUrl, cach
|
|
|
21
23
|
}) : !req.user)) {
|
|
22
24
|
throw new Forbidden(req.t);
|
|
23
25
|
}
|
|
24
|
-
|
|
26
|
+
assertClientUploadAllowed({
|
|
27
|
+
collection,
|
|
28
|
+
filename,
|
|
29
|
+
mimeType
|
|
30
|
+
});
|
|
31
|
+
const requested = buildUploadStoragePathData({
|
|
32
|
+
collectionPrefix: prefix,
|
|
33
|
+
docPrefix,
|
|
34
|
+
filename,
|
|
35
|
+
useCompositePrefixes
|
|
36
|
+
});
|
|
37
|
+
const allowOverwrite = await authorizeClientOverwrite({
|
|
38
|
+
collectionPrefix: prefix,
|
|
39
|
+
collectionSources,
|
|
40
|
+
overrideAccess,
|
|
41
|
+
req,
|
|
42
|
+
requestedCollectionSlug: collectionSlug,
|
|
43
|
+
requestedFilename: requested.sanitizedFilename,
|
|
44
|
+
requestedStorageFilePath: requested.storageFilePath
|
|
45
|
+
});
|
|
46
|
+
const resolved = allowOverwrite ? {
|
|
47
|
+
...requested,
|
|
48
|
+
uploadReference: {
|
|
49
|
+
prefix: requested.sanitizedDocPrefix,
|
|
50
|
+
signedReceipt: createClientUploadReceipt({
|
|
51
|
+
allowOverwrite: true,
|
|
52
|
+
collectionSlug,
|
|
53
|
+
filename: requested.sanitizedFilename,
|
|
54
|
+
filePrefix: requested.sanitizedDocPrefix,
|
|
55
|
+
req,
|
|
56
|
+
storageFilePath: requested.storageFilePath
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
} : await resolveSignedURLKey({
|
|
25
60
|
collectionPrefix: prefix,
|
|
26
61
|
collectionSlug,
|
|
27
62
|
docPrefix,
|
|
@@ -33,16 +68,18 @@ export function createVercelBlobAdapter({ access, addRandomSuffix, baseUrl, cach
|
|
|
33
68
|
name: 'uploadToVercelBlob',
|
|
34
69
|
type: 'dispatch',
|
|
35
70
|
data: {
|
|
36
|
-
pathname: resolved.
|
|
71
|
+
pathname: resolved.storageFilePath,
|
|
37
72
|
token: await generateClientTokenFromReadWriteToken({
|
|
38
|
-
addRandomSuffix,
|
|
73
|
+
addRandomSuffix: false,
|
|
39
74
|
allowedContentTypes: mimeType ? [
|
|
40
75
|
mimeType
|
|
41
76
|
] : undefined,
|
|
42
|
-
allowOverwrite
|
|
77
|
+
...allowOverwrite && {
|
|
78
|
+
allowOverwrite: true
|
|
79
|
+
},
|
|
43
80
|
cacheControlMaxAge,
|
|
44
81
|
maximumSizeInBytes: filesize,
|
|
45
|
-
pathname: resolved.
|
|
82
|
+
pathname: resolved.storageFilePath,
|
|
46
83
|
token
|
|
47
84
|
})
|
|
48
85
|
},
|
|
@@ -50,12 +87,11 @@ export function createVercelBlobAdapter({ access, addRandomSuffix, baseUrl, cach
|
|
|
50
87
|
filename: resolved.sanitizedFilename,
|
|
51
88
|
mimeType,
|
|
52
89
|
size: filesize,
|
|
53
|
-
uploadReference:
|
|
54
|
-
prefix: resolved.sanitizedDocPrefix
|
|
55
|
-
}
|
|
90
|
+
uploadReference: resolved.uploadReference
|
|
56
91
|
}
|
|
57
92
|
};
|
|
58
93
|
},
|
|
94
|
+
requiresUploadReceipt: true,
|
|
59
95
|
useInAdmin: true
|
|
60
96
|
},
|
|
61
97
|
generateURL: ({ filename, prefix: urlPrefix = '' })=>generateURL({
|
|
@@ -65,40 +101,34 @@ export function createVercelBlobAdapter({ access, addRandomSuffix, baseUrl, cach
|
|
|
65
101
|
prefix: urlPrefix,
|
|
66
102
|
useCompositePrefixes
|
|
67
103
|
}),
|
|
68
|
-
handleDelete: ({
|
|
104
|
+
handleDelete: ({ storageFilePath })=>deleteFile({
|
|
69
105
|
baseUrl,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
filename,
|
|
73
|
-
token,
|
|
74
|
-
useCompositePrefixes
|
|
106
|
+
storageFilePath,
|
|
107
|
+
token
|
|
75
108
|
}),
|
|
76
|
-
handleUpload: async ({ data, file: { buffer,
|
|
109
|
+
handleUpload: async ({ data, file: { buffer, mimeType }, storageFilePath })=>{
|
|
77
110
|
const result = await uploadFile({
|
|
78
111
|
access,
|
|
79
112
|
addRandomSuffix,
|
|
80
113
|
buffer,
|
|
81
114
|
cacheControlMaxAge,
|
|
82
|
-
collectionPrefix: prefix,
|
|
83
|
-
docPrefix: data.prefix,
|
|
84
|
-
filename,
|
|
85
115
|
mimeType,
|
|
86
|
-
|
|
87
|
-
|
|
116
|
+
storageFilePath,
|
|
117
|
+
token
|
|
88
118
|
});
|
|
89
119
|
if (result.filename) {
|
|
90
120
|
data.filename = result.filename;
|
|
91
121
|
}
|
|
92
122
|
return data;
|
|
93
123
|
},
|
|
94
|
-
staticHandler: (req, { headers, params: { filename,
|
|
124
|
+
staticHandler: (req, { doc, headers, params: { filename, uploadReference } })=>getFile({
|
|
95
125
|
baseUrl,
|
|
96
126
|
cacheControlMaxAge,
|
|
97
127
|
collection,
|
|
98
128
|
collectionPrefix: prefix,
|
|
129
|
+
doc,
|
|
99
130
|
filename,
|
|
100
131
|
incomingHeaders: headers,
|
|
101
|
-
prefixQueryParam,
|
|
102
132
|
req,
|
|
103
133
|
token,
|
|
104
134
|
uploadReference,
|
package/dist/adapter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapter.ts"],"sourcesContent":["import type {\n Adapter,\n ClientUploadsConfig,\n GeneratedAdapter,\n} from '@payloadcms/plugin-cloud-storage/types'\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../src/adapter.ts"],"sourcesContent":["import type {\n Adapter,\n ClientUploadsConfig,\n GeneratedAdapter,\n} from '@payloadcms/plugin-cloud-storage/types'\n\nimport {\n buildUploadStoragePathData,\n resolveSignedURLKey,\n} from '@payloadcms/plugin-cloud-storage/utilities'\nimport { generateClientTokenFromReadWriteToken } from '@vercel/blob/client'\nimport { Forbidden } from 'payload'\nimport { assertClientUploadAllowed, createClientUploadReceipt } from 'payload/internal'\n\nimport type { VercelBlobCollectionSource } from './authorizeFileOverwrite.js'\n\nimport { authorizeClientOverwrite } from './authorizeFileOverwrite.js'\nimport { deleteFile } from './deleteFile.js'\nimport { generateURL } from './generateURL.js'\nimport { getFile } from './getFile.js'\nimport { uploadFile } from './uploadFile.js'\n\ninterface CreateVercelBlobAdapterArgs {\n access: 'public'\n addRandomSuffix?: boolean\n baseUrl: string\n cacheControlMaxAge: number\n clientUploads?: ClientUploadsConfig\n collectionSources: VercelBlobCollectionSource[]\n token: string\n useCompositePrefixes?: boolean\n}\n\nexport function createVercelBlobAdapter({\n access,\n addRandomSuffix,\n baseUrl,\n cacheControlMaxAge,\n clientUploads,\n collectionSources,\n token,\n useCompositePrefixes = false,\n}: CreateVercelBlobAdapterArgs): Adapter {\n const clientUploadsAccess = typeof clientUploads === 'object' ? clientUploads.access : undefined\n\n return ({ collection, prefix = '' }): GeneratedAdapter => ({\n name: 'vercel-blob',\n\n uploadInstructions: {\n adminHandler: {\n path: '@payloadcms/storage-vercel-blob/client#VercelBlobClientUploadHandler',\n },\n enabled: Boolean(clientUploads),\n generate: async ({\n collectionSlug,\n docPrefix,\n filename,\n filesize,\n mimeType,\n overrideAccess,\n req,\n }) => {\n if (\n !overrideAccess &&\n (clientUploadsAccess ? !(await clientUploadsAccess({ collectionSlug, req })) : !req.user)\n ) {\n throw new Forbidden(req.t)\n }\n\n assertClientUploadAllowed({ collection, filename, mimeType })\n\n const requested = buildUploadStoragePathData({\n collectionPrefix: prefix,\n docPrefix,\n filename,\n useCompositePrefixes,\n })\n const allowOverwrite = await authorizeClientOverwrite({\n collectionPrefix: prefix,\n collectionSources,\n overrideAccess,\n req,\n requestedCollectionSlug: collectionSlug,\n requestedFilename: requested.sanitizedFilename,\n requestedStorageFilePath: requested.storageFilePath,\n })\n const resolved = allowOverwrite\n ? {\n ...requested,\n uploadReference: {\n prefix: requested.sanitizedDocPrefix,\n signedReceipt: createClientUploadReceipt({\n allowOverwrite: true,\n collectionSlug,\n filename: requested.sanitizedFilename,\n filePrefix: requested.sanitizedDocPrefix,\n req,\n storageFilePath: requested.storageFilePath,\n }),\n },\n }\n : await resolveSignedURLKey({\n collectionPrefix: prefix,\n collectionSlug,\n docPrefix,\n filename,\n req,\n useCompositePrefixes,\n })\n\n return {\n name: 'uploadToVercelBlob',\n type: 'dispatch',\n data: {\n pathname: resolved.storageFilePath,\n token: await generateClientTokenFromReadWriteToken({\n addRandomSuffix: false,\n allowedContentTypes: mimeType ? [mimeType] : undefined,\n ...(allowOverwrite && { allowOverwrite: true }),\n cacheControlMaxAge,\n maximumSizeInBytes: filesize,\n pathname: resolved.storageFilePath,\n token,\n }),\n },\n file: {\n filename: resolved.sanitizedFilename,\n mimeType,\n size: filesize,\n uploadReference: resolved.uploadReference,\n },\n }\n },\n requiresUploadReceipt: true,\n useInAdmin: true,\n },\n\n generateURL: ({ filename, prefix: urlPrefix = '' }) =>\n generateURL({\n baseUrl,\n collectionPrefix: prefix,\n filename,\n prefix: urlPrefix,\n useCompositePrefixes,\n }),\n\n handleDelete: ({ storageFilePath }) =>\n deleteFile({\n baseUrl,\n storageFilePath,\n token,\n }),\n\n handleUpload: async ({ data, file: { buffer, mimeType }, storageFilePath }) => {\n const result = await uploadFile({\n access,\n addRandomSuffix,\n buffer,\n cacheControlMaxAge,\n mimeType,\n storageFilePath,\n token,\n })\n\n if (result.filename) {\n data.filename = result.filename\n }\n\n return data\n },\n\n staticHandler: (req, { doc, headers, params: { filename, uploadReference } }) =>\n getFile({\n baseUrl,\n cacheControlMaxAge,\n collection,\n collectionPrefix: prefix,\n doc,\n filename,\n incomingHeaders: headers,\n req,\n token,\n uploadReference,\n useCompositePrefixes,\n }),\n })\n}\n"],"names":["buildUploadStoragePathData","resolveSignedURLKey","generateClientTokenFromReadWriteToken","Forbidden","assertClientUploadAllowed","createClientUploadReceipt","authorizeClientOverwrite","deleteFile","generateURL","getFile","uploadFile","createVercelBlobAdapter","access","addRandomSuffix","baseUrl","cacheControlMaxAge","clientUploads","collectionSources","token","useCompositePrefixes","clientUploadsAccess","undefined","collection","prefix","name","uploadInstructions","adminHandler","path","enabled","Boolean","generate","collectionSlug","docPrefix","filename","filesize","mimeType","overrideAccess","req","user","t","requested","collectionPrefix","allowOverwrite","requestedCollectionSlug","requestedFilename","sanitizedFilename","requestedStorageFilePath","storageFilePath","resolved","uploadReference","sanitizedDocPrefix","signedReceipt","filePrefix","type","data","pathname","allowedContentTypes","maximumSizeInBytes","file","size","requiresUploadReceipt","useInAdmin","urlPrefix","handleDelete","handleUpload","buffer","result","staticHandler","doc","headers","params","incomingHeaders"],"mappings":"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"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
const mocks = vi.hoisted(()=>({
|
|
3
|
+
generateClientToken: vi.fn(async ()=>'client-token'),
|
|
4
|
+
// Resolves the stored location of an owning document, so it matches the requested key.
|
|
5
|
+
buildStoragePathData: vi.fn(()=>({
|
|
6
|
+
storageFilePath: 'reference.png',
|
|
7
|
+
sanitizedCollectionPrefix: '',
|
|
8
|
+
sanitizedDocPrefix: '',
|
|
9
|
+
sanitizedFilename: 'reference.png'
|
|
10
|
+
})),
|
|
11
|
+
buildUploadStoragePathData: vi.fn(()=>({
|
|
12
|
+
storageFilePath: 'reference.png',
|
|
13
|
+
sanitizedCollectionPrefix: '',
|
|
14
|
+
sanitizedDocPrefix: '',
|
|
15
|
+
sanitizedFilename: 'reference.png'
|
|
16
|
+
})),
|
|
17
|
+
isStoragePathWithinCollectionPrefix: vi.fn(()=>true),
|
|
18
|
+
resolveSignedURLKey: vi.fn(async ()=>({
|
|
19
|
+
storageFilePath: 'reference-1.png',
|
|
20
|
+
sanitizedDocPrefix: '',
|
|
21
|
+
sanitizedFilename: 'reference-1.png',
|
|
22
|
+
uploadReference: {
|
|
23
|
+
prefix: '',
|
|
24
|
+
signedReceipt: 'upload-receipt'
|
|
25
|
+
}
|
|
26
|
+
}))
|
|
27
|
+
}));
|
|
28
|
+
vi.mock('@payloadcms/plugin-cloud-storage/utilities', ()=>({
|
|
29
|
+
buildStoragePathData: mocks.buildStoragePathData,
|
|
30
|
+
buildUploadStoragePathData: mocks.buildUploadStoragePathData,
|
|
31
|
+
isStoragePathWithinCollectionPrefix: mocks.isStoragePathWithinCollectionPrefix,
|
|
32
|
+
resolveSignedURLKey: mocks.resolveSignedURLKey
|
|
33
|
+
}));
|
|
34
|
+
vi.mock('@vercel/blob/client', ()=>({
|
|
35
|
+
generateClientTokenFromReadWriteToken: mocks.generateClientToken
|
|
36
|
+
}));
|
|
37
|
+
import { createVercelBlobAdapter } from './adapter.js';
|
|
38
|
+
const generateInstructions = async ({ hasOwner })=>{
|
|
39
|
+
const adapter = createVercelBlobAdapter({
|
|
40
|
+
access: 'public',
|
|
41
|
+
baseUrl: 'https://example.com',
|
|
42
|
+
cacheControlMaxAge: 60,
|
|
43
|
+
clientUploads: true,
|
|
44
|
+
collectionSources: [
|
|
45
|
+
{
|
|
46
|
+
collectionPrefix: '',
|
|
47
|
+
collectionSlug: 'media',
|
|
48
|
+
useCompositePrefixes: false
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
token: 'read-write-token'
|
|
52
|
+
});
|
|
53
|
+
const generatedAdapter = adapter({
|
|
54
|
+
collection: {
|
|
55
|
+
slug: 'media'
|
|
56
|
+
},
|
|
57
|
+
prefix: ''
|
|
58
|
+
});
|
|
59
|
+
const req = {
|
|
60
|
+
payload: {
|
|
61
|
+
collections: {
|
|
62
|
+
media: {
|
|
63
|
+
config: {
|
|
64
|
+
access: {
|
|
65
|
+
update: async ()=>true
|
|
66
|
+
},
|
|
67
|
+
upload: true
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
find: vi.fn(async ()=>({
|
|
72
|
+
docs: hasOwner ? [
|
|
73
|
+
{
|
|
74
|
+
filename: 'reference.png',
|
|
75
|
+
id: 1
|
|
76
|
+
}
|
|
77
|
+
] : []
|
|
78
|
+
})),
|
|
79
|
+
secret: 'secret'
|
|
80
|
+
},
|
|
81
|
+
t: vi.fn()
|
|
82
|
+
};
|
|
83
|
+
return generatedAdapter.uploadInstructions?.generate({
|
|
84
|
+
collectionSlug: 'media',
|
|
85
|
+
filename: 'reference.png',
|
|
86
|
+
filesize: 100,
|
|
87
|
+
mimeType: 'image/png',
|
|
88
|
+
overrideAccess: true,
|
|
89
|
+
req
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
describe('createVercelBlobAdapter', ()=>{
|
|
93
|
+
beforeEach(()=>{
|
|
94
|
+
vi.clearAllMocks();
|
|
95
|
+
});
|
|
96
|
+
it('should disable overwrite when no document owns the requested key', async ()=>{
|
|
97
|
+
const instructions = await generateInstructions({
|
|
98
|
+
hasOwner: false
|
|
99
|
+
});
|
|
100
|
+
const tokenOptions = mocks.generateClientToken.mock.calls[0][0];
|
|
101
|
+
expect(instructions).toMatchObject({
|
|
102
|
+
data: {
|
|
103
|
+
pathname: 'reference-1.png'
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
expect(tokenOptions).not.toHaveProperty('allowOverwrite');
|
|
107
|
+
});
|
|
108
|
+
it('should allow an authorized owner to update the requested key', async ()=>{
|
|
109
|
+
const instructions = await generateInstructions({
|
|
110
|
+
hasOwner: true
|
|
111
|
+
});
|
|
112
|
+
expect(instructions).toMatchObject({
|
|
113
|
+
data: {
|
|
114
|
+
pathname: 'reference.png'
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
expect(mocks.generateClientToken).toHaveBeenCalledWith(expect.objectContaining({
|
|
118
|
+
allowOverwrite: true,
|
|
119
|
+
pathname: 'reference.png'
|
|
120
|
+
}));
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
//# sourceMappingURL=adapter.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapter.spec.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest'\n\nconst mocks = vi.hoisted(() => ({\n generateClientToken: vi.fn(async () => 'client-token'),\n // Resolves the stored location of an owning document, so it matches the requested key.\n buildStoragePathData: vi.fn(() => ({\n storageFilePath: 'reference.png',\n sanitizedCollectionPrefix: '',\n sanitizedDocPrefix: '',\n sanitizedFilename: 'reference.png',\n })),\n buildUploadStoragePathData: vi.fn(() => ({\n storageFilePath: 'reference.png',\n sanitizedCollectionPrefix: '',\n sanitizedDocPrefix: '',\n sanitizedFilename: 'reference.png',\n })),\n isStoragePathWithinCollectionPrefix: vi.fn(() => true),\n resolveSignedURLKey: vi.fn(async () => ({\n storageFilePath: 'reference-1.png',\n sanitizedDocPrefix: '',\n sanitizedFilename: 'reference-1.png',\n uploadReference: { prefix: '', signedReceipt: 'upload-receipt' },\n })),\n}))\n\nvi.mock('@payloadcms/plugin-cloud-storage/utilities', () => ({\n buildStoragePathData: mocks.buildStoragePathData,\n buildUploadStoragePathData: mocks.buildUploadStoragePathData,\n isStoragePathWithinCollectionPrefix: mocks.isStoragePathWithinCollectionPrefix,\n resolveSignedURLKey: mocks.resolveSignedURLKey,\n}))\n\nvi.mock('@vercel/blob/client', () => ({\n generateClientTokenFromReadWriteToken: mocks.generateClientToken,\n}))\n\nimport { createVercelBlobAdapter } from './adapter.js'\n\nconst generateInstructions = async ({ hasOwner }: { hasOwner: boolean }) => {\n const adapter = createVercelBlobAdapter({\n access: 'public',\n baseUrl: 'https://example.com',\n cacheControlMaxAge: 60,\n clientUploads: true,\n collectionSources: [\n { collectionPrefix: '', collectionSlug: 'media', useCompositePrefixes: false },\n ],\n token: 'read-write-token',\n })\n const generatedAdapter = adapter({\n collection: { slug: 'media' },\n prefix: '',\n } as never)\n const req = {\n payload: {\n collections: {\n media: { config: { access: { update: async () => true }, upload: true } },\n },\n find: vi.fn(async () => ({\n docs: hasOwner ? [{ filename: 'reference.png', id: 1 }] : [],\n })),\n secret: 'secret',\n },\n t: vi.fn(),\n } as unknown as PayloadRequest\n\n return generatedAdapter.uploadInstructions?.generate({\n collectionSlug: 'media',\n filename: 'reference.png',\n filesize: 100,\n mimeType: 'image/png',\n overrideAccess: true,\n req,\n })\n}\n\ndescribe('createVercelBlobAdapter', () => {\n beforeEach(() => {\n vi.clearAllMocks()\n })\n\n it('should disable overwrite when no document owns the requested key', async () => {\n const instructions = await generateInstructions({ hasOwner: false })\n const tokenOptions = mocks.generateClientToken.mock.calls[0]![0]\n\n expect(instructions).toMatchObject({ data: { pathname: 'reference-1.png' } })\n expect(tokenOptions).not.toHaveProperty('allowOverwrite')\n })\n\n it('should allow an authorized owner to update the requested key', async () => {\n const instructions = await generateInstructions({ hasOwner: true })\n\n expect(instructions).toMatchObject({ data: { pathname: 'reference.png' } })\n expect(mocks.generateClientToken).toHaveBeenCalledWith(\n expect.objectContaining({ allowOverwrite: true, pathname: 'reference.png' }),\n )\n })\n})\n"],"names":["beforeEach","describe","expect","it","vi","mocks","hoisted","generateClientToken","fn","buildStoragePathData","storageFilePath","sanitizedCollectionPrefix","sanitizedDocPrefix","sanitizedFilename","buildUploadStoragePathData","isStoragePathWithinCollectionPrefix","resolveSignedURLKey","uploadReference","prefix","signedReceipt","mock","generateClientTokenFromReadWriteToken","createVercelBlobAdapter","generateInstructions","hasOwner","adapter","access","baseUrl","cacheControlMaxAge","clientUploads","collectionSources","collectionPrefix","collectionSlug","useCompositePrefixes","token","generatedAdapter","collection","slug","req","payload","collections","media","config","update","upload","find","docs","filename","id","secret","t","uploadInstructions","generate","filesize","mimeType","overrideAccess","clearAllMocks","instructions","tokenOptions","calls","toMatchObject","data","pathname","not","toHaveProperty","toHaveBeenCalledWith","objectContaining","allowOverwrite"],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { PayloadRequest } from 'payload';
|
|
2
|
+
export type VercelBlobCollectionSource = {
|
|
3
|
+
collectionPrefix: string;
|
|
4
|
+
collectionSlug: string;
|
|
5
|
+
useCompositePrefixes: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare function authorizeClientOverwrite({ collectionPrefix: collectionPrefixArg, collectionSources, overrideAccess, req, requestedCollectionSlug, requestedFilename, requestedStorageFilePath, }: {
|
|
8
|
+
collectionPrefix: string;
|
|
9
|
+
collectionSources: VercelBlobCollectionSource[];
|
|
10
|
+
overrideAccess?: boolean;
|
|
11
|
+
req: PayloadRequest;
|
|
12
|
+
requestedCollectionSlug: string;
|
|
13
|
+
requestedFilename: string;
|
|
14
|
+
requestedStorageFilePath: string;
|
|
15
|
+
}): Promise<boolean>;
|
|
16
|
+
//# sourceMappingURL=authorizeFileOverwrite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorizeFileOverwrite.d.ts","sourceRoot":"","sources":["../src/authorizeFileOverwrite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAY,cAAc,EAAqB,MAAM,SAAS,CAAA;AAU1E,MAAM,MAAM,0BAA0B,GAAG;IACvC,gBAAgB,EAAE,MAAM,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;IACtB,oBAAoB,EAAE,OAAO,CAAA;CAC9B,CAAA;AAmHD,wBAAsB,wBAAwB,CAAC,EAC7C,gBAAgB,EAAE,mBAAmB,EACrC,iBAAiB,EACjB,cAAsB,EACtB,GAAG,EACH,uBAAuB,EACvB,iBAAiB,EACjB,wBAAwB,GACzB,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,iBAAiB,EAAE,0BAA0B,EAAE,CAAA;IAC/C,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,GAAG,EAAE,cAAc,CAAA;IACnB,uBAAuB,EAAE,MAAM,CAAA;IAC/B,iBAAiB,EAAE,MAAM,CAAA;IACzB,wBAAwB,EAAE,MAAM,CAAA;CACjC,GAAG,OAAO,CAAC,OAAO,CAAC,CA8CnB"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { buildStoragePathData, isStoragePathWithinCollectionPrefix } from '@payloadcms/plugin-cloud-storage/utilities';
|
|
2
|
+
import { combineQueries, executeAccess, Forbidden } from 'payload';
|
|
3
|
+
function getDocumentFileKeys({ collectionPrefix, doc, useCompositePrefixes }) {
|
|
4
|
+
return [
|
|
5
|
+
doc.filename,
|
|
6
|
+
...Object.values(doc.sizes || {}).map((size)=>size?.filename)
|
|
7
|
+
].filter((filename)=>typeof filename === 'string').map((filename)=>buildStoragePathData({
|
|
8
|
+
collectionPrefix,
|
|
9
|
+
docPrefix: doc.prefix,
|
|
10
|
+
filename,
|
|
11
|
+
useCompositePrefixes
|
|
12
|
+
}).storageFilePath);
|
|
13
|
+
}
|
|
14
|
+
async function findMatchingDocs({ collectionPrefix, collectionSlug, req, requestedFilename, requestedStorageFilePath, useCompositePrefixes }) {
|
|
15
|
+
const collection = req.payload.collections[collectionSlug];
|
|
16
|
+
if (!collection) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
const imageSizes = collection.config.upload && typeof collection.config.upload === 'object' ? collection.config.upload.imageSizes || [] : [];
|
|
20
|
+
const filenameQueries = [
|
|
21
|
+
{
|
|
22
|
+
filename: {
|
|
23
|
+
equals: requestedFilename
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
...imageSizes.map(({ name })=>({
|
|
27
|
+
[`sizes.${name}.filename`]: {
|
|
28
|
+
equals: requestedFilename
|
|
29
|
+
}
|
|
30
|
+
}))
|
|
31
|
+
];
|
|
32
|
+
const result = await req.payload.find({
|
|
33
|
+
collection: collectionSlug,
|
|
34
|
+
depth: 0,
|
|
35
|
+
draft: true,
|
|
36
|
+
overrideAccess: true,
|
|
37
|
+
pagination: false,
|
|
38
|
+
req,
|
|
39
|
+
where: {
|
|
40
|
+
or: filenameQueries
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
return result.docs.filter((doc)=>getDocumentFileKeys({
|
|
44
|
+
collectionPrefix,
|
|
45
|
+
doc,
|
|
46
|
+
useCompositePrefixes
|
|
47
|
+
}).includes(requestedStorageFilePath));
|
|
48
|
+
}
|
|
49
|
+
async function canUpdateDoc({ collectionSlug, doc, req }) {
|
|
50
|
+
const collection = req.payload.collections[collectionSlug];
|
|
51
|
+
if (!collection) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const accessResult = await executeAccess({
|
|
55
|
+
id: doc.id,
|
|
56
|
+
slug: collectionSlug,
|
|
57
|
+
disableErrors: true,
|
|
58
|
+
req
|
|
59
|
+
}, collection.config.access.update);
|
|
60
|
+
if (typeof accessResult === 'boolean') {
|
|
61
|
+
return accessResult;
|
|
62
|
+
}
|
|
63
|
+
const result = await req.payload.find({
|
|
64
|
+
collection: collectionSlug,
|
|
65
|
+
depth: 0,
|
|
66
|
+
draft: true,
|
|
67
|
+
limit: 1,
|
|
68
|
+
overrideAccess: true,
|
|
69
|
+
pagination: false,
|
|
70
|
+
req,
|
|
71
|
+
where: combineQueries({
|
|
72
|
+
id: {
|
|
73
|
+
equals: doc.id
|
|
74
|
+
}
|
|
75
|
+
}, accessResult)
|
|
76
|
+
});
|
|
77
|
+
return result.docs.length === 1;
|
|
78
|
+
}
|
|
79
|
+
export async function authorizeClientOverwrite({ collectionPrefix: collectionPrefixArg, collectionSources, overrideAccess = false, req, requestedCollectionSlug, requestedFilename, requestedStorageFilePath }) {
|
|
80
|
+
if (!isStoragePathWithinCollectionPrefix({
|
|
81
|
+
collectionPrefix: collectionPrefixArg,
|
|
82
|
+
docPrefix: requestedStorageFilePath
|
|
83
|
+
})) {
|
|
84
|
+
throw new Forbidden(req.t);
|
|
85
|
+
}
|
|
86
|
+
const matchedDocs = (await Promise.all(collectionSources.map(async ({ collectionPrefix, collectionSlug, useCompositePrefixes })=>{
|
|
87
|
+
const docs = await findMatchingDocs({
|
|
88
|
+
collectionPrefix,
|
|
89
|
+
collectionSlug,
|
|
90
|
+
req,
|
|
91
|
+
requestedFilename,
|
|
92
|
+
requestedStorageFilePath,
|
|
93
|
+
useCompositePrefixes
|
|
94
|
+
});
|
|
95
|
+
return docs.map((doc)=>({
|
|
96
|
+
collectionSlug,
|
|
97
|
+
doc
|
|
98
|
+
}));
|
|
99
|
+
}))).flat();
|
|
100
|
+
if (matchedDocs.length === 0) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
const matchedDoc = matchedDocs[0];
|
|
104
|
+
if (matchedDocs.length !== 1 || matchedDoc.collectionSlug !== requestedCollectionSlug) {
|
|
105
|
+
throw new Forbidden(req.t);
|
|
106
|
+
}
|
|
107
|
+
if (!overrideAccess && !await canUpdateDoc({
|
|
108
|
+
collectionSlug: matchedDoc.collectionSlug,
|
|
109
|
+
doc: matchedDoc.doc,
|
|
110
|
+
req
|
|
111
|
+
})) {
|
|
112
|
+
throw new Forbidden(req.t);
|
|
113
|
+
}
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
//# sourceMappingURL=authorizeFileOverwrite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/authorizeFileOverwrite.ts"],"sourcesContent":["import type { FileData, PayloadRequest, TypeWithID, Where } from 'payload'\n\nimport {\n buildStoragePathData,\n isStoragePathWithinCollectionPrefix,\n} from '@payloadcms/plugin-cloud-storage/utilities'\nimport { combineQueries, executeAccess, Forbidden } from 'payload'\n\ntype OwnerDocument = { prefix?: string } & FileData & TypeWithID\n\nexport type VercelBlobCollectionSource = {\n collectionPrefix: string\n collectionSlug: string\n useCompositePrefixes: boolean\n}\n\ntype Owner = {\n collectionSlug: string\n doc: OwnerDocument\n}\n\nfunction getDocumentFileKeys({\n collectionPrefix,\n doc,\n useCompositePrefixes,\n}: {\n collectionPrefix: string\n doc: OwnerDocument\n useCompositePrefixes: boolean\n}): string[] {\n return [doc.filename, ...Object.values(doc.sizes || {}).map((size) => size?.filename)]\n .filter((filename): filename is string => typeof filename === 'string')\n .map(\n (filename) =>\n buildStoragePathData({\n collectionPrefix,\n docPrefix: doc.prefix,\n filename,\n useCompositePrefixes,\n }).storageFilePath,\n )\n}\n\nasync function findMatchingDocs({\n collectionPrefix,\n collectionSlug,\n req,\n requestedFilename,\n requestedStorageFilePath,\n useCompositePrefixes,\n}: {\n collectionPrefix: string\n collectionSlug: string\n req: PayloadRequest\n requestedFilename: string\n requestedStorageFilePath: string\n useCompositePrefixes: boolean\n}): Promise<OwnerDocument[]> {\n const collection = req.payload.collections[collectionSlug]\n\n if (!collection) {\n return []\n }\n\n const imageSizes =\n collection.config.upload && typeof collection.config.upload === 'object'\n ? collection.config.upload.imageSizes || []\n : []\n const filenameQueries: Where[] = [\n { filename: { equals: requestedFilename } },\n ...imageSizes.map(({ name }) => ({\n [`sizes.${name}.filename`]: { equals: requestedFilename },\n })),\n ]\n const result = await req.payload.find({\n collection: collectionSlug,\n depth: 0,\n draft: true,\n overrideAccess: true,\n pagination: false,\n req,\n where: { or: filenameQueries },\n })\n\n return (result.docs as OwnerDocument[]).filter((doc) =>\n getDocumentFileKeys({ collectionPrefix, doc, useCompositePrefixes }).includes(\n requestedStorageFilePath,\n ),\n )\n}\n\nasync function canUpdateDoc({\n collectionSlug,\n doc,\n req,\n}: {\n collectionSlug: string\n doc: OwnerDocument\n req: PayloadRequest\n}): Promise<boolean> {\n const collection = req.payload.collections[collectionSlug]\n\n if (!collection) {\n return false\n }\n\n const accessResult = await executeAccess(\n { id: doc.id, slug: collectionSlug, disableErrors: true, req },\n collection.config.access.update,\n )\n\n if (typeof accessResult === 'boolean') {\n return accessResult\n }\n\n const result = await req.payload.find({\n collection: collectionSlug,\n depth: 0,\n draft: true,\n limit: 1,\n overrideAccess: true,\n pagination: false,\n req,\n where: combineQueries({ id: { equals: doc.id } }, accessResult),\n })\n\n return result.docs.length === 1\n}\n\nexport async function authorizeClientOverwrite({\n collectionPrefix: collectionPrefixArg,\n collectionSources,\n overrideAccess = false,\n req,\n requestedCollectionSlug,\n requestedFilename,\n requestedStorageFilePath,\n}: {\n collectionPrefix: string\n collectionSources: VercelBlobCollectionSource[]\n overrideAccess?: boolean\n req: PayloadRequest\n requestedCollectionSlug: string\n requestedFilename: string\n requestedStorageFilePath: string\n}): Promise<boolean> {\n if (\n !isStoragePathWithinCollectionPrefix({\n collectionPrefix: collectionPrefixArg,\n docPrefix: requestedStorageFilePath,\n })\n ) {\n throw new Forbidden(req.t)\n }\n\n const matchedDocs = (\n await Promise.all(\n collectionSources.map(\n async ({ collectionPrefix, collectionSlug, useCompositePrefixes }): Promise<Owner[]> => {\n const docs = await findMatchingDocs({\n collectionPrefix,\n collectionSlug,\n req,\n requestedFilename,\n requestedStorageFilePath,\n useCompositePrefixes,\n })\n\n return docs.map((doc) => ({ collectionSlug, doc }))\n },\n ),\n )\n ).flat()\n\n if (matchedDocs.length === 0) {\n return false\n }\n\n const matchedDoc = matchedDocs[0]!\n if (matchedDocs.length !== 1 || matchedDoc.collectionSlug !== requestedCollectionSlug) {\n throw new Forbidden(req.t)\n }\n\n if (\n !overrideAccess &&\n !(await canUpdateDoc({ collectionSlug: matchedDoc.collectionSlug, doc: matchedDoc.doc, req }))\n ) {\n throw new Forbidden(req.t)\n }\n\n return true\n}\n"],"names":["buildStoragePathData","isStoragePathWithinCollectionPrefix","combineQueries","executeAccess","Forbidden","getDocumentFileKeys","collectionPrefix","doc","useCompositePrefixes","filename","Object","values","sizes","map","size","filter","docPrefix","prefix","storageFilePath","findMatchingDocs","collectionSlug","req","requestedFilename","requestedStorageFilePath","collection","payload","collections","imageSizes","config","upload","filenameQueries","equals","name","result","find","depth","draft","overrideAccess","pagination","where","or","docs","includes","canUpdateDoc","accessResult","id","slug","disableErrors","access","update","limit","length","authorizeClientOverwrite","collectionPrefixArg","collectionSources","requestedCollectionSlug","t","matchedDocs","Promise","all","flat","matchedDoc"],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { authorizeClientOverwrite } from './authorizeFileOverwrite.js';
|
|
3
|
+
const owner = (id)=>({
|
|
4
|
+
filename: 'image.png',
|
|
5
|
+
id,
|
|
6
|
+
prefix: 'shared'
|
|
7
|
+
});
|
|
8
|
+
const collectionSources = [
|
|
9
|
+
{
|
|
10
|
+
collectionPrefix: '',
|
|
11
|
+
collectionSlug: 'media',
|
|
12
|
+
useCompositePrefixes: false
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
collectionPrefix: '',
|
|
16
|
+
collectionSlug: 'protected',
|
|
17
|
+
useCompositePrefixes: false
|
|
18
|
+
}
|
|
19
|
+
];
|
|
20
|
+
const createRequest = ({ mediaOwner = true, protectedOwner = false } = {})=>({
|
|
21
|
+
payload: {
|
|
22
|
+
collections: {
|
|
23
|
+
media: {
|
|
24
|
+
config: {
|
|
25
|
+
access: {
|
|
26
|
+
update: async ()=>true
|
|
27
|
+
},
|
|
28
|
+
upload: true
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
protected: {
|
|
32
|
+
config: {
|
|
33
|
+
access: {
|
|
34
|
+
update: async ()=>false
|
|
35
|
+
},
|
|
36
|
+
upload: true
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
find: vi.fn(async ({ collection })=>({
|
|
41
|
+
docs: collection === 'media' ? mediaOwner ? [
|
|
42
|
+
owner(1)
|
|
43
|
+
] : [] : protectedOwner ? [
|
|
44
|
+
owner(2)
|
|
45
|
+
] : []
|
|
46
|
+
}))
|
|
47
|
+
},
|
|
48
|
+
t: vi.fn()
|
|
49
|
+
});
|
|
50
|
+
describe('authorizeClientOverwrite', ()=>{
|
|
51
|
+
it('allows an update when the requested collection is the only owner', async ()=>{
|
|
52
|
+
await expect(authorizeClientOverwrite({
|
|
53
|
+
collectionSources,
|
|
54
|
+
requestedStorageFilePath: 'shared/image.png',
|
|
55
|
+
requestedFilename: 'image.png',
|
|
56
|
+
req: createRequest(),
|
|
57
|
+
requestedCollectionSlug: 'media',
|
|
58
|
+
collectionPrefix: ''
|
|
59
|
+
})).resolves.toBe(true);
|
|
60
|
+
});
|
|
61
|
+
it('rejects an update when another collection owns the same key', async ()=>{
|
|
62
|
+
await expect(authorizeClientOverwrite({
|
|
63
|
+
collectionSources,
|
|
64
|
+
requestedStorageFilePath: 'shared/image.png',
|
|
65
|
+
requestedFilename: 'image.png',
|
|
66
|
+
req: createRequest({
|
|
67
|
+
mediaOwner: false,
|
|
68
|
+
protectedOwner: true
|
|
69
|
+
}),
|
|
70
|
+
requestedCollectionSlug: 'media',
|
|
71
|
+
collectionPrefix: ''
|
|
72
|
+
})).rejects.toMatchObject({
|
|
73
|
+
status: 403
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
it('rejects an update when multiple collections own the same key', async ()=>{
|
|
77
|
+
await expect(authorizeClientOverwrite({
|
|
78
|
+
collectionSources,
|
|
79
|
+
requestedStorageFilePath: 'shared/image.png',
|
|
80
|
+
requestedFilename: 'image.png',
|
|
81
|
+
req: createRequest({
|
|
82
|
+
protectedOwner: true
|
|
83
|
+
}),
|
|
84
|
+
requestedCollectionSlug: 'media',
|
|
85
|
+
collectionPrefix: ''
|
|
86
|
+
})).rejects.toMatchObject({
|
|
87
|
+
status: 403
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
//# sourceMappingURL=authorizeFileOverwrite.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/authorizeFileOverwrite.spec.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { describe, expect, it, vi } from 'vitest'\n\nimport { authorizeClientOverwrite } from './authorizeFileOverwrite.js'\n\nconst owner = (id: number) => ({ filename: 'image.png', id, prefix: 'shared' })\nconst collectionSources = [\n { collectionPrefix: '', collectionSlug: 'media', useCompositePrefixes: false },\n { collectionPrefix: '', collectionSlug: 'protected', useCompositePrefixes: false },\n]\n\nconst createRequest = ({\n mediaOwner = true,\n protectedOwner = false,\n}: {\n mediaOwner?: boolean\n protectedOwner?: boolean\n} = {}) =>\n ({\n payload: {\n collections: {\n media: {\n config: { access: { update: async () => true }, upload: true },\n },\n protected: {\n config: { access: { update: async () => false }, upload: true },\n },\n },\n find: vi.fn(async ({ collection }: { collection: string }) => ({\n docs:\n collection === 'media'\n ? mediaOwner\n ? [owner(1)]\n : []\n : protectedOwner\n ? [owner(2)]\n : [],\n })),\n },\n t: vi.fn(),\n }) as unknown as PayloadRequest\n\ndescribe('authorizeClientOverwrite', () => {\n it('allows an update when the requested collection is the only owner', async () => {\n await expect(\n authorizeClientOverwrite({\n collectionSources,\n requestedStorageFilePath: 'shared/image.png',\n requestedFilename: 'image.png',\n req: createRequest(),\n requestedCollectionSlug: 'media',\n collectionPrefix: '',\n }),\n ).resolves.toBe(true)\n })\n\n it('rejects an update when another collection owns the same key', async () => {\n await expect(\n authorizeClientOverwrite({\n collectionSources,\n requestedStorageFilePath: 'shared/image.png',\n requestedFilename: 'image.png',\n req: createRequest({ mediaOwner: false, protectedOwner: true }),\n requestedCollectionSlug: 'media',\n collectionPrefix: '',\n }),\n ).rejects.toMatchObject({ status: 403 })\n })\n\n it('rejects an update when multiple collections own the same key', async () => {\n await expect(\n authorizeClientOverwrite({\n collectionSources,\n requestedStorageFilePath: 'shared/image.png',\n requestedFilename: 'image.png',\n req: createRequest({ protectedOwner: true }),\n requestedCollectionSlug: 'media',\n collectionPrefix: '',\n }),\n ).rejects.toMatchObject({ status: 403 })\n })\n})\n"],"names":["describe","expect","it","vi","authorizeClientOverwrite","owner","id","filename","prefix","collectionSources","collectionPrefix","collectionSlug","useCompositePrefixes","createRequest","mediaOwner","protectedOwner","payload","collections","media","config","access","update","upload","protected","find","fn","collection","docs","t","requestedStorageFilePath","requestedFilename","req","requestedCollectionSlug","resolves","toBe","rejects","toMatchObject","status"],"mappings":"AAEA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,EAAEC,EAAE,QAAQ,SAAQ;AAEjD,SAASC,wBAAwB,QAAQ,8BAA6B;AAEtE,MAAMC,QAAQ,CAACC,KAAgB,CAAA;QAAEC,UAAU;QAAaD;QAAIE,QAAQ;IAAS,CAAA;AAC7E,MAAMC,oBAAoB;IACxB;QAAEC,kBAAkB;QAAIC,gBAAgB;QAASC,sBAAsB;IAAM;IAC7E;QAAEF,kBAAkB;QAAIC,gBAAgB;QAAaC,sBAAsB;IAAM;CAClF;AAED,MAAMC,gBAAgB,CAAC,EACrBC,aAAa,IAAI,EACjBC,iBAAiB,KAAK,EAIvB,GAAG,CAAC,CAAC,GACH,CAAA;QACCC,SAAS;YACPC,aAAa;gBACXC,OAAO;oBACLC,QAAQ;wBAAEC,QAAQ;4BAAEC,QAAQ,UAAY;wBAAK;wBAAGC,QAAQ;oBAAK;gBAC/D;gBACAC,WAAW;oBACTJ,QAAQ;wBAAEC,QAAQ;4BAAEC,QAAQ,UAAY;wBAAM;wBAAGC,QAAQ;oBAAK;gBAChE;YACF;YACAE,MAAMrB,GAAGsB,EAAE,CAAC,OAAO,EAAEC,UAAU,EAA0B,GAAM,CAAA;oBAC7DC,MACED,eAAe,UACXZ,aACE;wBAACT,MAAM;qBAAG,GACV,EAAE,GACJU,iBACE;wBAACV,MAAM;qBAAG,GACV,EAAE;gBACZ,CAAA;QACF;QACAuB,GAAGzB,GAAGsB,EAAE;IACV,CAAA;AAEFzB,SAAS,4BAA4B;IACnCE,GAAG,oEAAoE;QACrE,MAAMD,OACJG,yBAAyB;YACvBK;YACAoB,0BAA0B;YAC1BC,mBAAmB;YACnBC,KAAKlB;YACLmB,yBAAyB;YACzBtB,kBAAkB;QACpB,IACAuB,QAAQ,CAACC,IAAI,CAAC;IAClB;IAEAhC,GAAG,+DAA+D;QAChE,MAAMD,OACJG,yBAAyB;YACvBK;YACAoB,0BAA0B;YAC1BC,mBAAmB;YACnBC,KAAKlB,cAAc;gBAAEC,YAAY;gBAAOC,gBAAgB;YAAK;YAC7DiB,yBAAyB;YACzBtB,kBAAkB;QACpB,IACAyB,OAAO,CAACC,aAAa,CAAC;YAAEC,QAAQ;QAAI;IACxC;IAEAnC,GAAG,gEAAgE;QACjE,MAAMD,OACJG,yBAAyB;YACvBK;YACAoB,0BAA0B;YAC1BC,mBAAmB;YACnBC,KAAKlB,cAAc;gBAAEE,gBAAgB;YAAK;YAC1CiB,yBAAyB;YACzBtB,kBAAkB;QACpB,IACAyB,OAAO,CAACC,aAAa,CAAC;YAAEC,QAAQ;QAAI;IACxC;AACF"}
|
package/dist/deleteFile.d.ts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
interface DeleteFileArgs {
|
|
2
2
|
baseUrl: string;
|
|
3
|
-
|
|
4
|
-
docPrefix: string;
|
|
5
|
-
filename: string;
|
|
3
|
+
storageFilePath: string;
|
|
6
4
|
token: string;
|
|
7
|
-
useCompositePrefixes?: boolean;
|
|
8
5
|
}
|
|
9
|
-
export declare function deleteFile({ baseUrl,
|
|
6
|
+
export declare function deleteFile({ baseUrl, storageFilePath, token, }: DeleteFileArgs): Promise<void>;
|
|
10
7
|
export {};
|
|
11
8
|
//# sourceMappingURL=deleteFile.d.ts.map
|
package/dist/deleteFile.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deleteFile.d.ts","sourceRoot":"","sources":["../src/deleteFile.ts"],"names":[],"mappings":"AAIA,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,
|
|
1
|
+
{"version":3,"file":"deleteFile.d.ts","sourceRoot":"","sources":["../src/deleteFile.ts"],"names":[],"mappings":"AAIA,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,EAAE,MAAM,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,wBAAsB,UAAU,CAAC,EAC/B,OAAO,EACP,eAAe,EACf,KAAK,GACN,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhC"}
|