@payloadcms/plugin-cloud-storage 4.0.0-canary.34 → 4.0.0-canary.36

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.
@@ -1,241 +0,0 @@
1
- import { buildStoragePathData, buildUploadStoragePathData, isStoragePathWithinCollectionPrefix } from './buildStoragePathData.js';
2
- import { describe, expect, it } from 'vitest';
3
- describe('buildFileKey', ()=>{
4
- describe('non-composite mode (useCompositePrefixes: false)', ()=>{
5
- it('should preserve the key of a legacy document outside the collection prefix', ()=>{
6
- const result = buildStoragePathData({
7
- collectionPrefix: 'media/',
8
- docPrefix: 'media-archive',
9
- filename: 'test.png',
10
- useCompositePrefixes: false
11
- });
12
- expect(result).toEqual({
13
- sanitizedCollectionPrefix: 'media',
14
- sanitizedDocPrefix: 'media-archive',
15
- sanitizedFilename: 'test.png',
16
- storageFilePath: 'media-archive/test.png'
17
- });
18
- });
19
- it('should fallback to collectionPrefix when docPrefix is empty', ()=>{
20
- const result = buildStoragePathData({
21
- collectionPrefix: 'collection',
22
- docPrefix: '',
23
- filename: 'test.png',
24
- useCompositePrefixes: false
25
- });
26
- expect(result).toEqual({
27
- sanitizedCollectionPrefix: 'collection',
28
- sanitizedDocPrefix: '',
29
- sanitizedFilename: 'test.png',
30
- storageFilePath: 'collection/test.png'
31
- });
32
- });
33
- it('should fallback to collectionPrefix when docPrefix is undefined', ()=>{
34
- const result = buildStoragePathData({
35
- collectionPrefix: 'collection',
36
- filename: 'test.png',
37
- useCompositePrefixes: false
38
- });
39
- expect(result).toEqual({
40
- sanitizedCollectionPrefix: 'collection',
41
- sanitizedDocPrefix: '',
42
- sanitizedFilename: 'test.png',
43
- storageFilePath: 'collection/test.png'
44
- });
45
- });
46
- it('should return only filename when both prefixes are empty', ()=>{
47
- const result = buildStoragePathData({
48
- filename: 'test.png',
49
- useCompositePrefixes: false
50
- });
51
- expect(result).toEqual({
52
- sanitizedCollectionPrefix: '',
53
- sanitizedDocPrefix: '',
54
- sanitizedFilename: 'test.png',
55
- storageFilePath: 'test.png'
56
- });
57
- });
58
- });
59
- describe('composite mode (useCompositePrefixes: true)', ()=>{
60
- it('should combine collectionPrefix and docPrefix', ()=>{
61
- const result = buildStoragePathData({
62
- collectionPrefix: 'collection',
63
- docPrefix: 'document',
64
- filename: 'test.png',
65
- useCompositePrefixes: true
66
- });
67
- expect(result).toEqual({
68
- sanitizedCollectionPrefix: 'collection',
69
- sanitizedDocPrefix: 'document',
70
- sanitizedFilename: 'test.png',
71
- storageFilePath: 'collection/document/test.png'
72
- });
73
- });
74
- it('should work with only collectionPrefix', ()=>{
75
- const result = buildStoragePathData({
76
- collectionPrefix: 'collection',
77
- filename: 'test.png',
78
- useCompositePrefixes: true
79
- });
80
- expect(result).toEqual({
81
- sanitizedCollectionPrefix: 'collection',
82
- sanitizedDocPrefix: '',
83
- sanitizedFilename: 'test.png',
84
- storageFilePath: 'collection/test.png'
85
- });
86
- });
87
- it('should work with only docPrefix', ()=>{
88
- const result = buildStoragePathData({
89
- docPrefix: 'document',
90
- filename: 'test.png',
91
- useCompositePrefixes: true
92
- });
93
- expect(result).toEqual({
94
- sanitizedCollectionPrefix: '',
95
- sanitizedDocPrefix: 'document',
96
- sanitizedFilename: 'test.png',
97
- storageFilePath: 'document/test.png'
98
- });
99
- });
100
- it('should return only filename when both prefixes are empty', ()=>{
101
- const result = buildStoragePathData({
102
- filename: 'test.png',
103
- useCompositePrefixes: true
104
- });
105
- expect(result).toEqual({
106
- sanitizedCollectionPrefix: '',
107
- sanitizedDocPrefix: '',
108
- sanitizedFilename: 'test.png',
109
- storageFilePath: 'test.png'
110
- });
111
- });
112
- });
113
- describe('collection prefix boundaries', ()=>{
114
- it('should accept a file key within a slash-terminated collection prefix', ()=>{
115
- expect(isStoragePathWithinCollectionPrefix({
116
- collectionPrefix: 'media/',
117
- docPrefix: 'media/documents/test.png'
118
- })).toBe(true);
119
- });
120
- });
121
- describe('sanitization', ()=>{
122
- it.each([
123
- './media/./images',
124
- 'media\\images',
125
- '/media//images'
126
- ])('should canonicalize equivalent prefix paths', (docPrefix)=>{
127
- const result = buildStoragePathData({
128
- docPrefix,
129
- filename: 'test.png'
130
- });
131
- expect(result).toEqual({
132
- sanitizedCollectionPrefix: '',
133
- sanitizedDocPrefix: 'media/images',
134
- sanitizedFilename: 'test.png',
135
- storageFilePath: 'media/images/test.png'
136
- });
137
- });
138
- it('should remove path traversal segments from collectionPrefix', ()=>{
139
- const result = buildStoragePathData({
140
- collectionPrefix: '../../../etc',
141
- filename: 'test.png',
142
- useCompositePrefixes: false
143
- });
144
- expect(result).toEqual({
145
- sanitizedCollectionPrefix: 'etc',
146
- sanitizedDocPrefix: '',
147
- sanitizedFilename: 'test.png',
148
- storageFilePath: 'etc/test.png'
149
- });
150
- expect(result.storageFilePath).not.toContain('..');
151
- });
152
- it('should remove path traversal segments from docPrefix', ()=>{
153
- const result = buildStoragePathData({
154
- docPrefix: 'a/../../outside',
155
- filename: 'test.png',
156
- useCompositePrefixes: false
157
- });
158
- expect(result).toEqual({
159
- sanitizedCollectionPrefix: '',
160
- sanitizedDocPrefix: 'a/outside',
161
- sanitizedFilename: 'test.png',
162
- storageFilePath: 'a/outside/test.png'
163
- });
164
- expect(result.storageFilePath).not.toContain('..');
165
- });
166
- it('should remove control characters from prefixes', ()=>{
167
- const result = buildStoragePathData({
168
- collectionPrefix: 'test\x00\x1fprefix',
169
- filename: 'test.png',
170
- useCompositePrefixes: false
171
- });
172
- expect(result).toEqual({
173
- sanitizedCollectionPrefix: 'testprefix',
174
- sanitizedDocPrefix: '',
175
- sanitizedFilename: 'test.png',
176
- storageFilePath: 'testprefix/test.png'
177
- });
178
- expect(result.storageFilePath).not.toMatch(/[\x00-\x1f]/);
179
- });
180
- it('should normalize both prefixes after removing control characters in composite mode', ()=>{
181
- const result = buildStoragePathData({
182
- collectionPrefix: '.\x00./collection',
183
- docPrefix: '.\x00./doc',
184
- filename: 'test.png',
185
- useCompositePrefixes: true
186
- });
187
- expect(result).toEqual({
188
- sanitizedCollectionPrefix: 'collection',
189
- sanitizedDocPrefix: 'doc',
190
- sanitizedFilename: 'test.png',
191
- storageFilePath: 'collection/doc/test.png'
192
- });
193
- expect(result.storageFilePath).not.toContain('..');
194
- });
195
- });
196
- });
197
- describe('buildUploadStoragePathData', ()=>{
198
- it.each([
199
- [
200
- 'invoices',
201
- false,
202
- 'media/invoices/file.png',
203
- 'media/invoices'
204
- ],
205
- [
206
- 'media/invoices',
207
- false,
208
- 'media/invoices/file.png',
209
- 'media/invoices'
210
- ],
211
- [
212
- '',
213
- false,
214
- 'media/file.png',
215
- ''
216
- ],
217
- [
218
- 'invoices',
219
- true,
220
- 'media/invoices/file.png',
221
- 'invoices'
222
- ]
223
- ])('should persist a readable destination for %s (composite %s)', (docPrefix, useCompositePrefixes, fileKey, storedPrefix)=>{
224
- const result = buildUploadStoragePathData({
225
- collectionPrefix: 'media',
226
- docPrefix,
227
- filename: 'file.png',
228
- useCompositePrefixes
229
- });
230
- expect(result.storageFilePath).toBe(fileKey);
231
- expect(result.sanitizedDocPrefix).toBe(storedPrefix);
232
- expect(buildStoragePathData({
233
- collectionPrefix: 'media',
234
- docPrefix: result.sanitizedDocPrefix,
235
- filename: 'file.png',
236
- useCompositePrefixes
237
- }).storageFilePath).toBe(fileKey);
238
- });
239
- });
240
-
241
- //# sourceMappingURL=buildStoragePathData.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/utilities/buildStoragePathData.spec.ts"],"sourcesContent":["import {\n buildStoragePathData,\n buildUploadStoragePathData,\n isStoragePathWithinCollectionPrefix,\n} from './buildStoragePathData.js'\nimport { describe, expect, it } from 'vitest'\n\ndescribe('buildFileKey', () => {\n describe('non-composite mode (useCompositePrefixes: false)', () => {\n it('should preserve the key of a legacy document outside the collection prefix', () => {\n const result = buildStoragePathData({\n collectionPrefix: 'media/',\n docPrefix: 'media-archive',\n filename: 'test.png',\n useCompositePrefixes: false,\n })\n\n expect(result).toEqual({\n sanitizedCollectionPrefix: 'media',\n sanitizedDocPrefix: 'media-archive',\n sanitizedFilename: 'test.png',\n storageFilePath: 'media-archive/test.png',\n })\n })\n\n it('should fallback to collectionPrefix when docPrefix is empty', () => {\n const result = buildStoragePathData({\n collectionPrefix: 'collection',\n docPrefix: '',\n filename: 'test.png',\n useCompositePrefixes: false,\n })\n expect(result).toEqual({\n sanitizedCollectionPrefix: 'collection',\n sanitizedDocPrefix: '',\n sanitizedFilename: 'test.png',\n storageFilePath: 'collection/test.png',\n })\n })\n\n it('should fallback to collectionPrefix when docPrefix is undefined', () => {\n const result = buildStoragePathData({\n collectionPrefix: 'collection',\n filename: 'test.png',\n useCompositePrefixes: false,\n })\n expect(result).toEqual({\n sanitizedCollectionPrefix: 'collection',\n sanitizedDocPrefix: '',\n sanitizedFilename: 'test.png',\n storageFilePath: 'collection/test.png',\n })\n })\n\n it('should return only filename when both prefixes are empty', () => {\n const result = buildStoragePathData({\n filename: 'test.png',\n useCompositePrefixes: false,\n })\n expect(result).toEqual({\n sanitizedCollectionPrefix: '',\n sanitizedDocPrefix: '',\n sanitizedFilename: 'test.png',\n storageFilePath: 'test.png',\n })\n })\n })\n\n describe('composite mode (useCompositePrefixes: true)', () => {\n it('should combine collectionPrefix and docPrefix', () => {\n const result = buildStoragePathData({\n collectionPrefix: 'collection',\n docPrefix: 'document',\n filename: 'test.png',\n useCompositePrefixes: true,\n })\n expect(result).toEqual({\n sanitizedCollectionPrefix: 'collection',\n sanitizedDocPrefix: 'document',\n sanitizedFilename: 'test.png',\n storageFilePath: 'collection/document/test.png',\n })\n })\n\n it('should work with only collectionPrefix', () => {\n const result = buildStoragePathData({\n collectionPrefix: 'collection',\n filename: 'test.png',\n useCompositePrefixes: true,\n })\n expect(result).toEqual({\n sanitizedCollectionPrefix: 'collection',\n sanitizedDocPrefix: '',\n sanitizedFilename: 'test.png',\n storageFilePath: 'collection/test.png',\n })\n })\n\n it('should work with only docPrefix', () => {\n const result = buildStoragePathData({\n docPrefix: 'document',\n filename: 'test.png',\n useCompositePrefixes: true,\n })\n expect(result).toEqual({\n sanitizedCollectionPrefix: '',\n sanitizedDocPrefix: 'document',\n sanitizedFilename: 'test.png',\n storageFilePath: 'document/test.png',\n })\n })\n\n it('should return only filename when both prefixes are empty', () => {\n const result = buildStoragePathData({\n filename: 'test.png',\n useCompositePrefixes: true,\n })\n expect(result).toEqual({\n sanitizedCollectionPrefix: '',\n sanitizedDocPrefix: '',\n sanitizedFilename: 'test.png',\n storageFilePath: 'test.png',\n })\n })\n })\n\n describe('collection prefix boundaries', () => {\n it('should accept a file key within a slash-terminated collection prefix', () => {\n expect(\n isStoragePathWithinCollectionPrefix({\n collectionPrefix: 'media/',\n docPrefix: 'media/documents/test.png',\n }),\n ).toBe(true)\n })\n })\n\n describe('sanitization', () => {\n it.each(['./media/./images', 'media\\\\images', '/media//images'])(\n 'should canonicalize equivalent prefix paths',\n (docPrefix) => {\n const result = buildStoragePathData({ docPrefix, filename: 'test.png' })\n\n expect(result).toEqual({\n sanitizedCollectionPrefix: '',\n sanitizedDocPrefix: 'media/images',\n sanitizedFilename: 'test.png',\n storageFilePath: 'media/images/test.png',\n })\n },\n )\n\n it('should remove path traversal segments from collectionPrefix', () => {\n const result = buildStoragePathData({\n collectionPrefix: '../../../etc',\n filename: 'test.png',\n useCompositePrefixes: false,\n })\n expect(result).toEqual({\n sanitizedCollectionPrefix: 'etc',\n sanitizedDocPrefix: '',\n sanitizedFilename: 'test.png',\n storageFilePath: 'etc/test.png',\n })\n expect(result.storageFilePath).not.toContain('..')\n })\n\n it('should remove path traversal segments from docPrefix', () => {\n const result = buildStoragePathData({\n docPrefix: 'a/../../outside',\n filename: 'test.png',\n useCompositePrefixes: false,\n })\n expect(result).toEqual({\n sanitizedCollectionPrefix: '',\n sanitizedDocPrefix: 'a/outside',\n sanitizedFilename: 'test.png',\n storageFilePath: 'a/outside/test.png',\n })\n expect(result.storageFilePath).not.toContain('..')\n })\n\n it('should remove control characters from prefixes', () => {\n const result = buildStoragePathData({\n collectionPrefix: 'test\\x00\\x1fprefix',\n filename: 'test.png',\n useCompositePrefixes: false,\n })\n expect(result).toEqual({\n sanitizedCollectionPrefix: 'testprefix',\n sanitizedDocPrefix: '',\n sanitizedFilename: 'test.png',\n storageFilePath: 'testprefix/test.png',\n })\n expect(result.storageFilePath).not.toMatch(/[\\x00-\\x1f]/)\n })\n\n it('should normalize both prefixes after removing control characters in composite mode', () => {\n const result = buildStoragePathData({\n collectionPrefix: '.\\x00./collection',\n docPrefix: '.\\x00./doc',\n filename: 'test.png',\n useCompositePrefixes: true,\n })\n expect(result).toEqual({\n sanitizedCollectionPrefix: 'collection',\n sanitizedDocPrefix: 'doc',\n sanitizedFilename: 'test.png',\n storageFilePath: 'collection/doc/test.png',\n })\n expect(result.storageFilePath).not.toContain('..')\n })\n })\n})\n\ndescribe('buildUploadStoragePathData', () => {\n it.each([\n ['invoices', false, 'media/invoices/file.png', 'media/invoices'],\n ['media/invoices', false, 'media/invoices/file.png', 'media/invoices'],\n ['', false, 'media/file.png', ''],\n ['invoices', true, 'media/invoices/file.png', 'invoices'],\n ] as const)(\n 'should persist a readable destination for %s (composite %s)',\n (docPrefix, useCompositePrefixes, fileKey, storedPrefix) => {\n const result = buildUploadStoragePathData({\n collectionPrefix: 'media',\n docPrefix,\n filename: 'file.png',\n useCompositePrefixes,\n })\n\n expect(result.storageFilePath).toBe(fileKey)\n expect(result.sanitizedDocPrefix).toBe(storedPrefix)\n expect(\n buildStoragePathData({\n collectionPrefix: 'media',\n docPrefix: result.sanitizedDocPrefix,\n filename: 'file.png',\n useCompositePrefixes,\n }).storageFilePath,\n ).toBe(fileKey)\n },\n )\n})\n"],"names":["buildStoragePathData","buildUploadStoragePathData","isStoragePathWithinCollectionPrefix","describe","expect","it","result","collectionPrefix","docPrefix","filename","useCompositePrefixes","toEqual","sanitizedCollectionPrefix","sanitizedDocPrefix","sanitizedFilename","storageFilePath","toBe","each","not","toContain","toMatch","fileKey","storedPrefix"],"mappings":"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"}
@@ -1,248 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import { getFilePrefix } from './getFilePrefix.js';
3
- const makeReq = (docs = [])=>({
4
- payload: {
5
- find: vi.fn().mockResolvedValue({
6
- docs
7
- })
8
- }
9
- });
10
- const makeCollection = ({ hasPrefixField = false } = {})=>({
11
- slug: 'media',
12
- fields: hasPrefixField ? [
13
- {
14
- name: 'prefix',
15
- type: 'text'
16
- }
17
- ] : [],
18
- upload: {}
19
- });
20
- const whereOf = (req)=>JSON.stringify(req.payload.find.mock.calls[0][0].where);
21
- describe('getFilePrefix', ()=>{
22
- it('prefers an already-authorized document over an upload reference or query prefix', async ()=>{
23
- const req = makeReq([
24
- {
25
- prefix: 'db-prefix'
26
- }
27
- ]);
28
- const doc = {
29
- id: '1',
30
- prefix: 'invoices'
31
- };
32
- const result = await getFilePrefix({
33
- collection: makeCollection(),
34
- collectionPrefix: 'media',
35
- doc,
36
- filename: 'logo.png',
37
- prefixQueryParam: 'query-prefix',
38
- req,
39
- uploadReference: {
40
- prefix: 'reference-prefix'
41
- }
42
- });
43
- expect(result).toBe('invoices');
44
- expect(req.payload.find).not.toHaveBeenCalled();
45
- });
46
- it('does not fall back to a lookup when the checked document has no prefix', async ()=>{
47
- const req = makeReq([
48
- {
49
- prefix: 'db-prefix'
50
- }
51
- ]);
52
- const result = await getFilePrefix({
53
- collection: makeCollection(),
54
- collectionPrefix: 'media',
55
- doc: {
56
- id: '1'
57
- },
58
- filename: 'logo.png',
59
- req
60
- });
61
- expect(result).toBe('');
62
- expect(req.payload.find).not.toHaveBeenCalled();
63
- });
64
- it('contains an upload reference prefix beneath the collection prefix', async ()=>{
65
- const req = makeReq();
66
- const result = await getFilePrefix({
67
- collection: makeCollection(),
68
- collectionPrefix: 'media',
69
- filename: 'file.png',
70
- req,
71
- uploadReference: {
72
- prefix: 'invoices'
73
- }
74
- });
75
- expect(result).toBe('media/invoices');
76
- expect(req.payload.find).not.toHaveBeenCalled();
77
- });
78
- describe('verified upload reference (trusted)', ()=>{
79
- it('folds the object key into the prefix and skips the database', async ()=>{
80
- const req = makeReq();
81
- const result = await getFilePrefix({
82
- collection: makeCollection(),
83
- filename: 'logo.png',
84
- req,
85
- uploadReference: {
86
- _objectKey: 'abc123',
87
- prefix: 'documents'
88
- }
89
- });
90
- expect(result).toBe('documents/abc123');
91
- expect(req.payload.find).not.toHaveBeenCalled();
92
- });
93
- it('returns the prefix alone when the reference has no object key', async ()=>{
94
- const req = makeReq();
95
- const result = await getFilePrefix({
96
- collection: makeCollection(),
97
- filename: 'logo.png',
98
- req,
99
- uploadReference: {
100
- prefix: 'documents'
101
- }
102
- });
103
- expect(result).toBe('documents');
104
- });
105
- });
106
- describe('authorized document (trusted)', ()=>{
107
- it('folds the object key into the document prefix and skips the database', async ()=>{
108
- const req = makeReq([
109
- {
110
- prefix: 'db-prefix'
111
- }
112
- ]);
113
- const result = await getFilePrefix({
114
- collection: makeCollection(),
115
- doc: {
116
- id: '1',
117
- _objectKey: 'abc123',
118
- prefix: 'doc-prefix'
119
- },
120
- filename: 'logo.png',
121
- req
122
- });
123
- expect(result).toBe('doc-prefix/abc123');
124
- expect(req.payload.find).not.toHaveBeenCalled();
125
- });
126
- it('returns the document prefix alone when it has no object key', async ()=>{
127
- const req = makeReq();
128
- const result = await getFilePrefix({
129
- collection: makeCollection(),
130
- doc: {
131
- id: '1',
132
- prefix: 'doc-prefix'
133
- },
134
- filename: 'logo.png',
135
- req
136
- });
137
- expect(result).toBe('doc-prefix');
138
- });
139
- it('sanitizes the document prefix', async ()=>{
140
- const req = makeReq();
141
- const result = await getFilePrefix({
142
- collection: makeCollection(),
143
- doc: {
144
- id: '1',
145
- prefix: '../secret'
146
- },
147
- filename: 'logo.png',
148
- req
149
- });
150
- expect(result).toBe('secret');
151
- });
152
- });
153
- describe('access-controlled database resolution', ()=>{
154
- it('does NOT short-circuit on a client-supplied prefix — the access-controlled query still runs', async ()=>{
155
- const req = makeReq([
156
- {
157
- _objectKey: 'abc123',
158
- prefix: 'documents'
159
- }
160
- ]);
161
- await getFilePrefix({
162
- collection: makeCollection({
163
- hasPrefixField: true
164
- }),
165
- filename: 'logo.png',
166
- prefixQueryParam: 'documents',
167
- req
168
- });
169
- expect(req.payload.find).toHaveBeenCalledOnce();
170
- });
171
- it('queries with access control enabled and hidden fields', async ()=>{
172
- const req = makeReq([
173
- {
174
- prefix: 'db-prefix'
175
- }
176
- ]);
177
- await getFilePrefix({
178
- collection: makeCollection(),
179
- filename: 'logo.png',
180
- req
181
- });
182
- expect(req.payload.find).toHaveBeenCalledWith(expect.objectContaining({
183
- overrideAccess: false,
184
- req,
185
- showHiddenFields: true
186
- }));
187
- });
188
- it('folds the stored object key into the resolved prefix', async ()=>{
189
- const req = makeReq([
190
- {
191
- _objectKey: 'abc123',
192
- prefix: 'db-prefix'
193
- }
194
- ]);
195
- const result = await getFilePrefix({
196
- collection: makeCollection(),
197
- filename: 'logo.png',
198
- req
199
- });
200
- expect(result).toBe('db-prefix/abc123');
201
- });
202
- it('returns an empty string when no document is found', async ()=>{
203
- const req = makeReq([]);
204
- const result = await getFilePrefix({
205
- collection: makeCollection(),
206
- filename: 'logo.png',
207
- req
208
- });
209
- expect(result).toBe('');
210
- });
211
- });
212
- describe('client prefix as a disambiguation filter only', ()=>{
213
- it('adds the prefix filter when the collection persists a prefix field', async ()=>{
214
- const req = makeReq([
215
- {
216
- prefix: 'documents'
217
- }
218
- ]);
219
- await getFilePrefix({
220
- collection: makeCollection({
221
- hasPrefixField: true
222
- }),
223
- filename: 'logo.png',
224
- prefixQueryParam: 'documents',
225
- req
226
- });
227
- expect(whereOf(req)).toContain('prefix');
228
- });
229
- it('omits the prefix filter when the collection has no prefix field', async ()=>{
230
- const req = makeReq([
231
- {
232
- prefix: ''
233
- }
234
- ]);
235
- await getFilePrefix({
236
- collection: makeCollection({
237
- hasPrefixField: false
238
- }),
239
- filename: 'logo.png',
240
- prefixQueryParam: 'anything',
241
- req
242
- });
243
- expect(whereOf(req)).not.toContain('prefix');
244
- });
245
- });
246
- });
247
-
248
- //# sourceMappingURL=getFilePrefix.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/utilities/getFilePrefix.spec.ts"],"sourcesContent":["import type { CollectionConfig, PayloadRequest } from 'payload'\n\nimport { describe, expect, it, vi } from 'vitest'\n\nimport { getFilePrefix } from './getFilePrefix.js'\n\nconst makeReq = (docs: unknown[] = []) =>\n ({\n payload: {\n find: vi.fn().mockResolvedValue({ docs }),\n },\n }) as unknown as PayloadRequest\n\nconst makeCollection = ({\n hasPrefixField = false,\n}: { hasPrefixField?: boolean } = {}): CollectionConfig =>\n ({\n slug: 'media',\n fields: hasPrefixField ? [{ name: 'prefix', type: 'text' }] : [],\n upload: {},\n }) as unknown as CollectionConfig\n\nconst whereOf = (req: PayloadRequest) =>\n JSON.stringify(\n (req.payload.find as unknown as { mock: { calls: [{ where: unknown }][] } }).mock.calls[0][0]\n .where,\n )\n\ndescribe('getFilePrefix', () => {\n it('prefers an already-authorized document over an upload reference or query prefix', async () => {\n const req = makeReq([{ prefix: 'db-prefix' }])\n const doc = { id: '1', prefix: 'invoices' }\n\n const result = await getFilePrefix({\n collection: makeCollection(),\n collectionPrefix: 'media',\n doc,\n filename: 'logo.png',\n prefixQueryParam: 'query-prefix',\n req,\n uploadReference: { prefix: 'reference-prefix' },\n })\n\n expect(result).toBe('invoices')\n expect(req.payload.find).not.toHaveBeenCalled()\n })\n\n it('does not fall back to a lookup when the checked document has no prefix', async () => {\n const req = makeReq([{ prefix: 'db-prefix' }])\n\n const result = await getFilePrefix({\n collection: makeCollection(),\n collectionPrefix: 'media',\n doc: { id: '1' },\n filename: 'logo.png',\n req,\n })\n\n expect(result).toBe('')\n expect(req.payload.find).not.toHaveBeenCalled()\n })\n\n it('contains an upload reference prefix beneath the collection prefix', async () => {\n const req = makeReq()\n\n const result = await getFilePrefix({\n collection: makeCollection(),\n collectionPrefix: 'media',\n filename: 'file.png',\n req,\n uploadReference: { prefix: 'invoices' },\n })\n\n expect(result).toBe('media/invoices')\n expect(req.payload.find).not.toHaveBeenCalled()\n })\n\n describe('verified upload reference (trusted)', () => {\n it('folds the object key into the prefix and skips the database', async () => {\n const req = makeReq()\n\n const result = await getFilePrefix({\n collection: makeCollection(),\n filename: 'logo.png',\n req,\n uploadReference: { _objectKey: 'abc123', prefix: 'documents' },\n })\n\n expect(result).toBe('documents/abc123')\n expect(req.payload.find).not.toHaveBeenCalled()\n })\n\n it('returns the prefix alone when the reference has no object key', async () => {\n const req = makeReq()\n\n const result = await getFilePrefix({\n collection: makeCollection(),\n filename: 'logo.png',\n req,\n uploadReference: { prefix: 'documents' },\n })\n\n expect(result).toBe('documents')\n })\n })\n\n describe('authorized document (trusted)', () => {\n it('folds the object key into the document prefix and skips the database', async () => {\n const req = makeReq([{ prefix: 'db-prefix' }])\n\n const result = await getFilePrefix({\n collection: makeCollection(),\n doc: { id: '1', _objectKey: 'abc123', prefix: 'doc-prefix' },\n filename: 'logo.png',\n req,\n })\n\n expect(result).toBe('doc-prefix/abc123')\n expect(req.payload.find).not.toHaveBeenCalled()\n })\n\n it('returns the document prefix alone when it has no object key', async () => {\n const req = makeReq()\n\n const result = await getFilePrefix({\n collection: makeCollection(),\n doc: { id: '1', prefix: 'doc-prefix' },\n filename: 'logo.png',\n req,\n })\n\n expect(result).toBe('doc-prefix')\n })\n\n it('sanitizes the document prefix', async () => {\n const req = makeReq()\n\n const result = await getFilePrefix({\n collection: makeCollection(),\n doc: { id: '1', prefix: '../secret' },\n filename: 'logo.png',\n req,\n })\n\n expect(result).toBe('secret')\n })\n })\n\n describe('access-controlled database resolution', () => {\n it('does NOT short-circuit on a client-supplied prefix — the access-controlled query still runs', async () => {\n const req = makeReq([{ _objectKey: 'abc123', prefix: 'documents' }])\n\n await getFilePrefix({\n collection: makeCollection({ hasPrefixField: true }),\n filename: 'logo.png',\n prefixQueryParam: 'documents',\n req,\n })\n\n expect(req.payload.find).toHaveBeenCalledOnce()\n })\n\n it('queries with access control enabled and hidden fields', async () => {\n const req = makeReq([{ prefix: 'db-prefix' }])\n\n await getFilePrefix({\n collection: makeCollection(),\n filename: 'logo.png',\n req,\n })\n\n expect(req.payload.find).toHaveBeenCalledWith(\n expect.objectContaining({ overrideAccess: false, req, showHiddenFields: true }),\n )\n })\n\n it('folds the stored object key into the resolved prefix', async () => {\n const req = makeReq([{ _objectKey: 'abc123', prefix: 'db-prefix' }])\n\n const result = await getFilePrefix({\n collection: makeCollection(),\n filename: 'logo.png',\n req,\n })\n\n expect(result).toBe('db-prefix/abc123')\n })\n\n it('returns an empty string when no document is found', async () => {\n const req = makeReq([])\n\n const result = await getFilePrefix({\n collection: makeCollection(),\n filename: 'logo.png',\n req,\n })\n\n expect(result).toBe('')\n })\n })\n\n describe('client prefix as a disambiguation filter only', () => {\n it('adds the prefix filter when the collection persists a prefix field', async () => {\n const req = makeReq([{ prefix: 'documents' }])\n\n await getFilePrefix({\n collection: makeCollection({ hasPrefixField: true }),\n filename: 'logo.png',\n prefixQueryParam: 'documents',\n req,\n })\n\n expect(whereOf(req)).toContain('prefix')\n })\n\n it('omits the prefix filter when the collection has no prefix field', async () => {\n const req = makeReq([{ prefix: '' }])\n\n await getFilePrefix({\n collection: makeCollection({ hasPrefixField: false }),\n filename: 'logo.png',\n prefixQueryParam: 'anything',\n req,\n })\n\n expect(whereOf(req)).not.toContain('prefix')\n })\n })\n})\n"],"names":["describe","expect","it","vi","getFilePrefix","makeReq","docs","payload","find","fn","mockResolvedValue","makeCollection","hasPrefixField","slug","fields","name","type","upload","whereOf","req","JSON","stringify","mock","calls","where","prefix","doc","id","result","collection","collectionPrefix","filename","prefixQueryParam","uploadReference","toBe","not","toHaveBeenCalled","_objectKey","toHaveBeenCalledOnce","toHaveBeenCalledWith","objectContaining","overrideAccess","showHiddenFields","toContain"],"mappings":"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"}
@@ -1,74 +0,0 @@
1
- import { createClientUploadReceipt, getSafeFileName } from 'payload/internal';
2
- import { beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { resolveSignedURLKey } from './resolveSignedURLKey.js';
4
- vi.mock('payload/internal', ()=>({
5
- createClientUploadReceipt: vi.fn(()=>'receipt'),
6
- getSafeFileName: vi.fn(async ({ desiredFilename })=>desiredFilename)
7
- }));
8
- describe('resolveSignedURLKey', ()=>{
9
- beforeEach(()=>{
10
- vi.clearAllMocks();
11
- });
12
- it('checks the normalized filename before resolving the storage key', async ()=>{
13
- vi.mocked(getSafeFileName).mockResolvedValueOnce('photo-1.png');
14
- const result = await resolveSignedURLKey({
15
- collectionPrefix: 'media',
16
- collectionSlug: 'uploads',
17
- filename: 'nested\\folder/photo.png',
18
- req: {}
19
- });
20
- expect(getSafeFileName).toHaveBeenCalledWith({
21
- collectionSlug: 'uploads',
22
- desiredFilename: 'photo.png',
23
- req: {}
24
- });
25
- expect(createClientUploadReceipt).toHaveBeenCalledWith({
26
- _objectKey: expect.stringMatching(/^[0-9a-f-]+$/),
27
- collectionSlug: 'uploads',
28
- filePrefix: 'media',
29
- filename: 'photo-1.png',
30
- req: {},
31
- storageFilePath: expect.stringMatching(/^media\/[0-9a-f-]+\/photo-1\.png$/)
32
- });
33
- expect(result).toEqual({
34
- sanitizedDocPrefix: 'media',
35
- sanitizedFilename: 'photo-1.png',
36
- storageFilePath: expect.stringMatching(/^media\/[0-9a-f-]+\/photo-1\.png$/),
37
- uploadReference: {
38
- _objectKey: expect.stringMatching(/^[0-9a-f-]+$/),
39
- prefix: 'media',
40
- signedReceipt: 'receipt'
41
- }
42
- });
43
- });
44
- it('should mint the receipt for a key contained by the collection prefix', async ()=>{
45
- vi.mocked(getSafeFileName).mockResolvedValueOnce('photo-1.jpg');
46
- const result = await resolveSignedURLKey({
47
- collectionPrefix: 'media',
48
- collectionSlug: 'media',
49
- docPrefix: 'media-archive',
50
- filename: 'photo.jpg',
51
- req: {}
52
- });
53
- expect(createClientUploadReceipt).toHaveBeenCalledWith({
54
- _objectKey: expect.stringMatching(/^[0-9a-f-]+$/),
55
- collectionSlug: 'media',
56
- filePrefix: result.sanitizedDocPrefix,
57
- filename: 'photo-1.jpg',
58
- req: {},
59
- storageFilePath: result.storageFilePath
60
- });
61
- expect(result).toEqual({
62
- sanitizedDocPrefix: 'media/media-archive',
63
- sanitizedFilename: 'photo-1.jpg',
64
- storageFilePath: expect.stringMatching(/^media\/media-archive\/[0-9a-f-]+\/photo-1\.jpg$/),
65
- uploadReference: {
66
- _objectKey: expect.stringMatching(/^[0-9a-f-]+$/),
67
- prefix: 'media/media-archive',
68
- signedReceipt: 'receipt'
69
- }
70
- });
71
- });
72
- });
73
-
74
- //# sourceMappingURL=resolveSignedURLKey.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/utilities/resolveSignedURLKey.spec.ts"],"sourcesContent":["import { createClientUploadReceipt, getSafeFileName } from 'payload/internal'\nimport { beforeEach, describe, expect, it, vi } from 'vitest'\n\nimport { resolveSignedURLKey } from './resolveSignedURLKey.js'\n\nvi.mock('payload/internal', () => ({\n createClientUploadReceipt: vi.fn(() => 'receipt'),\n getSafeFileName: vi.fn(async ({ desiredFilename }) => desiredFilename),\n}))\n\ndescribe('resolveSignedURLKey', () => {\n beforeEach(() => {\n vi.clearAllMocks()\n })\n\n it('checks the normalized filename before resolving the storage key', async () => {\n vi.mocked(getSafeFileName).mockResolvedValueOnce('photo-1.png')\n\n const result = await resolveSignedURLKey({\n collectionPrefix: 'media',\n collectionSlug: 'uploads',\n filename: 'nested\\\\folder/photo.png',\n req: {} as never,\n })\n\n expect(getSafeFileName).toHaveBeenCalledWith({\n collectionSlug: 'uploads',\n desiredFilename: 'photo.png',\n req: {},\n })\n expect(createClientUploadReceipt).toHaveBeenCalledWith({\n _objectKey: expect.stringMatching(/^[0-9a-f-]+$/),\n collectionSlug: 'uploads',\n filePrefix: 'media',\n filename: 'photo-1.png',\n req: {},\n storageFilePath: expect.stringMatching(/^media\\/[0-9a-f-]+\\/photo-1\\.png$/),\n })\n expect(result).toEqual({\n sanitizedDocPrefix: 'media',\n sanitizedFilename: 'photo-1.png',\n storageFilePath: expect.stringMatching(/^media\\/[0-9a-f-]+\\/photo-1\\.png$/),\n uploadReference: {\n _objectKey: expect.stringMatching(/^[0-9a-f-]+$/),\n prefix: 'media',\n signedReceipt: 'receipt',\n },\n })\n })\n\n it('should mint the receipt for a key contained by the collection prefix', async () => {\n vi.mocked(getSafeFileName).mockResolvedValueOnce('photo-1.jpg')\n\n const result = await resolveSignedURLKey({\n collectionPrefix: 'media',\n collectionSlug: 'media',\n docPrefix: 'media-archive',\n filename: 'photo.jpg',\n req: {} as never,\n })\n\n expect(createClientUploadReceipt).toHaveBeenCalledWith({\n _objectKey: expect.stringMatching(/^[0-9a-f-]+$/),\n collectionSlug: 'media',\n filePrefix: result.sanitizedDocPrefix,\n filename: 'photo-1.jpg',\n req: {},\n storageFilePath: result.storageFilePath,\n })\n expect(result).toEqual({\n sanitizedDocPrefix: 'media/media-archive',\n sanitizedFilename: 'photo-1.jpg',\n storageFilePath: expect.stringMatching(/^media\\/media-archive\\/[0-9a-f-]+\\/photo-1\\.jpg$/),\n uploadReference: {\n _objectKey: expect.stringMatching(/^[0-9a-f-]+$/),\n prefix: 'media/media-archive',\n signedReceipt: 'receipt',\n },\n })\n })\n})\n"],"names":["createClientUploadReceipt","getSafeFileName","beforeEach","describe","expect","it","vi","resolveSignedURLKey","mock","fn","desiredFilename","clearAllMocks","mocked","mockResolvedValueOnce","result","collectionPrefix","collectionSlug","filename","req","toHaveBeenCalledWith","_objectKey","stringMatching","filePrefix","storageFilePath","toEqual","sanitizedDocPrefix","sanitizedFilename","uploadReference","prefix","signedReceipt","docPrefix"],"mappings":"AAAA,SAASA,yBAAyB,EAAEC,eAAe,QAAQ,mBAAkB;AAC7E,SAASC,UAAU,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,EAAEC,EAAE,QAAQ,SAAQ;AAE7D,SAASC,mBAAmB,QAAQ,2BAA0B;AAE9DD,GAAGE,IAAI,CAAC,oBAAoB,IAAO,CAAA;QACjCR,2BAA2BM,GAAGG,EAAE,CAAC,IAAM;QACvCR,iBAAiBK,GAAGG,EAAE,CAAC,OAAO,EAAEC,eAAe,EAAE,GAAKA;IACxD,CAAA;AAEAP,SAAS,uBAAuB;IAC9BD,WAAW;QACTI,GAAGK,aAAa;IAClB;IAEAN,GAAG,mEAAmE;QACpEC,GAAGM,MAAM,CAACX,iBAAiBY,qBAAqB,CAAC;QAEjD,MAAMC,SAAS,MAAMP,oBAAoB;YACvCQ,kBAAkB;YAClBC,gBAAgB;YAChBC,UAAU;YACVC,KAAK,CAAC;QACR;QAEAd,OAAOH,iBAAiBkB,oBAAoB,CAAC;YAC3CH,gBAAgB;YAChBN,iBAAiB;YACjBQ,KAAK,CAAC;QACR;QACAd,OAAOJ,2BAA2BmB,oBAAoB,CAAC;YACrDC,YAAYhB,OAAOiB,cAAc,CAAC;YAClCL,gBAAgB;YAChBM,YAAY;YACZL,UAAU;YACVC,KAAK,CAAC;YACNK,iBAAiBnB,OAAOiB,cAAc,CAAC;QACzC;QACAjB,OAAOU,QAAQU,OAAO,CAAC;YACrBC,oBAAoB;YACpBC,mBAAmB;YACnBH,iBAAiBnB,OAAOiB,cAAc,CAAC;YACvCM,iBAAiB;gBACfP,YAAYhB,OAAOiB,cAAc,CAAC;gBAClCO,QAAQ;gBACRC,eAAe;YACjB;QACF;IACF;IAEAxB,GAAG,wEAAwE;QACzEC,GAAGM,MAAM,CAACX,iBAAiBY,qBAAqB,CAAC;QAEjD,MAAMC,SAAS,MAAMP,oBAAoB;YACvCQ,kBAAkB;YAClBC,gBAAgB;YAChBc,WAAW;YACXb,UAAU;YACVC,KAAK,CAAC;QACR;QAEAd,OAAOJ,2BAA2BmB,oBAAoB,CAAC;YACrDC,YAAYhB,OAAOiB,cAAc,CAAC;YAClCL,gBAAgB;YAChBM,YAAYR,OAAOW,kBAAkB;YACrCR,UAAU;YACVC,KAAK,CAAC;YACNK,iBAAiBT,OAAOS,eAAe;QACzC;QACAnB,OAAOU,QAAQU,OAAO,CAAC;YACrBC,oBAAoB;YACpBC,mBAAmB;YACnBH,iBAAiBnB,OAAOiB,cAAc,CAAC;YACvCM,iBAAiB;gBACfP,YAAYhB,OAAOiB,cAAc,CAAC;gBAClCO,QAAQ;gBACRC,eAAe;YACjB;QACF;IACF;AACF"}