@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.
- package/dist/fields/getFields.d.ts +1 -5
- package/dist/fields/getFields.d.ts.map +1 -1
- package/dist/fields/getFields.js +27 -28
- package/dist/fields/getFields.js.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +29 -32
- package/dist/plugin.js.map +1 -1
- package/dist/types.d.ts +0 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +4 -4
- package/dist/admin/fields/getFields.d.ts +0 -17
- package/dist/admin/fields/getFields.d.ts.map +0 -1
- package/dist/admin/fields/getFields.js +0 -98
- package/dist/admin/fields/getFields.js.map +0 -1
- package/dist/admin/index.d.ts +0 -4
- package/dist/admin/index.d.ts.map +0 -1
- package/dist/admin/index.js +0 -34
- package/dist/admin/index.js.map +0 -1
- package/dist/hooks/afterChange.spec.js +0 -95
- package/dist/hooks/afterChange.spec.js.map +0 -1
- package/dist/hooks/normalizeUploadPrefix.spec.js +0 -154
- package/dist/hooks/normalizeUploadPrefix.spec.js.map +0 -1
- package/dist/plugin.spec.js +0 -166
- package/dist/plugin.spec.js.map +0 -1
- package/dist/utilities/buildStoragePathData.spec.js +0 -241
- package/dist/utilities/buildStoragePathData.spec.js.map +0 -1
- package/dist/utilities/getFilePrefix.spec.js +0 -248
- package/dist/utilities/getFilePrefix.spec.js.map +0 -1
- package/dist/utilities/resolveSignedURLKey.spec.js +0 -74
- package/dist/utilities/resolveSignedURLKey.spec.js.map +0 -1
|
@@ -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":"AAAA,SACEA,oBAAoB,EACpBC,0BAA0B,EAC1BC,mCAAmC,QAC9B,4BAA2B;AAClC,SAASC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAE7CF,SAAS,gBAAgB;IACvBA,SAAS,oDAAoD;QAC3DE,GAAG,8EAA8E;YAC/E,MAAMC,SAASN,qBAAqB;gBAClCO,kBAAkB;gBAClBC,WAAW;gBACXC,UAAU;gBACVC,sBAAsB;YACxB;YAEAN,OAAOE,QAAQK,OAAO,CAAC;gBACrBC,2BAA2B;gBAC3BC,oBAAoB;gBACpBC,mBAAmB;gBACnBC,iBAAiB;YACnB;QACF;QAEAV,GAAG,+DAA+D;YAChE,MAAMC,SAASN,qBAAqB;gBAClCO,kBAAkB;gBAClBC,WAAW;gBACXC,UAAU;gBACVC,sBAAsB;YACxB;YACAN,OAAOE,QAAQK,OAAO,CAAC;gBACrBC,2BAA2B;gBAC3BC,oBAAoB;gBACpBC,mBAAmB;gBACnBC,iBAAiB;YACnB;QACF;QAEAV,GAAG,mEAAmE;YACpE,MAAMC,SAASN,qBAAqB;gBAClCO,kBAAkB;gBAClBE,UAAU;gBACVC,sBAAsB;YACxB;YACAN,OAAOE,QAAQK,OAAO,CAAC;gBACrBC,2BAA2B;gBAC3BC,oBAAoB;gBACpBC,mBAAmB;gBACnBC,iBAAiB;YACnB;QACF;QAEAV,GAAG,4DAA4D;YAC7D,MAAMC,SAASN,qBAAqB;gBAClCS,UAAU;gBACVC,sBAAsB;YACxB;YACAN,OAAOE,QAAQK,OAAO,CAAC;gBACrBC,2BAA2B;gBAC3BC,oBAAoB;gBACpBC,mBAAmB;gBACnBC,iBAAiB;YACnB;QACF;IACF;IAEAZ,SAAS,+CAA+C;QACtDE,GAAG,iDAAiD;YAClD,MAAMC,SAASN,qBAAqB;gBAClCO,kBAAkB;gBAClBC,WAAW;gBACXC,UAAU;gBACVC,sBAAsB;YACxB;YACAN,OAAOE,QAAQK,OAAO,CAAC;gBACrBC,2BAA2B;gBAC3BC,oBAAoB;gBACpBC,mBAAmB;gBACnBC,iBAAiB;YACnB;QACF;QAEAV,GAAG,0CAA0C;YAC3C,MAAMC,SAASN,qBAAqB;gBAClCO,kBAAkB;gBAClBE,UAAU;gBACVC,sBAAsB;YACxB;YACAN,OAAOE,QAAQK,OAAO,CAAC;gBACrBC,2BAA2B;gBAC3BC,oBAAoB;gBACpBC,mBAAmB;gBACnBC,iBAAiB;YACnB;QACF;QAEAV,GAAG,mCAAmC;YACpC,MAAMC,SAASN,qBAAqB;gBAClCQ,WAAW;gBACXC,UAAU;gBACVC,sBAAsB;YACxB;YACAN,OAAOE,QAAQK,OAAO,CAAC;gBACrBC,2BAA2B;gBAC3BC,oBAAoB;gBACpBC,mBAAmB;gBACnBC,iBAAiB;YACnB;QACF;QAEAV,GAAG,4DAA4D;YAC7D,MAAMC,SAASN,qBAAqB;gBAClCS,UAAU;gBACVC,sBAAsB;YACxB;YACAN,OAAOE,QAAQK,OAAO,CAAC;gBACrBC,2BAA2B;gBAC3BC,oBAAoB;gBACpBC,mBAAmB;gBACnBC,iBAAiB;YACnB;QACF;IACF;IAEAZ,SAAS,gCAAgC;QACvCE,GAAG,wEAAwE;YACzED,OACEF,oCAAoC;gBAClCK,kBAAkB;gBAClBC,WAAW;YACb,IACAQ,IAAI,CAAC;QACT;IACF;IAEAb,SAAS,gBAAgB;QACvBE,GAAGY,IAAI,CAAC;YAAC;YAAoB;YAAiB;SAAiB,EAC7D,+CACA,CAACT;YACC,MAAMF,SAASN,qBAAqB;gBAAEQ;gBAAWC,UAAU;YAAW;YAEtEL,OAAOE,QAAQK,OAAO,CAAC;gBACrBC,2BAA2B;gBAC3BC,oBAAoB;gBACpBC,mBAAmB;gBACnBC,iBAAiB;YACnB;QACF;QAGFV,GAAG,+DAA+D;YAChE,MAAMC,SAASN,qBAAqB;gBAClCO,kBAAkB;gBAClBE,UAAU;gBACVC,sBAAsB;YACxB;YACAN,OAAOE,QAAQK,OAAO,CAAC;gBACrBC,2BAA2B;gBAC3BC,oBAAoB;gBACpBC,mBAAmB;gBACnBC,iBAAiB;YACnB;YACAX,OAAOE,OAAOS,eAAe,EAAEG,GAAG,CAACC,SAAS,CAAC;QAC/C;QAEAd,GAAG,wDAAwD;YACzD,MAAMC,SAASN,qBAAqB;gBAClCQ,WAAW;gBACXC,UAAU;gBACVC,sBAAsB;YACxB;YACAN,OAAOE,QAAQK,OAAO,CAAC;gBACrBC,2BAA2B;gBAC3BC,oBAAoB;gBACpBC,mBAAmB;gBACnBC,iBAAiB;YACnB;YACAX,OAAOE,OAAOS,eAAe,EAAEG,GAAG,CAACC,SAAS,CAAC;QAC/C;QAEAd,GAAG,kDAAkD;YACnD,MAAMC,SAASN,qBAAqB;gBAClCO,kBAAkB;gBAClBE,UAAU;gBACVC,sBAAsB;YACxB;YACAN,OAAOE,QAAQK,OAAO,CAAC;gBACrBC,2BAA2B;gBAC3BC,oBAAoB;gBACpBC,mBAAmB;gBACnBC,iBAAiB;YACnB;YACAX,OAAOE,OAAOS,eAAe,EAAEG,GAAG,CAACE,OAAO,CAAC;QAC7C;QAEAf,GAAG,sFAAsF;YACvF,MAAMC,SAASN,qBAAqB;gBAClCO,kBAAkB;gBAClBC,WAAW;gBACXC,UAAU;gBACVC,sBAAsB;YACxB;YACAN,OAAOE,QAAQK,OAAO,CAAC;gBACrBC,2BAA2B;gBAC3BC,oBAAoB;gBACpBC,mBAAmB;gBACnBC,iBAAiB;YACnB;YACAX,OAAOE,OAAOS,eAAe,EAAEG,GAAG,CAACC,SAAS,CAAC;QAC/C;IACF;AACF;AAEAhB,SAAS,8BAA8B;IACrCE,GAAGY,IAAI,CAAC;QACN;YAAC;YAAY;YAAO;YAA2B;SAAiB;QAChE;YAAC;YAAkB;YAAO;YAA2B;SAAiB;QACtE;YAAC;YAAI;YAAO;YAAkB;SAAG;QACjC;YAAC;YAAY;YAAM;YAA2B;SAAW;KAC1D,EACC,+DACA,CAACT,WAAWE,sBAAsBW,SAASC;QACzC,MAAMhB,SAASL,2BAA2B;YACxCM,kBAAkB;YAClBC;YACAC,UAAU;YACVC;QACF;QAEAN,OAAOE,OAAOS,eAAe,EAAEC,IAAI,CAACK;QACpCjB,OAAOE,OAAOO,kBAAkB,EAAEG,IAAI,CAACM;QACvClB,OACEJ,qBAAqB;YACnBO,kBAAkB;YAClBC,WAAWF,OAAOO,kBAAkB;YACpCJ,UAAU;YACVC;QACF,GAAGK,eAAe,EAClBC,IAAI,CAACK;IACT;AAEJ"}
|
|
@@ -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"}
|