payload 3.89.0 → 3.90.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/forms/Field.d.ts +2 -0
- package/dist/admin/forms/Field.d.ts.map +1 -1
- package/dist/admin/forms/Field.js.map +1 -1
- package/dist/admin/forms/Form.d.ts +2 -0
- package/dist/admin/forms/Form.d.ts.map +1 -1
- package/dist/admin/forms/Form.js.map +1 -1
- package/dist/admin/functions/index.d.ts +3 -1
- package/dist/admin/functions/index.d.ts.map +1 -1
- package/dist/admin/functions/index.js.map +1 -1
- package/dist/admin/views/dashboard.d.ts +1 -1
- package/dist/admin/views/dashboard.d.ts.map +1 -1
- package/dist/admin/views/dashboard.js.map +1 -1
- package/dist/auth/applyUserReadAccess.d.ts +15 -0
- package/dist/auth/applyUserReadAccess.d.ts.map +1 -0
- package/dist/auth/applyUserReadAccess.js +41 -0
- package/dist/auth/applyUserReadAccess.js.map +1 -0
- package/dist/auth/baseFields/apiKey/canCreateOrUpdateAPIKey.d.ts +4 -0
- package/dist/auth/baseFields/apiKey/canCreateOrUpdateAPIKey.d.ts.map +1 -0
- package/dist/auth/baseFields/apiKey/canCreateOrUpdateAPIKey.js +20 -0
- package/dist/auth/baseFields/apiKey/canCreateOrUpdateAPIKey.js.map +1 -0
- package/dist/auth/baseFields/apiKey/encryptAPIKey.d.ts +4 -0
- package/dist/auth/baseFields/apiKey/encryptAPIKey.d.ts.map +1 -0
- package/dist/auth/baseFields/apiKey/encryptAPIKey.js +16 -0
- package/dist/auth/baseFields/apiKey/encryptAPIKey.js.map +1 -0
- package/dist/auth/baseFields/apiKey/index.d.ts +6 -0
- package/dist/auth/baseFields/apiKey/index.d.ts.map +1 -0
- package/dist/auth/baseFields/apiKey/index.js +112 -0
- package/dist/auth/baseFields/apiKey/index.js.map +1 -0
- package/dist/auth/baseFields/apiKey/omitAPIKey.d.ts +4 -0
- package/dist/auth/baseFields/apiKey/omitAPIKey.d.ts.map +1 -0
- package/dist/auth/baseFields/apiKey/omitAPIKey.js +8 -0
- package/dist/auth/baseFields/apiKey/omitAPIKey.js.map +1 -0
- package/dist/auth/baseFields/apiKey/omitAPIKeyIndex.d.ts +4 -0
- package/dist/auth/baseFields/apiKey/omitAPIKeyIndex.d.ts.map +1 -0
- package/dist/auth/baseFields/apiKey/omitAPIKeyIndex.js +5 -0
- package/dist/auth/baseFields/apiKey/omitAPIKeyIndex.js.map +1 -0
- package/dist/auth/baseFields/apiKey/omitEncryptedAPIKey.d.ts +4 -0
- package/dist/auth/baseFields/apiKey/omitEncryptedAPIKey.d.ts.map +1 -0
- package/dist/auth/baseFields/apiKey/omitEncryptedAPIKey.js +5 -0
- package/dist/auth/baseFields/apiKey/omitEncryptedAPIKey.js.map +1 -0
- package/dist/auth/baseFields/apiKey/setAPIKeyIndex.d.ts +4 -0
- package/dist/auth/baseFields/apiKey/setAPIKeyIndex.d.ts.map +1 -0
- package/dist/auth/baseFields/apiKey/setAPIKeyIndex.js +17 -0
- package/dist/auth/baseFields/apiKey/setAPIKeyIndex.js.map +1 -0
- package/dist/auth/baseFields/auth.d.ts +1 -0
- package/dist/auth/baseFields/auth.d.ts.map +1 -1
- package/dist/auth/baseFields/auth.js +9 -0
- package/dist/auth/baseFields/auth.js.map +1 -1
- package/dist/auth/defaultUnlockAccess.d.ts +3 -0
- package/dist/auth/defaultUnlockAccess.d.ts.map +1 -0
- package/dist/auth/defaultUnlockAccess.js +8 -0
- package/dist/auth/defaultUnlockAccess.js.map +1 -0
- package/dist/auth/endpoints/index.d.ts +1 -0
- package/dist/auth/endpoints/index.d.ts.map +1 -1
- package/dist/auth/endpoints/index.js +8 -0
- package/dist/auth/endpoints/index.js.map +1 -1
- package/dist/auth/endpoints/revealAPIKey.d.ts +7 -0
- package/dist/auth/endpoints/revealAPIKey.d.ts.map +1 -0
- package/dist/auth/endpoints/revealAPIKey.js +120 -0
- package/dist/auth/endpoints/revealAPIKey.js.map +1 -0
- package/dist/auth/executeAccess.d.ts +3 -1
- package/dist/auth/executeAccess.d.ts.map +1 -1
- package/dist/auth/executeAccess.js +2 -1
- package/dist/auth/executeAccess.js.map +1 -1
- package/dist/auth/getAuthFields.d.ts +1 -1
- package/dist/auth/getAuthFields.d.ts.map +1 -1
- package/dist/auth/getAuthFields.js +7 -4
- package/dist/auth/getAuthFields.js.map +1 -1
- package/dist/auth/getFieldsToSign.d.ts.map +1 -1
- package/dist/auth/getFieldsToSign.js +17 -10
- package/dist/auth/getFieldsToSign.js.map +1 -1
- package/dist/auth/getFieldsToSign.spec.js +114 -0
- package/dist/auth/getFieldsToSign.spec.js.map +1 -0
- package/dist/auth/jwt.d.ts.map +1 -1
- package/dist/auth/jwt.js +2 -0
- package/dist/auth/jwt.js.map +1 -1
- package/dist/auth/jwt.spec.js +24 -0
- package/dist/auth/jwt.spec.js.map +1 -0
- package/dist/auth/jwtAuth.d.ts +9 -0
- package/dist/auth/jwtAuth.d.ts.map +1 -0
- package/dist/auth/jwtAuth.js +8 -0
- package/dist/auth/jwtAuth.js.map +1 -0
- package/dist/auth/operations/auth.d.ts.map +1 -1
- package/dist/auth/operations/auth.js +2 -1
- package/dist/auth/operations/auth.js.map +1 -1
- package/dist/auth/operations/forgotPassword.d.ts.map +1 -1
- package/dist/auth/operations/forgotPassword.js +95 -7
- package/dist/auth/operations/forgotPassword.js.map +1 -1
- package/dist/auth/operations/local/auth.js +3 -1
- package/dist/auth/operations/local/auth.js.map +1 -1
- package/dist/auth/operations/login.d.ts.map +1 -1
- package/dist/auth/operations/login.js +48 -26
- package/dist/auth/operations/login.js.map +1 -1
- package/dist/auth/operations/refresh.d.ts.map +1 -1
- package/dist/auth/operations/refresh.js +32 -9
- package/dist/auth/operations/refresh.js.map +1 -1
- package/dist/auth/operations/registerFirstUser.d.ts.map +1 -1
- package/dist/auth/operations/registerFirstUser.js +3 -4
- package/dist/auth/operations/registerFirstUser.js.map +1 -1
- package/dist/auth/operations/resetPassword.d.ts.map +1 -1
- package/dist/auth/operations/resetPassword.js +31 -22
- package/dist/auth/operations/resetPassword.js.map +1 -1
- package/dist/auth/operations/unlock.d.ts.map +1 -1
- package/dist/auth/operations/unlock.js +1 -0
- package/dist/auth/operations/unlock.js.map +1 -1
- package/dist/auth/strategies/apiKey.d.ts.map +1 -1
- package/dist/auth/strategies/apiKey.js +15 -1
- package/dist/auth/strategies/apiKey.js.map +1 -1
- package/dist/auth/strategies/jwt.d.ts.map +1 -1
- package/dist/auth/strategies/jwt.js +61 -10
- package/dist/auth/strategies/jwt.js.map +1 -1
- package/dist/auth/strategies/jwt.spec.js +281 -0
- package/dist/auth/strategies/jwt.spec.js.map +1 -0
- package/dist/auth/strategies/local/authenticate.d.ts +5 -1
- package/dist/auth/strategies/local/authenticate.d.ts.map +1 -1
- package/dist/auth/strategies/local/authenticate.js +8 -3
- package/dist/auth/strategies/local/authenticate.js.map +1 -1
- package/dist/auth/strategies/local/authenticate.spec.js +37 -10
- package/dist/auth/strategies/local/authenticate.spec.js.map +1 -1
- package/dist/auth/strategies/local/generatePasswordSaltHash.d.ts +9 -1
- package/dist/auth/strategies/local/generatePasswordSaltHash.d.ts.map +1 -1
- package/dist/auth/strategies/local/generatePasswordSaltHash.js +61 -34
- package/dist/auth/strategies/local/generatePasswordSaltHash.js.map +1 -1
- package/dist/auth/types.d.ts +16 -1
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/auth/types.js.map +1 -1
- package/dist/collections/config/client.d.ts +1 -0
- package/dist/collections/config/client.d.ts.map +1 -1
- package/dist/collections/config/client.js +3 -0
- package/dist/collections/config/client.js.map +1 -1
- package/dist/collections/config/defaults.d.ts.map +1 -1
- package/dist/collections/config/defaults.js +4 -2
- package/dist/collections/config/defaults.js.map +1 -1
- package/dist/collections/config/sanitize.d.ts.map +1 -1
- package/dist/collections/config/sanitize.js +17 -6
- package/dist/collections/config/sanitize.js.map +1 -1
- package/dist/collections/endpoints/index.d.ts +1 -0
- package/dist/collections/endpoints/index.d.ts.map +1 -1
- package/dist/collections/endpoints/index.js +6 -5
- package/dist/collections/endpoints/index.js.map +1 -1
- package/dist/collections/operations/create.d.ts.map +1 -1
- package/dist/collections/operations/create.js +105 -8
- package/dist/collections/operations/create.js.map +1 -1
- package/dist/collections/operations/deleteByID.js +13 -13
- package/dist/collections/operations/deleteByID.js.map +1 -1
- package/dist/collections/operations/findDistinct.d.ts.map +1 -1
- package/dist/collections/operations/findDistinct.js +96 -18
- package/dist/collections/operations/findDistinct.js.map +1 -1
- package/dist/collections/operations/restoreVersion.d.ts.map +1 -1
- package/dist/collections/operations/restoreVersion.js +47 -13
- package/dist/collections/operations/restoreVersion.js.map +1 -1
- package/dist/collections/operations/update.d.ts.map +1 -1
- package/dist/collections/operations/update.js +118 -18
- package/dist/collections/operations/update.js.map +1 -1
- package/dist/collections/operations/updateByID.d.ts.map +1 -1
- package/dist/collections/operations/updateByID.js +62 -2
- package/dist/collections/operations/updateByID.js.map +1 -1
- package/dist/collections/operations/utilities/update.d.ts.map +1 -1
- package/dist/collections/operations/utilities/update.js +71 -15
- package/dist/collections/operations/utilities/update.js.map +1 -1
- package/dist/config/orderable/index.d.ts.map +1 -1
- package/dist/config/orderable/index.js +67 -14
- package/dist/config/orderable/index.js.map +1 -1
- package/dist/config/sanitize.d.ts.map +1 -1
- package/dist/config/sanitize.js +1 -1
- package/dist/config/sanitize.js.map +1 -1
- package/dist/config/types.d.ts +13 -1
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js.map +1 -1
- package/dist/database/getLocalizedPaths.d.ts +2 -1
- package/dist/database/getLocalizedPaths.d.ts.map +1 -1
- package/dist/database/getLocalizedPaths.js +12 -3
- package/dist/database/getLocalizedPaths.js.map +1 -1
- package/dist/database/isNestedRelationshipQuery.d.ts +9 -0
- package/dist/database/isNestedRelationshipQuery.d.ts.map +1 -0
- package/dist/database/isNestedRelationshipQuery.js +14 -0
- package/dist/database/isNestedRelationshipQuery.js.map +1 -0
- package/dist/database/prefixWherePaths.d.ts +6 -0
- package/dist/database/prefixWherePaths.d.ts.map +1 -0
- package/dist/database/prefixWherePaths.js +19 -0
- package/dist/database/prefixWherePaths.js.map +1 -0
- package/dist/database/prefixWherePaths.spec.js +46 -0
- package/dist/database/prefixWherePaths.spec.js.map +1 -0
- package/dist/database/queryValidation/validateQueryPaths.d.ts +2 -1
- package/dist/database/queryValidation/validateQueryPaths.d.ts.map +1 -1
- package/dist/database/queryValidation/validateQueryPaths.js +4 -1
- package/dist/database/queryValidation/validateQueryPaths.js.map +1 -1
- package/dist/database/queryValidation/validateSearchParams.d.ts +2 -1
- package/dist/database/queryValidation/validateSearchParams.d.ts.map +1 -1
- package/dist/database/queryValidation/validateSearchParams.js +82 -4
- package/dist/database/queryValidation/validateSearchParams.js.map +1 -1
- package/dist/database/types.d.ts +5 -0
- package/dist/database/types.d.ts.map +1 -1
- package/dist/database/types.js.map +1 -1
- package/dist/email/normalizeSendEmailOptions.js.map +1 -1
- package/dist/email/types.d.ts +4 -1
- package/dist/email/types.d.ts.map +1 -1
- package/dist/email/types.js.map +1 -1
- package/dist/exports/internal.d.ts +7 -0
- package/dist/exports/internal.d.ts.map +1 -1
- package/dist/exports/internal.js +7 -1
- package/dist/exports/internal.js.map +1 -1
- package/dist/exports/shared.d.ts +3 -0
- package/dist/exports/shared.d.ts.map +1 -1
- package/dist/exports/shared.js +3 -0
- package/dist/exports/shared.js.map +1 -1
- package/dist/fields/config/types.d.ts +7 -5
- package/dist/fields/config/types.d.ts.map +1 -1
- package/dist/fields/config/types.js.map +1 -1
- package/dist/fields/hooks/beforeChange/index.d.ts +7 -1
- package/dist/fields/hooks/beforeChange/index.d.ts.map +1 -1
- package/dist/fields/hooks/beforeChange/index.js +4 -2
- package/dist/fields/hooks/beforeChange/index.js.map +1 -1
- package/dist/fields/hooks/beforeChange/index.spec.js +206 -0
- package/dist/fields/hooks/beforeChange/index.spec.js.map +1 -0
- package/dist/fields/hooks/beforeChange/promise.d.ts +2 -1
- package/dist/fields/hooks/beforeChange/promise.d.ts.map +1 -1
- package/dist/fields/hooks/beforeChange/promise.js +51 -9
- package/dist/fields/hooks/beforeChange/promise.js.map +1 -1
- package/dist/fields/hooks/beforeChange/traverseFields.d.ts +2 -1
- package/dist/fields/hooks/beforeChange/traverseFields.d.ts.map +1 -1
- package/dist/fields/hooks/beforeChange/traverseFields.js +3 -2
- package/dist/fields/hooks/beforeChange/traverseFields.js.map +1 -1
- package/dist/fields/hooks/beforeDuplicate/promise.d.ts.map +1 -1
- package/dist/fields/hooks/beforeDuplicate/promise.js +4 -0
- package/dist/fields/hooks/beforeDuplicate/promise.js.map +1 -1
- package/dist/fields/hooks/beforeValidate/getFallbackValue.d.ts +2 -1
- package/dist/fields/hooks/beforeValidate/getFallbackValue.d.ts.map +1 -1
- package/dist/fields/hooks/beforeValidate/getFallbackValue.js +2 -2
- package/dist/fields/hooks/beforeValidate/getFallbackValue.js.map +1 -1
- package/dist/fields/hooks/beforeValidate/index.d.ts +6 -1
- package/dist/fields/hooks/beforeValidate/index.d.ts.map +1 -1
- package/dist/fields/hooks/beforeValidate/index.js +3 -1
- package/dist/fields/hooks/beforeValidate/index.js.map +1 -1
- package/dist/fields/hooks/beforeValidate/index.spec.js +90 -0
- package/dist/fields/hooks/beforeValidate/index.spec.js.map +1 -0
- package/dist/fields/hooks/beforeValidate/promise.d.ts +6 -1
- package/dist/fields/hooks/beforeValidate/promise.d.ts.map +1 -1
- package/dist/fields/hooks/beforeValidate/promise.js +23 -8
- package/dist/fields/hooks/beforeValidate/promise.js.map +1 -1
- package/dist/fields/hooks/beforeValidate/traverseFields.d.ts +6 -1
- package/dist/fields/hooks/beforeValidate/traverseFields.d.ts.map +1 -1
- package/dist/fields/hooks/beforeValidate/traverseFields.js +3 -1
- package/dist/fields/hooks/beforeValidate/traverseFields.js.map +1 -1
- package/dist/fields/validations.d.ts.map +1 -1
- package/dist/fields/validations.js +3 -1
- package/dist/fields/validations.js.map +1 -1
- package/dist/globals/operations/restoreVersion.d.ts.map +1 -1
- package/dist/globals/operations/restoreVersion.js +45 -11
- package/dist/globals/operations/restoreVersion.js.map +1 -1
- package/dist/globals/operations/update.d.ts.map +1 -1
- package/dist/globals/operations/update.js +95 -16
- package/dist/globals/operations/update.js.map +1 -1
- package/dist/index.bundled.d.ts +102 -24
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/preferences/config.d.ts.map +1 -1
- package/dist/preferences/config.js +2 -1
- package/dist/preferences/config.js.map +1 -1
- package/dist/query-presets/access.d.ts.map +1 -1
- package/dist/query-presets/access.js +2 -1
- package/dist/query-presets/access.js.map +1 -1
- package/dist/queues/config/types/index.d.ts +2 -1
- package/dist/queues/config/types/index.d.ts.map +1 -1
- package/dist/queues/config/types/index.js.map +1 -1
- package/dist/uploads/assertClientUploadAccess.d.ts +7 -0
- package/dist/uploads/assertClientUploadAccess.d.ts.map +1 -0
- package/dist/uploads/assertClientUploadAccess.js +27 -0
- package/dist/uploads/assertClientUploadAccess.js.map +1 -0
- package/dist/uploads/assertClientUploadAllowed.d.ts +11 -0
- package/dist/uploads/assertClientUploadAllowed.d.ts.map +1 -0
- package/dist/uploads/assertClientUploadAllowed.js +46 -0
- package/dist/uploads/assertClientUploadAllowed.js.map +1 -0
- package/dist/uploads/assertClientUploadAllowed.spec.js +91 -0
- package/dist/uploads/assertClientUploadAllowed.spec.js.map +1 -0
- package/dist/uploads/checkFileRestrictions.d.ts +4 -1
- package/dist/uploads/checkFileRestrictions.d.ts.map +1 -1
- package/dist/uploads/checkFileRestrictions.js +66 -26
- package/dist/uploads/checkFileRestrictions.js.map +1 -1
- package/dist/uploads/clientUploadReceipt.d.ts +23 -0
- package/dist/uploads/clientUploadReceipt.d.ts.map +1 -0
- package/dist/uploads/clientUploadReceipt.js +55 -0
- package/dist/uploads/clientUploadReceipt.js.map +1 -0
- package/dist/uploads/deleteAssociatedFiles.d.ts.map +1 -1
- package/dist/uploads/deleteAssociatedFiles.js +33 -8
- package/dist/uploads/deleteAssociatedFiles.js.map +1 -1
- package/dist/uploads/deleteAssociatedFiles.spec.js +124 -0
- package/dist/uploads/deleteAssociatedFiles.spec.js.map +1 -0
- package/dist/uploads/detectSvgFromXml.d.ts +1 -3
- package/dist/uploads/detectSvgFromXml.d.ts.map +1 -1
- package/dist/uploads/detectSvgFromXml.js +3 -40
- package/dist/uploads/detectSvgFromXml.js.map +1 -1
- package/dist/uploads/endpoints/getFile.d.ts.map +1 -1
- package/dist/uploads/endpoints/getFile.js +5 -3
- package/dist/uploads/endpoints/getFile.js.map +1 -1
- package/dist/uploads/fetchAPI-multipart/handlers.d.ts +2 -2
- package/dist/uploads/fetchAPI-multipart/handlers.d.ts.map +1 -1
- package/dist/uploads/fetchAPI-multipart/handlers.js +18 -5
- package/dist/uploads/fetchAPI-multipart/handlers.js.map +1 -1
- package/dist/uploads/fetchAPI-multipart/index.d.ts.map +1 -1
- package/dist/uploads/fetchAPI-multipart/index.js +24 -2
- package/dist/uploads/fetchAPI-multipart/index.js.map +1 -1
- package/dist/uploads/fetchAPI-multipart/processMultipart.d.ts +0 -6
- package/dist/uploads/fetchAPI-multipart/processMultipart.d.ts.map +1 -1
- package/dist/uploads/fetchAPI-multipart/processMultipart.js +146 -126
- package/dist/uploads/fetchAPI-multipart/processMultipart.js.map +1 -1
- package/dist/uploads/fetchAPI-multipart/processMultipart.spec.js +663 -0
- package/dist/uploads/fetchAPI-multipart/processMultipart.spec.js.map +1 -0
- package/dist/uploads/generateFileData.d.ts +3 -1
- package/dist/uploads/generateFileData.d.ts.map +1 -1
- package/dist/uploads/generateFileData.js +29 -16
- package/dist/uploads/generateFileData.js.map +1 -1
- package/dist/uploads/getBaseFields.d.ts.map +1 -1
- package/dist/uploads/getBaseFields.js +3 -1
- package/dist/uploads/getBaseFields.js.map +1 -1
- package/dist/uploads/getExternalFile.d.ts +1 -1
- package/dist/uploads/getExternalFile.d.ts.map +1 -1
- package/dist/uploads/getExternalFile.js +60 -15
- package/dist/uploads/getExternalFile.js.map +1 -1
- package/dist/uploads/getFileTypeFallback.d.ts.map +1 -1
- package/dist/uploads/getFileTypeFallback.js +3 -1
- package/dist/uploads/getFileTypeFallback.js.map +1 -1
- package/dist/uploads/getFileTypeIdentity.d.ts +19 -0
- package/dist/uploads/getFileTypeIdentity.d.ts.map +1 -0
- package/dist/uploads/getFileTypeIdentity.js +34 -0
- package/dist/uploads/getFileTypeIdentity.js.map +1 -0
- package/dist/uploads/getFileTypeIdentity.spec.js +43 -0
- package/dist/uploads/getFileTypeIdentity.spec.js.map +1 -0
- package/dist/uploads/isProcessableImage.d.ts +2 -0
- package/dist/uploads/isProcessableImage.d.ts.map +1 -0
- package/dist/uploads/isProcessableImage.js +7 -0
- package/dist/uploads/isProcessableImage.js.map +1 -0
- package/dist/uploads/safeFetch.d.ts.map +1 -1
- package/dist/uploads/safeFetch.js +3 -2
- package/dist/uploads/safeFetch.js.map +1 -1
- package/dist/uploads/sanitizeUploadData.d.ts +26 -0
- package/dist/uploads/sanitizeUploadData.d.ts.map +1 -0
- package/dist/uploads/sanitizeUploadData.js +159 -0
- package/dist/uploads/sanitizeUploadData.js.map +1 -0
- package/dist/uploads/sanitizeUploadData.spec.js +255 -0
- package/dist/uploads/sanitizeUploadData.spec.js.map +1 -0
- package/dist/uploads/types.d.ts +11 -3
- package/dist/uploads/types.d.ts.map +1 -1
- package/dist/uploads/types.js.map +1 -1
- package/dist/uploads/uploadContentSecurityPolicy.d.ts +2 -0
- package/dist/uploads/uploadContentSecurityPolicy.d.ts.map +1 -0
- package/dist/uploads/uploadContentSecurityPolicy.js +3 -0
- package/dist/uploads/uploadContentSecurityPolicy.js.map +1 -0
- package/dist/uploads/validateISOBaseMediaFile.d.ts +4 -0
- package/dist/uploads/validateISOBaseMediaFile.d.ts.map +1 -0
- package/dist/uploads/validateISOBaseMediaFile.js +91 -0
- package/dist/uploads/validateISOBaseMediaFile.js.map +1 -0
- package/dist/uploads/validateISOBaseMediaFile.spec.js +130 -0
- package/dist/uploads/validateISOBaseMediaFile.spec.js.map +1 -0
- package/dist/uploads/validateSvg.d.ts +10 -4
- package/dist/uploads/validateSvg.d.ts.map +1 -1
- package/dist/uploads/validateSvg.js +280 -40
- package/dist/uploads/validateSvg.js.map +1 -1
- package/dist/uploads/validateSvg.spec.js +123 -0
- package/dist/uploads/validateSvg.spec.js.map +1 -0
- package/dist/uploads/validateUploadFilename.d.ts +3 -0
- package/dist/uploads/validateUploadFilename.d.ts.map +1 -0
- package/dist/uploads/validateUploadFilename.js +13 -0
- package/dist/uploads/validateUploadFilename.js.map +1 -0
- package/dist/uploads/validateUploadFilename.spec.js +24 -0
- package/dist/uploads/validateUploadFilename.spec.js.map +1 -0
- package/dist/utilities/addDataAndFileToRequest.d.ts.map +1 -1
- package/dist/utilities/addDataAndFileToRequest.js +28 -1
- package/dist/utilities/addDataAndFileToRequest.js.map +1 -1
- package/dist/utilities/addDataAndFileToRequest.spec.js +158 -0
- package/dist/utilities/addDataAndFileToRequest.spec.js.map +1 -1
- package/dist/utilities/createPayloadRequest.d.ts.map +1 -1
- package/dist/utilities/createPayloadRequest.js +2 -1
- package/dist/utilities/createPayloadRequest.js.map +1 -1
- package/dist/utilities/deepCopyObject.d.ts.map +1 -1
- package/dist/utilities/deepCopyObject.js +110 -19
- package/dist/utilities/deepCopyObject.js.map +1 -1
- package/dist/utilities/deepCopyObject.spec.js +216 -0
- package/dist/utilities/deepCopyObject.spec.js.map +1 -0
- package/dist/utilities/fieldPath.d.ts +13 -0
- package/dist/utilities/fieldPath.d.ts.map +1 -0
- package/dist/utilities/fieldPath.js +51 -0
- package/dist/utilities/fieldPath.js.map +1 -0
- package/dist/utilities/fieldPath.spec.js +155 -0
- package/dist/utilities/fieldPath.spec.js.map +1 -0
- package/dist/utilities/getEntityPermissions/getEntityPermissions.d.ts.map +1 -1
- package/dist/utilities/getEntityPermissions/getEntityPermissions.js +2 -0
- package/dist/utilities/getEntityPermissions/getEntityPermissions.js.map +1 -1
- package/dist/utilities/getObjectDotNotation.d.ts.map +1 -1
- package/dist/utilities/getObjectDotNotation.js +7 -1
- package/dist/utilities/getObjectDotNotation.js.map +1 -1
- package/dist/utilities/getObjectDotNotation.spec.js +33 -0
- package/dist/utilities/getObjectDotNotation.spec.js.map +1 -0
- package/dist/utilities/getSafeRedirect.spec.js +14 -0
- package/dist/utilities/getSafeRedirect.spec.js.map +1 -1
- package/dist/utilities/getTopLevelFieldNames.d.ts +2 -0
- package/dist/utilities/getTopLevelFieldNames.d.ts.map +1 -0
- package/dist/utilities/getTopLevelFieldNames.js +3 -0
- package/dist/utilities/getTopLevelFieldNames.js.map +1 -0
- package/dist/utilities/getTopLevelFieldNames.spec.js +18 -0
- package/dist/utilities/getTopLevelFieldNames.spec.js.map +1 -0
- package/dist/utilities/handleEndpoints.js +1 -1
- package/dist/utilities/handleEndpoints.js.map +1 -1
- package/dist/utilities/parseParams/index.d.ts.map +1 -1
- package/dist/utilities/parseParams/index.js +3 -1
- package/dist/utilities/parseParams/index.js.map +1 -1
- package/dist/utilities/parseParams/index.spec.js +8 -0
- package/dist/utilities/parseParams/index.spec.js.map +1 -1
- package/dist/utilities/traverseFields.d.ts.map +1 -1
- package/dist/utilities/traverseFields.js +5 -14
- package/dist/utilities/traverseFields.js.map +1 -1
- package/dist/utilities/unflatten.d.ts.map +1 -1
- package/dist/utilities/unflatten.js +21 -9
- package/dist/utilities/unflatten.js.map +1 -1
- package/dist/utilities/unflatten.spec.js +38 -0
- package/dist/utilities/unflatten.spec.js.map +1 -0
- package/dist/versions/allLocalesPublicationStatus.d.ts +38 -0
- package/dist/versions/allLocalesPublicationStatus.d.ts.map +1 -0
- package/dist/versions/allLocalesPublicationStatus.js +57 -0
- package/dist/versions/allLocalesPublicationStatus.js.map +1 -0
- package/dist/versions/getLatestGlobalVersion.d.ts.map +1 -1
- package/dist/versions/getLatestGlobalVersion.js +10 -2
- package/dist/versions/getLatestGlobalVersion.js.map +1 -1
- package/dist/versions/getRestoredStatusesToAuthorize.d.ts +9 -0
- package/dist/versions/getRestoredStatusesToAuthorize.d.ts.map +1 -0
- package/dist/versions/getRestoredStatusesToAuthorize.js +22 -0
- package/dist/versions/getRestoredStatusesToAuthorize.js.map +1 -0
- package/dist/versions/getRestoredStatusesToAuthorize.spec.js +50 -0
- package/dist/versions/getRestoredStatusesToAuthorize.spec.js.map +1 -0
- package/dist/versions/schedule/job.d.ts +2 -2
- package/dist/versions/schedule/job.d.ts.map +1 -1
- package/dist/versions/schedule/job.js +11 -7
- package/dist/versions/schedule/job.js.map +1 -1
- package/dist/versions/schedule/types.d.ts +5 -1
- package/dist/versions/schedule/types.d.ts.map +1 -1
- package/dist/versions/schedule/types.js.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
import { APIError } from '../errors/APIError.js';
|
|
3
|
+
const LIFETIME_MS = 6 * 60 * 60 * 1000;
|
|
4
|
+
const DOMAIN = 'payload-client-upload-receipt-v1';
|
|
5
|
+
export const createClientUploadReceipt = ({ collectionSlug, context, filename, req, user = getUser(req) })=>{
|
|
6
|
+
const data = {
|
|
7
|
+
collectionSlug,
|
|
8
|
+
context,
|
|
9
|
+
expiresAt: Date.now() + LIFETIME_MS,
|
|
10
|
+
filename,
|
|
11
|
+
...user
|
|
12
|
+
};
|
|
13
|
+
const encodedReceipt = Buffer.from(JSON.stringify(data)).toString('base64url');
|
|
14
|
+
return `${encodedReceipt}.${sign(encodedReceipt, req.payload.secret)}`;
|
|
15
|
+
};
|
|
16
|
+
export const verifyClientUploadReceipt = ({ collectionSlug, req, signedReceipt })=>{
|
|
17
|
+
const [encodedReceipt, signature, extra] = signedReceipt.split('.');
|
|
18
|
+
const expected = encodedReceipt ? sign(encodedReceipt, req.payload.secret) : '';
|
|
19
|
+
if (!encodedReceipt || !signature || extra || !equal(signature, expected)) {
|
|
20
|
+
throwInvalidReference();
|
|
21
|
+
}
|
|
22
|
+
let decodedReceipt;
|
|
23
|
+
try {
|
|
24
|
+
decodedReceipt = JSON.parse(Buffer.from(encodedReceipt, 'base64url').toString());
|
|
25
|
+
} catch {
|
|
26
|
+
throwInvalidReference();
|
|
27
|
+
}
|
|
28
|
+
const user = getUser(req);
|
|
29
|
+
if (!isReceipt(decodedReceipt) || decodedReceipt.collectionSlug !== collectionSlug || decodedReceipt.expiresAt <= Date.now() || decodedReceipt.userCollection !== user.userCollection || decodedReceipt.userID !== user.userID) {
|
|
30
|
+
throwInvalidReference();
|
|
31
|
+
}
|
|
32
|
+
return decodedReceipt;
|
|
33
|
+
};
|
|
34
|
+
function throwInvalidReference() {
|
|
35
|
+
throw new APIError('Invalid or expired client upload reference.', 400);
|
|
36
|
+
}
|
|
37
|
+
const getUser = (req)=>({
|
|
38
|
+
userCollection: req.user?.collection ?? null,
|
|
39
|
+
userID: req.user?.id ?? null
|
|
40
|
+
});
|
|
41
|
+
const sign = (encodedReceipt, secret)=>crypto.createHmac('sha256', `${DOMAIN}:${secret}`).update(encodedReceipt).digest('base64url');
|
|
42
|
+
const equal = (actual, expected)=>{
|
|
43
|
+
const actualBuffer = Buffer.from(actual);
|
|
44
|
+
const expectedBuffer = Buffer.from(expected);
|
|
45
|
+
return actualBuffer.length === expectedBuffer.length && crypto.timingSafeEqual(actualBuffer, expectedBuffer);
|
|
46
|
+
};
|
|
47
|
+
const isReceipt = (value)=>{
|
|
48
|
+
if (!value || typeof value !== 'object') {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
const data = value;
|
|
52
|
+
return typeof data.collectionSlug === 'string' && Boolean(data.context) && typeof data.context === 'object' && !Array.isArray(data.context) && typeof data.expiresAt === 'number' && Number.isFinite(data.expiresAt) && typeof data.filename === 'string' && (data.userCollection === null || typeof data.userCollection === 'string') && (data.userID === null || typeof data.userID === 'string' || typeof data.userID === 'number' && Number.isFinite(data.userID));
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
//# sourceMappingURL=clientUploadReceipt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/uploads/clientUploadReceipt.ts"],"sourcesContent":["import crypto from 'crypto'\n\nimport type { PayloadRequest } from '../types/index.js'\n\nimport { APIError } from '../errors/APIError.js'\n\nexport type ClientUploadReceipt = {\n collectionSlug: string\n context: Record<string, unknown>\n expiresAt: number\n filename: string\n userCollection: null | string\n userID: null | number | string\n}\n\n// `<base64url payload>.<base64url HMAC signature>`\nexport type SignedClientUploadReceipt = `${string}.${string}`\n\nconst LIFETIME_MS = 6 * 60 * 60 * 1000\nconst DOMAIN = 'payload-client-upload-receipt-v1'\n\nexport const createClientUploadReceipt = ({\n collectionSlug,\n context,\n filename,\n req,\n user = getUser(req),\n}: {\n collectionSlug: string\n context: Record<string, unknown>\n filename: string\n req: PayloadRequest\n user?: Pick<ClientUploadReceipt, 'userCollection' | 'userID'>\n}): SignedClientUploadReceipt => {\n const data: ClientUploadReceipt = {\n collectionSlug,\n context,\n expiresAt: Date.now() + LIFETIME_MS,\n filename,\n ...user,\n }\n const encodedReceipt = Buffer.from(JSON.stringify(data)).toString('base64url')\n\n return `${encodedReceipt}.${sign(encodedReceipt, req.payload.secret)}`\n}\n\nexport const verifyClientUploadReceipt = ({\n collectionSlug,\n req,\n signedReceipt,\n}: {\n collectionSlug: string\n req: PayloadRequest\n signedReceipt: string\n}): ClientUploadReceipt => {\n const [encodedReceipt, signature, extra] = signedReceipt.split('.')\n const expected = encodedReceipt ? sign(encodedReceipt, req.payload.secret) : ''\n\n if (!encodedReceipt || !signature || extra || !equal(signature, expected)) {\n throwInvalidReference()\n }\n\n let decodedReceipt: unknown\n try {\n decodedReceipt = JSON.parse(Buffer.from(encodedReceipt, 'base64url').toString())\n } catch {\n throwInvalidReference()\n }\n\n const user = getUser(req)\n if (\n !isReceipt(decodedReceipt) ||\n decodedReceipt.collectionSlug !== collectionSlug ||\n decodedReceipt.expiresAt <= Date.now() ||\n decodedReceipt.userCollection !== user.userCollection ||\n decodedReceipt.userID !== user.userID\n ) {\n throwInvalidReference()\n }\n\n return decodedReceipt\n}\n\nfunction throwInvalidReference(): never {\n throw new APIError('Invalid or expired client upload reference.', 400)\n}\n\nconst getUser = (req: PayloadRequest) => ({\n userCollection: req.user?.collection ?? null,\n userID: req.user?.id ?? null,\n})\n\nconst sign = (encodedReceipt: string, secret: string) =>\n crypto.createHmac('sha256', `${DOMAIN}:${secret}`).update(encodedReceipt).digest('base64url')\n\nconst equal = (actual: string, expected: string) => {\n const actualBuffer = Buffer.from(actual)\n const expectedBuffer = Buffer.from(expected)\n return (\n actualBuffer.length === expectedBuffer.length &&\n crypto.timingSafeEqual(actualBuffer, expectedBuffer)\n )\n}\n\nconst isReceipt = (value: unknown): value is ClientUploadReceipt => {\n if (!value || typeof value !== 'object') {\n return false\n }\n const data = value as Partial<ClientUploadReceipt>\n return (\n typeof data.collectionSlug === 'string' &&\n Boolean(data.context) &&\n typeof data.context === 'object' &&\n !Array.isArray(data.context) &&\n typeof data.expiresAt === 'number' &&\n Number.isFinite(data.expiresAt) &&\n typeof data.filename === 'string' &&\n (data.userCollection === null || typeof data.userCollection === 'string') &&\n (data.userID === null ||\n typeof data.userID === 'string' ||\n (typeof data.userID === 'number' && Number.isFinite(data.userID)))\n )\n}\n"],"names":["crypto","APIError","LIFETIME_MS","DOMAIN","createClientUploadReceipt","collectionSlug","context","filename","req","user","getUser","data","expiresAt","Date","now","encodedReceipt","Buffer","from","JSON","stringify","toString","sign","payload","secret","verifyClientUploadReceipt","signedReceipt","signature","extra","split","expected","equal","throwInvalidReference","decodedReceipt","parse","isReceipt","userCollection","userID","collection","id","createHmac","update","digest","actual","actualBuffer","expectedBuffer","length","timingSafeEqual","value","Boolean","Array","isArray","Number","isFinite"],"mappings":"AAAA,OAAOA,YAAY,SAAQ;AAI3B,SAASC,QAAQ,QAAQ,wBAAuB;AAchD,MAAMC,cAAc,IAAI,KAAK,KAAK;AAClC,MAAMC,SAAS;AAEf,OAAO,MAAMC,4BAA4B,CAAC,EACxCC,cAAc,EACdC,OAAO,EACPC,QAAQ,EACRC,GAAG,EACHC,OAAOC,QAAQF,IAAI,EAOpB;IACC,MAAMG,OAA4B;QAChCN;QACAC;QACAM,WAAWC,KAAKC,GAAG,KAAKZ;QACxBK;QACA,GAAGE,IAAI;IACT;IACA,MAAMM,iBAAiBC,OAAOC,IAAI,CAACC,KAAKC,SAAS,CAACR,OAAOS,QAAQ,CAAC;IAElE,OAAO,GAAGL,eAAe,CAAC,EAAEM,KAAKN,gBAAgBP,IAAIc,OAAO,CAACC,MAAM,GAAG;AACxE,EAAC;AAED,OAAO,MAAMC,4BAA4B,CAAC,EACxCnB,cAAc,EACdG,GAAG,EACHiB,aAAa,EAKd;IACC,MAAM,CAACV,gBAAgBW,WAAWC,MAAM,GAAGF,cAAcG,KAAK,CAAC;IAC/D,MAAMC,WAAWd,iBAAiBM,KAAKN,gBAAgBP,IAAIc,OAAO,CAACC,MAAM,IAAI;IAE7E,IAAI,CAACR,kBAAkB,CAACW,aAAaC,SAAS,CAACG,MAAMJ,WAAWG,WAAW;QACzEE;IACF;IAEA,IAAIC;IACJ,IAAI;QACFA,iBAAiBd,KAAKe,KAAK,CAACjB,OAAOC,IAAI,CAACF,gBAAgB,aAAaK,QAAQ;IAC/E,EAAE,OAAM;QACNW;IACF;IAEA,MAAMtB,OAAOC,QAAQF;IACrB,IACE,CAAC0B,UAAUF,mBACXA,eAAe3B,cAAc,KAAKA,kBAClC2B,eAAepB,SAAS,IAAIC,KAAKC,GAAG,MACpCkB,eAAeG,cAAc,KAAK1B,KAAK0B,cAAc,IACrDH,eAAeI,MAAM,KAAK3B,KAAK2B,MAAM,EACrC;QACAL;IACF;IAEA,OAAOC;AACT,EAAC;AAED,SAASD;IACP,MAAM,IAAI9B,SAAS,+CAA+C;AACpE;AAEA,MAAMS,UAAU,CAACF,MAAyB,CAAA;QACxC2B,gBAAgB3B,IAAIC,IAAI,EAAE4B,cAAc;QACxCD,QAAQ5B,IAAIC,IAAI,EAAE6B,MAAM;IAC1B,CAAA;AAEA,MAAMjB,OAAO,CAACN,gBAAwBQ,SACpCvB,OAAOuC,UAAU,CAAC,UAAU,GAAGpC,OAAO,CAAC,EAAEoB,QAAQ,EAAEiB,MAAM,CAACzB,gBAAgB0B,MAAM,CAAC;AAEnF,MAAMX,QAAQ,CAACY,QAAgBb;IAC7B,MAAMc,eAAe3B,OAAOC,IAAI,CAACyB;IACjC,MAAME,iBAAiB5B,OAAOC,IAAI,CAACY;IACnC,OACEc,aAAaE,MAAM,KAAKD,eAAeC,MAAM,IAC7C7C,OAAO8C,eAAe,CAACH,cAAcC;AAEzC;AAEA,MAAMV,YAAY,CAACa;IACjB,IAAI,CAACA,SAAS,OAAOA,UAAU,UAAU;QACvC,OAAO;IACT;IACA,MAAMpC,OAAOoC;IACb,OACE,OAAOpC,KAAKN,cAAc,KAAK,YAC/B2C,QAAQrC,KAAKL,OAAO,KACpB,OAAOK,KAAKL,OAAO,KAAK,YACxB,CAAC2C,MAAMC,OAAO,CAACvC,KAAKL,OAAO,KAC3B,OAAOK,KAAKC,SAAS,KAAK,YAC1BuC,OAAOC,QAAQ,CAACzC,KAAKC,SAAS,KAC9B,OAAOD,KAAKJ,QAAQ,KAAK,YACxBI,CAAAA,KAAKwB,cAAc,KAAK,QAAQ,OAAOxB,KAAKwB,cAAc,KAAK,QAAO,KACtExB,CAAAA,KAAKyB,MAAM,KAAK,QACf,OAAOzB,KAAKyB,MAAM,KAAK,YACtB,OAAOzB,KAAKyB,MAAM,KAAK,YAAYe,OAAOC,QAAQ,CAACzC,KAAKyB,MAAM,CAAC;AAEtE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deleteAssociatedFiles.d.ts","sourceRoot":"","sources":["../../src/uploads/deleteAssociatedFiles.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deleteAssociatedFiles.d.ts","sourceRoot":"","sources":["../../src/uploads/deleteAssociatedFiles.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAA;AAC/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,KAAK,EAAY,UAAU,EAAE,MAAM,YAAY,CAAA;AAKtD,KAAK,IAAI,GAAG;IACV,gBAAgB,EAAE,yBAAyB,CAAA;IAC3C,MAAM,EAAE,eAAe,CAAA;IACvB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC5B,KAAK,CAAC,EAAE,UAAU,EAAE,CAAA;IACpB,cAAc,EAAE,OAAO,CAAA;IACvB,GAAG,EAAE,cAAc,CAAA;CACpB,CAAA;AAuCD,eAAO,MAAM,qBAAqB,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAkC/D,CAAA"}
|
|
@@ -1,17 +1,42 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
2
3
|
import { ErrorDeletingFile } from '../errors/index.js';
|
|
3
4
|
import { fileExists } from './fileExists.js';
|
|
5
|
+
const isPathWithin = (parentPath, targetPath)=>{
|
|
6
|
+
const relativePath = path.relative(parentPath, targetPath);
|
|
7
|
+
return relativePath === '' || !path.isAbsolute(relativePath) && relativePath !== '..' && !relativePath.startsWith(`..${path.sep}`);
|
|
8
|
+
};
|
|
9
|
+
const deleteFile = async ({ filename, staticPath })=>{
|
|
10
|
+
if (!filename || !staticPath) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const resolvedStaticPath = path.resolve(staticPath);
|
|
14
|
+
const filePath = path.resolve(resolvedStaticPath, filename);
|
|
15
|
+
if (!isPathWithin(resolvedStaticPath, filePath)) {
|
|
16
|
+
throw new Error('Invalid filename');
|
|
17
|
+
}
|
|
18
|
+
if (await fileExists(filePath)) {
|
|
19
|
+
const [canonicalParentPath, canonicalStaticPath] = await Promise.all([
|
|
20
|
+
fs.realpath(path.dirname(filePath)),
|
|
21
|
+
fs.realpath(resolvedStaticPath)
|
|
22
|
+
]);
|
|
23
|
+
if (!isPathWithin(canonicalStaticPath, canonicalParentPath)) {
|
|
24
|
+
throw new Error('Invalid filename');
|
|
25
|
+
}
|
|
26
|
+
await fs.unlink(filePath);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
4
29
|
export const deleteAssociatedFiles = async ({ collectionConfig, doc, files = [], overrideDelete, req })=>{
|
|
5
30
|
if (!collectionConfig.upload) {
|
|
6
31
|
return;
|
|
7
32
|
}
|
|
8
33
|
if (overrideDelete || files.length > 0) {
|
|
9
34
|
const { staticDir: staticPath } = collectionConfig.upload;
|
|
10
|
-
const fileToDelete = `${staticPath}/${doc.filename}`;
|
|
11
35
|
try {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
36
|
+
await deleteFile({
|
|
37
|
+
filename: doc.filename,
|
|
38
|
+
staticPath
|
|
39
|
+
});
|
|
15
40
|
} catch (ignore) {
|
|
16
41
|
throw new ErrorDeletingFile(req.t);
|
|
17
42
|
}
|
|
@@ -21,11 +46,11 @@ export const deleteAssociatedFiles = async ({ collectionConfig, doc, files = [],
|
|
|
21
46
|
// happen that two operations will try to delete the same file.
|
|
22
47
|
// To avoid this it is recommended to use "sync" instead
|
|
23
48
|
for (const size of sizes){
|
|
24
|
-
const sizeToDelete = `${staticPath}/${size.filename}`;
|
|
25
49
|
try {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
50
|
+
await deleteFile({
|
|
51
|
+
filename: size.filename,
|
|
52
|
+
staticPath
|
|
53
|
+
});
|
|
29
54
|
} catch (ignore) {
|
|
30
55
|
throw new ErrorDeletingFile(req.t);
|
|
31
56
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/uploads/deleteAssociatedFiles.ts"],"sourcesContent":["import fs from 'fs/promises'\n\nimport type { SanitizedCollectionConfig } from '../collections/config/types.js'\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type { FileData, FileToSave } from './types.js'\n\nimport { ErrorDeletingFile } from '../errors/index.js'\nimport { fileExists } from './fileExists.js'\n\ntype Args = {\n collectionConfig: SanitizedCollectionConfig\n config: SanitizedConfig\n doc: Record<string, unknown>\n files?: FileToSave[]\n overrideDelete: boolean\n req: PayloadRequest\n}\n\nexport const deleteAssociatedFiles: (args: Args) => Promise<void> = async ({\n collectionConfig,\n doc,\n files = [],\n overrideDelete,\n req,\n}) => {\n if (!collectionConfig.upload) {\n return\n }\n if (overrideDelete || files.length > 0) {\n const { staticDir: staticPath } = collectionConfig.upload\n\n
|
|
1
|
+
{"version":3,"sources":["../../src/uploads/deleteAssociatedFiles.ts"],"sourcesContent":["import fs from 'fs/promises'\nimport path from 'path'\n\nimport type { SanitizedCollectionConfig } from '../collections/config/types.js'\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type { FileData, FileToSave } from './types.js'\n\nimport { ErrorDeletingFile } from '../errors/index.js'\nimport { fileExists } from './fileExists.js'\n\ntype Args = {\n collectionConfig: SanitizedCollectionConfig\n config: SanitizedConfig\n doc: Record<string, unknown>\n files?: FileToSave[]\n overrideDelete: boolean\n req: PayloadRequest\n}\n\nconst isPathWithin = (parentPath: string, targetPath: string): boolean => {\n const relativePath = path.relative(parentPath, targetPath)\n\n return (\n relativePath === '' ||\n (!path.isAbsolute(relativePath) &&\n relativePath !== '..' &&\n !relativePath.startsWith(`..${path.sep}`))\n )\n}\n\nconst deleteFile = async ({ filename, staticPath }: { filename?: string; staticPath?: string }) => {\n if (!filename || !staticPath) {\n return\n }\n\n const resolvedStaticPath = path.resolve(staticPath)\n const filePath = path.resolve(resolvedStaticPath, filename)\n\n if (!isPathWithin(resolvedStaticPath, filePath)) {\n throw new Error('Invalid filename')\n }\n\n if (await fileExists(filePath)) {\n const [canonicalParentPath, canonicalStaticPath] = await Promise.all([\n fs.realpath(path.dirname(filePath)),\n fs.realpath(resolvedStaticPath),\n ])\n\n if (!isPathWithin(canonicalStaticPath, canonicalParentPath)) {\n throw new Error('Invalid filename')\n }\n\n await fs.unlink(filePath)\n }\n}\n\nexport const deleteAssociatedFiles: (args: Args) => Promise<void> = async ({\n collectionConfig,\n doc,\n files = [],\n overrideDelete,\n req,\n}) => {\n if (!collectionConfig.upload) {\n return\n }\n if (overrideDelete || files.length > 0) {\n const { staticDir: staticPath } = collectionConfig.upload\n\n try {\n await deleteFile({ filename: doc.filename as string | undefined, staticPath })\n } catch (ignore) {\n throw new ErrorDeletingFile(req.t)\n }\n\n if (doc.sizes) {\n const sizes: FileData[] = Object.values(doc.sizes)\n // Since forEach will not wait until unlink is finished it could\n // happen that two operations will try to delete the same file.\n // To avoid this it is recommended to use \"sync\" instead\n\n for (const size of sizes) {\n try {\n await deleteFile({ filename: size.filename, staticPath })\n } catch (ignore) {\n throw new ErrorDeletingFile(req.t)\n }\n }\n }\n }\n}\n"],"names":["fs","path","ErrorDeletingFile","fileExists","isPathWithin","parentPath","targetPath","relativePath","relative","isAbsolute","startsWith","sep","deleteFile","filename","staticPath","resolvedStaticPath","resolve","filePath","Error","canonicalParentPath","canonicalStaticPath","Promise","all","realpath","dirname","unlink","deleteAssociatedFiles","collectionConfig","doc","files","overrideDelete","req","upload","length","staticDir","ignore","t","sizes","Object","values","size"],"mappings":"AAAA,OAAOA,QAAQ,cAAa;AAC5B,OAAOC,UAAU,OAAM;AAOvB,SAASC,iBAAiB,QAAQ,qBAAoB;AACtD,SAASC,UAAU,QAAQ,kBAAiB;AAW5C,MAAMC,eAAe,CAACC,YAAoBC;IACxC,MAAMC,eAAeN,KAAKO,QAAQ,CAACH,YAAYC;IAE/C,OACEC,iBAAiB,MAChB,CAACN,KAAKQ,UAAU,CAACF,iBAChBA,iBAAiB,QACjB,CAACA,aAAaG,UAAU,CAAC,CAAC,EAAE,EAAET,KAAKU,GAAG,EAAE;AAE9C;AAEA,MAAMC,aAAa,OAAO,EAAEC,QAAQ,EAAEC,UAAU,EAA8C;IAC5F,IAAI,CAACD,YAAY,CAACC,YAAY;QAC5B;IACF;IAEA,MAAMC,qBAAqBd,KAAKe,OAAO,CAACF;IACxC,MAAMG,WAAWhB,KAAKe,OAAO,CAACD,oBAAoBF;IAElD,IAAI,CAACT,aAAaW,oBAAoBE,WAAW;QAC/C,MAAM,IAAIC,MAAM;IAClB;IAEA,IAAI,MAAMf,WAAWc,WAAW;QAC9B,MAAM,CAACE,qBAAqBC,oBAAoB,GAAG,MAAMC,QAAQC,GAAG,CAAC;YACnEtB,GAAGuB,QAAQ,CAACtB,KAAKuB,OAAO,CAACP;YACzBjB,GAAGuB,QAAQ,CAACR;SACb;QAED,IAAI,CAACX,aAAagB,qBAAqBD,sBAAsB;YAC3D,MAAM,IAAID,MAAM;QAClB;QAEA,MAAMlB,GAAGyB,MAAM,CAACR;IAClB;AACF;AAEA,OAAO,MAAMS,wBAAuD,OAAO,EACzEC,gBAAgB,EAChBC,GAAG,EACHC,QAAQ,EAAE,EACVC,cAAc,EACdC,GAAG,EACJ;IACC,IAAI,CAACJ,iBAAiBK,MAAM,EAAE;QAC5B;IACF;IACA,IAAIF,kBAAkBD,MAAMI,MAAM,GAAG,GAAG;QACtC,MAAM,EAAEC,WAAWpB,UAAU,EAAE,GAAGa,iBAAiBK,MAAM;QAEzD,IAAI;YACF,MAAMpB,WAAW;gBAAEC,UAAUe,IAAIf,QAAQ;gBAAwBC;YAAW;QAC9E,EAAE,OAAOqB,QAAQ;YACf,MAAM,IAAIjC,kBAAkB6B,IAAIK,CAAC;QACnC;QAEA,IAAIR,IAAIS,KAAK,EAAE;YACb,MAAMA,QAAoBC,OAAOC,MAAM,CAACX,IAAIS,KAAK;YACjD,gEAAgE;YAChE,+DAA+D;YAC/D,wDAAwD;YAExD,KAAK,MAAMG,QAAQH,MAAO;gBACxB,IAAI;oBACF,MAAMzB,WAAW;wBAAEC,UAAU2B,KAAK3B,QAAQ;wBAAEC;oBAAW;gBACzD,EAAE,OAAOqB,QAAQ;oBACf,MAAM,IAAIjC,kBAAkB6B,IAAIK,CAAC;gBACnC;YACF;QACF;IACF;AACF,EAAC"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { ErrorDeletingFile } from '../errors/index.js';
|
|
6
|
+
import { deleteAssociatedFiles } from './deleteAssociatedFiles.js';
|
|
7
|
+
describe('deleteAssociatedFiles', ()=>{
|
|
8
|
+
let testDir;
|
|
9
|
+
let uploadDir;
|
|
10
|
+
beforeEach(async ()=>{
|
|
11
|
+
testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'payload-upload-delete-'));
|
|
12
|
+
uploadDir = path.join(testDir, 'uploads');
|
|
13
|
+
await fs.mkdir(uploadDir);
|
|
14
|
+
});
|
|
15
|
+
afterEach(async ()=>{
|
|
16
|
+
await fs.rm(testDir, {
|
|
17
|
+
force: true,
|
|
18
|
+
recursive: true
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
it('deletes files from the configured upload directory', async ()=>{
|
|
22
|
+
const filename = 'document.txt';
|
|
23
|
+
const filePath = path.join(uploadDir, filename);
|
|
24
|
+
await fs.writeFile(filePath, 'content');
|
|
25
|
+
await deleteAssociatedFiles({
|
|
26
|
+
collectionConfig: {
|
|
27
|
+
upload: {
|
|
28
|
+
staticDir: uploadDir
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
config: {},
|
|
32
|
+
doc: {
|
|
33
|
+
filename
|
|
34
|
+
},
|
|
35
|
+
overrideDelete: true,
|
|
36
|
+
req: {}
|
|
37
|
+
});
|
|
38
|
+
await expect(fs.access(filePath)).rejects.toThrow();
|
|
39
|
+
});
|
|
40
|
+
it('deletes files from nested directories within the configured upload directory', async ()=>{
|
|
41
|
+
const filename = path.join('tenant', 'document.txt');
|
|
42
|
+
const filePath = path.join(uploadDir, filename);
|
|
43
|
+
await fs.mkdir(path.dirname(filePath));
|
|
44
|
+
await fs.writeFile(filePath, 'content');
|
|
45
|
+
await deleteAssociatedFiles({
|
|
46
|
+
collectionConfig: {
|
|
47
|
+
upload: {
|
|
48
|
+
staticDir: uploadDir
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
config: {},
|
|
52
|
+
doc: {
|
|
53
|
+
filename
|
|
54
|
+
},
|
|
55
|
+
overrideDelete: true,
|
|
56
|
+
req: {}
|
|
57
|
+
});
|
|
58
|
+
await expect(fs.access(filePath)).rejects.toThrow();
|
|
59
|
+
});
|
|
60
|
+
it('rejects filenames outside the configured upload directory', async ()=>{
|
|
61
|
+
const filePath = path.join(testDir, 'document.txt');
|
|
62
|
+
await fs.writeFile(filePath, 'content');
|
|
63
|
+
await expect(deleteAssociatedFiles({
|
|
64
|
+
collectionConfig: {
|
|
65
|
+
upload: {
|
|
66
|
+
staticDir: uploadDir
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
config: {},
|
|
70
|
+
doc: {
|
|
71
|
+
filename: path.relative(uploadDir, filePath)
|
|
72
|
+
},
|
|
73
|
+
overrideDelete: true,
|
|
74
|
+
req: {}
|
|
75
|
+
})).rejects.toBeInstanceOf(ErrorDeletingFile);
|
|
76
|
+
await expect(fs.readFile(filePath, 'utf8')).resolves.toBe('content');
|
|
77
|
+
});
|
|
78
|
+
it('rejects generated size filenames outside the configured upload directory', async ()=>{
|
|
79
|
+
const filePath = path.join(testDir, 'thumbnail.txt');
|
|
80
|
+
await fs.writeFile(filePath, 'content');
|
|
81
|
+
await expect(deleteAssociatedFiles({
|
|
82
|
+
collectionConfig: {
|
|
83
|
+
upload: {
|
|
84
|
+
staticDir: uploadDir
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
config: {},
|
|
88
|
+
doc: {
|
|
89
|
+
filename: 'document.txt',
|
|
90
|
+
sizes: {
|
|
91
|
+
thumbnail: {
|
|
92
|
+
filename: path.relative(uploadDir, filePath)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
overrideDelete: true,
|
|
97
|
+
req: {}
|
|
98
|
+
})).rejects.toBeInstanceOf(ErrorDeletingFile);
|
|
99
|
+
await expect(fs.readFile(filePath, 'utf8')).resolves.toBe('content');
|
|
100
|
+
});
|
|
101
|
+
it('rejects files reached through linked directories outside the configured upload directory', async ()=>{
|
|
102
|
+
const externalDir = path.join(testDir, 'documents');
|
|
103
|
+
const filePath = path.join(externalDir, 'document.txt');
|
|
104
|
+
await fs.mkdir(externalDir);
|
|
105
|
+
await fs.writeFile(filePath, 'content');
|
|
106
|
+
await fs.symlink(externalDir, path.join(uploadDir, 'linked'), 'dir');
|
|
107
|
+
await expect(deleteAssociatedFiles({
|
|
108
|
+
collectionConfig: {
|
|
109
|
+
upload: {
|
|
110
|
+
staticDir: uploadDir
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
config: {},
|
|
114
|
+
doc: {
|
|
115
|
+
filename: path.join('linked', 'document.txt')
|
|
116
|
+
},
|
|
117
|
+
overrideDelete: true,
|
|
118
|
+
req: {}
|
|
119
|
+
})).rejects.toBeInstanceOf(ErrorDeletingFile);
|
|
120
|
+
await expect(fs.readFile(filePath, 'utf8')).resolves.toBe('content');
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
//# sourceMappingURL=deleteAssociatedFiles.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/uploads/deleteAssociatedFiles.spec.ts"],"sourcesContent":["import fs from 'fs/promises'\nimport os from 'os'\nimport path from 'path'\nimport { afterEach, beforeEach, describe, expect, it } from 'vitest'\n\nimport type { SanitizedCollectionConfig } from '../collections/config/types.js'\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\n\nimport { ErrorDeletingFile } from '../errors/index.js'\nimport { deleteAssociatedFiles } from './deleteAssociatedFiles.js'\n\ndescribe('deleteAssociatedFiles', () => {\n let testDir: string\n let uploadDir: string\n\n beforeEach(async () => {\n testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'payload-upload-delete-'))\n uploadDir = path.join(testDir, 'uploads')\n await fs.mkdir(uploadDir)\n })\n\n afterEach(async () => {\n await fs.rm(testDir, { force: true, recursive: true })\n })\n\n it('deletes files from the configured upload directory', async () => {\n const filename = 'document.txt'\n const filePath = path.join(uploadDir, filename)\n await fs.writeFile(filePath, 'content')\n\n await deleteAssociatedFiles({\n collectionConfig: { upload: { staticDir: uploadDir } } as SanitizedCollectionConfig,\n config: {} as SanitizedConfig,\n doc: { filename },\n overrideDelete: true,\n req: {} as PayloadRequest,\n })\n\n await expect(fs.access(filePath)).rejects.toThrow()\n })\n\n it('deletes files from nested directories within the configured upload directory', async () => {\n const filename = path.join('tenant', 'document.txt')\n const filePath = path.join(uploadDir, filename)\n await fs.mkdir(path.dirname(filePath))\n await fs.writeFile(filePath, 'content')\n\n await deleteAssociatedFiles({\n collectionConfig: { upload: { staticDir: uploadDir } } as SanitizedCollectionConfig,\n config: {} as SanitizedConfig,\n doc: { filename },\n overrideDelete: true,\n req: {} as PayloadRequest,\n })\n\n await expect(fs.access(filePath)).rejects.toThrow()\n })\n\n it('rejects filenames outside the configured upload directory', async () => {\n const filePath = path.join(testDir, 'document.txt')\n await fs.writeFile(filePath, 'content')\n\n await expect(\n deleteAssociatedFiles({\n collectionConfig: { upload: { staticDir: uploadDir } } as SanitizedCollectionConfig,\n config: {} as SanitizedConfig,\n doc: { filename: path.relative(uploadDir, filePath) },\n overrideDelete: true,\n req: {} as PayloadRequest,\n }),\n ).rejects.toBeInstanceOf(ErrorDeletingFile)\n\n await expect(fs.readFile(filePath, 'utf8')).resolves.toBe('content')\n })\n\n it('rejects generated size filenames outside the configured upload directory', async () => {\n const filePath = path.join(testDir, 'thumbnail.txt')\n await fs.writeFile(filePath, 'content')\n\n await expect(\n deleteAssociatedFiles({\n collectionConfig: { upload: { staticDir: uploadDir } } as SanitizedCollectionConfig,\n config: {} as SanitizedConfig,\n doc: {\n filename: 'document.txt',\n sizes: { thumbnail: { filename: path.relative(uploadDir, filePath) } },\n },\n overrideDelete: true,\n req: {} as PayloadRequest,\n }),\n ).rejects.toBeInstanceOf(ErrorDeletingFile)\n\n await expect(fs.readFile(filePath, 'utf8')).resolves.toBe('content')\n })\n\n it('rejects files reached through linked directories outside the configured upload directory', async () => {\n const externalDir = path.join(testDir, 'documents')\n const filePath = path.join(externalDir, 'document.txt')\n await fs.mkdir(externalDir)\n await fs.writeFile(filePath, 'content')\n await fs.symlink(externalDir, path.join(uploadDir, 'linked'), 'dir')\n\n await expect(\n deleteAssociatedFiles({\n collectionConfig: { upload: { staticDir: uploadDir } } as SanitizedCollectionConfig,\n config: {} as SanitizedConfig,\n doc: { filename: path.join('linked', 'document.txt') },\n overrideDelete: true,\n req: {} as PayloadRequest,\n }),\n ).rejects.toBeInstanceOf(ErrorDeletingFile)\n\n await expect(fs.readFile(filePath, 'utf8')).resolves.toBe('content')\n })\n})\n"],"names":["fs","os","path","afterEach","beforeEach","describe","expect","it","ErrorDeletingFile","deleteAssociatedFiles","testDir","uploadDir","mkdtemp","join","tmpdir","mkdir","rm","force","recursive","filename","filePath","writeFile","collectionConfig","upload","staticDir","config","doc","overrideDelete","req","access","rejects","toThrow","dirname","relative","toBeInstanceOf","readFile","resolves","toBe","sizes","thumbnail","externalDir","symlink"],"mappings":"AAAA,OAAOA,QAAQ,cAAa;AAC5B,OAAOC,QAAQ,KAAI;AACnB,OAAOC,UAAU,OAAM;AACvB,SAASC,SAAS,EAAEC,UAAU,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAMpE,SAASC,iBAAiB,QAAQ,qBAAoB;AACtD,SAASC,qBAAqB,QAAQ,6BAA4B;AAElEJ,SAAS,yBAAyB;IAChC,IAAIK;IACJ,IAAIC;IAEJP,WAAW;QACTM,UAAU,MAAMV,GAAGY,OAAO,CAACV,KAAKW,IAAI,CAACZ,GAAGa,MAAM,IAAI;QAClDH,YAAYT,KAAKW,IAAI,CAACH,SAAS;QAC/B,MAAMV,GAAGe,KAAK,CAACJ;IACjB;IAEAR,UAAU;QACR,MAAMH,GAAGgB,EAAE,CAACN,SAAS;YAAEO,OAAO;YAAMC,WAAW;QAAK;IACtD;IAEAX,GAAG,sDAAsD;QACvD,MAAMY,WAAW;QACjB,MAAMC,WAAWlB,KAAKW,IAAI,CAACF,WAAWQ;QACtC,MAAMnB,GAAGqB,SAAS,CAACD,UAAU;QAE7B,MAAMX,sBAAsB;YAC1Ba,kBAAkB;gBAAEC,QAAQ;oBAAEC,WAAWb;gBAAU;YAAE;YACrDc,QAAQ,CAAC;YACTC,KAAK;gBAAEP;YAAS;YAChBQ,gBAAgB;YAChBC,KAAK,CAAC;QACR;QAEA,MAAMtB,OAAON,GAAG6B,MAAM,CAACT,WAAWU,OAAO,CAACC,OAAO;IACnD;IAEAxB,GAAG,gFAAgF;QACjF,MAAMY,WAAWjB,KAAKW,IAAI,CAAC,UAAU;QACrC,MAAMO,WAAWlB,KAAKW,IAAI,CAACF,WAAWQ;QACtC,MAAMnB,GAAGe,KAAK,CAACb,KAAK8B,OAAO,CAACZ;QAC5B,MAAMpB,GAAGqB,SAAS,CAACD,UAAU;QAE7B,MAAMX,sBAAsB;YAC1Ba,kBAAkB;gBAAEC,QAAQ;oBAAEC,WAAWb;gBAAU;YAAE;YACrDc,QAAQ,CAAC;YACTC,KAAK;gBAAEP;YAAS;YAChBQ,gBAAgB;YAChBC,KAAK,CAAC;QACR;QAEA,MAAMtB,OAAON,GAAG6B,MAAM,CAACT,WAAWU,OAAO,CAACC,OAAO;IACnD;IAEAxB,GAAG,6DAA6D;QAC9D,MAAMa,WAAWlB,KAAKW,IAAI,CAACH,SAAS;QACpC,MAAMV,GAAGqB,SAAS,CAACD,UAAU;QAE7B,MAAMd,OACJG,sBAAsB;YACpBa,kBAAkB;gBAAEC,QAAQ;oBAAEC,WAAWb;gBAAU;YAAE;YACrDc,QAAQ,CAAC;YACTC,KAAK;gBAAEP,UAAUjB,KAAK+B,QAAQ,CAACtB,WAAWS;YAAU;YACpDO,gBAAgB;YAChBC,KAAK,CAAC;QACR,IACAE,OAAO,CAACI,cAAc,CAAC1B;QAEzB,MAAMF,OAAON,GAAGmC,QAAQ,CAACf,UAAU,SAASgB,QAAQ,CAACC,IAAI,CAAC;IAC5D;IAEA9B,GAAG,4EAA4E;QAC7E,MAAMa,WAAWlB,KAAKW,IAAI,CAACH,SAAS;QACpC,MAAMV,GAAGqB,SAAS,CAACD,UAAU;QAE7B,MAAMd,OACJG,sBAAsB;YACpBa,kBAAkB;gBAAEC,QAAQ;oBAAEC,WAAWb;gBAAU;YAAE;YACrDc,QAAQ,CAAC;YACTC,KAAK;gBACHP,UAAU;gBACVmB,OAAO;oBAAEC,WAAW;wBAAEpB,UAAUjB,KAAK+B,QAAQ,CAACtB,WAAWS;oBAAU;gBAAE;YACvE;YACAO,gBAAgB;YAChBC,KAAK,CAAC;QACR,IACAE,OAAO,CAACI,cAAc,CAAC1B;QAEzB,MAAMF,OAAON,GAAGmC,QAAQ,CAACf,UAAU,SAASgB,QAAQ,CAACC,IAAI,CAAC;IAC5D;IAEA9B,GAAG,4FAA4F;QAC7F,MAAMiC,cAActC,KAAKW,IAAI,CAACH,SAAS;QACvC,MAAMU,WAAWlB,KAAKW,IAAI,CAAC2B,aAAa;QACxC,MAAMxC,GAAGe,KAAK,CAACyB;QACf,MAAMxC,GAAGqB,SAAS,CAACD,UAAU;QAC7B,MAAMpB,GAAGyC,OAAO,CAACD,aAAatC,KAAKW,IAAI,CAACF,WAAW,WAAW;QAE9D,MAAML,OACJG,sBAAsB;YACpBa,kBAAkB;gBAAEC,QAAQ;oBAAEC,WAAWb;gBAAU;YAAE;YACrDc,QAAQ,CAAC;YACTC,KAAK;gBAAEP,UAAUjB,KAAKW,IAAI,CAAC,UAAU;YAAgB;YACrDc,gBAAgB;YAChBC,KAAK,CAAC;QACR,IACAE,OAAO,CAACI,cAAc,CAAC1B;QAEzB,MAAMF,OAAON,GAAGmC,QAAQ,CAACf,UAAU,SAASgB,QAAQ,CAACC,IAAI,CAAC;IAC5D;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detectSvgFromXml.d.ts","sourceRoot":"","sources":["../../src/uploads/detectSvgFromXml.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"detectSvgFromXml.d.ts","sourceRoot":"","sources":["../../src/uploads/detectSvgFromXml.ts"],"names":[],"mappings":"AAEA,uEAAuE;AACvE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAExD"}
|
|
@@ -1,43 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
try {
|
|
5
|
-
// Limit buffer size to prevent processing large malicious files
|
|
6
|
-
const maxSize = 2048;
|
|
7
|
-
const content = buffer.toString('utf8', 0, Math.min(buffer.length, maxSize));
|
|
8
|
-
// Check for XML declaration and extract encoding if present
|
|
9
|
-
const xmlDeclMatch = content.match(/^<\?xml[^>]*encoding=["']([^"']+)["']/i);
|
|
10
|
-
const declaredEncoding = xmlDeclMatch?.[1]?.toLowerCase();
|
|
11
|
-
// Only support safe encodings
|
|
12
|
-
if (declaredEncoding && ![
|
|
13
|
-
'ascii',
|
|
14
|
-
'utf-8',
|
|
15
|
-
'utf8'
|
|
16
|
-
].includes(declaredEncoding)) {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
// Remove XML declarations, comments, and processing instructions
|
|
20
|
-
const cleanContent = content.replace(/<\?xml[^>]*\?>/gi, '').replace(/<!--[\s\S]*?-->/g, '').replace(/<\?[^>]*\?>/g, '').trim();
|
|
21
|
-
// Find the first actual element (root element)
|
|
22
|
-
const rootElementMatch = cleanContent.match(/^<(\w+)(?:\s|>)/);
|
|
23
|
-
if (!rootElementMatch || rootElementMatch[1] !== 'svg') {
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
// Validate SVG namespace - must be present for valid SVG
|
|
27
|
-
const svgNamespaceRegex = /xmlns=["']http:\/\/www\.w3\.org\/2000\/svg["']/;
|
|
28
|
-
if (!svgNamespaceRegex.test(content)) {
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
// Additional validation: ensure it's not malformed
|
|
32
|
-
const svgOpenTag = content.match(/<svg[\s>]/);
|
|
33
|
-
if (!svgOpenTag) {
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
return true;
|
|
37
|
-
} catch (_error) {
|
|
38
|
-
// If any error occurs during parsing, treat as not SVG
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
1
|
+
import { inspectSvg } from './validateSvg.js';
|
|
2
|
+
/** Detect whether an XML document's root element is namespaced SVG. */ export function detectSvgFromXml(buffer) {
|
|
3
|
+
return inspectSvg(buffer).isSvg;
|
|
41
4
|
}
|
|
42
5
|
|
|
43
6
|
//# sourceMappingURL=detectSvgFromXml.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/uploads/detectSvgFromXml.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../src/uploads/detectSvgFromXml.ts"],"sourcesContent":["import { inspectSvg } from './validateSvg.js'\n\n/** Detect whether an XML document's root element is namespaced SVG. */\nexport function detectSvgFromXml(buffer: Buffer): boolean {\n return inspectSvg(buffer).isSvg\n}\n"],"names":["inspectSvg","detectSvgFromXml","buffer","isSvg"],"mappings":"AAAA,SAASA,UAAU,QAAQ,mBAAkB;AAE7C,qEAAqE,GACrE,OAAO,SAASC,iBAAiBC,MAAc;IAC7C,OAAOF,WAAWE,QAAQC,KAAK;AACjC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getFile.d.ts","sourceRoot":"","sources":["../../../src/uploads/endpoints/getFile.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"getFile.d.ts","sourceRoot":"","sources":["../../../src/uploads/endpoints/getFile.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAY3D,eAAO,MAAM,cAAc,EAAE,cAgK5B,CAAA"}
|
|
@@ -6,7 +6,9 @@ import { APIError } from '../../errors/APIError.js';
|
|
|
6
6
|
import { checkFileAccess } from '../../uploads/checkFileAccess.js';
|
|
7
7
|
import { streamFile } from '../../uploads/fetchAPI-stream-file/index.js';
|
|
8
8
|
import { getFileTypeFallback } from '../../uploads/getFileTypeFallback.js';
|
|
9
|
+
import { getFileExtension, isXmlMimeType } from '../../uploads/getFileTypeIdentity.js';
|
|
9
10
|
import { parseRangeHeader } from '../../uploads/parseRangeHeader.js';
|
|
11
|
+
import { UPLOAD_CONTENT_SECURITY_POLICY } from '../../uploads/uploadContentSecurityPolicy.js';
|
|
10
12
|
import { getRequestCollection } from '../../utilities/getRequestEntity.js';
|
|
11
13
|
import { headersWithCors } from '../../utilities/headersWithCors.js';
|
|
12
14
|
export const getFileHandler = async (req)=>{
|
|
@@ -80,7 +82,7 @@ export const getFileHandler = async (req)=>{
|
|
|
80
82
|
}
|
|
81
83
|
const fileTypeResult = await fileTypeFromFile(filePath) || getFileTypeFallback(filePath);
|
|
82
84
|
let mimeType = fileTypeResult.mime;
|
|
83
|
-
if (filePath.
|
|
85
|
+
if (getFileExtension(filePath).toLowerCase() === 'svg' && fileTypeResult.mime === 'application/xml') {
|
|
84
86
|
mimeType = 'image/svg+xml';
|
|
85
87
|
}
|
|
86
88
|
// Parse Range header for byte range requests
|
|
@@ -106,8 +108,8 @@ export const getFileHandler = async (req)=>{
|
|
|
106
108
|
let headers = new Headers();
|
|
107
109
|
headers.set('Content-Type', mimeType);
|
|
108
110
|
headers.set('Accept-Ranges', 'bytes');
|
|
109
|
-
if (mimeType
|
|
110
|
-
headers.set('Content-Security-Policy',
|
|
111
|
+
if (isXmlMimeType(mimeType)) {
|
|
112
|
+
headers.set('Content-Security-Policy', UPLOAD_CONTENT_SECURITY_POLICY);
|
|
111
113
|
}
|
|
112
114
|
let data;
|
|
113
115
|
let status;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/uploads/endpoints/getFile.ts"],"sourcesContent":["import type { Stats } from 'fs'\n\nimport { fileTypeFromFile } from 'file-type'\nimport fsPromises from 'fs/promises'\nimport { status as httpStatus } from 'http-status'\nimport path from 'path'\n\nimport type { PayloadHandler } from '../../config/types.js'\n\nimport { APIError } from '../../errors/APIError.js'\nimport { checkFileAccess } from '../../uploads/checkFileAccess.js'\nimport { streamFile } from '../../uploads/fetchAPI-stream-file/index.js'\nimport { getFileTypeFallback } from '../../uploads/getFileTypeFallback.js'\nimport { parseRangeHeader } from '../../uploads/parseRangeHeader.js'\nimport { getRequestCollection } from '../../utilities/getRequestEntity.js'\nimport { headersWithCors } from '../../utilities/headersWithCors.js'\n\nexport const getFileHandler: PayloadHandler = async (req) => {\n const collection = getRequestCollection(req)\n\n const filename = req.routeParams?.filename as string\n const prefix = req.searchParams?.get('prefix') ?? undefined\n\n if (!collection.config.upload) {\n throw new APIError(\n `This collection is not an upload collection: ${collection.config.slug}`,\n httpStatus.BAD_REQUEST,\n )\n }\n\n const accessResult = (await checkFileAccess({\n collection,\n filename,\n prefix,\n req,\n }))!\n\n if (accessResult instanceof Response) {\n return accessResult\n }\n\n if (collection.config.upload.handlers?.length) {\n let customResponse: null | Response | void = null\n const headers = new Headers()\n\n for (const handler of collection.config.upload.handlers) {\n customResponse = await handler(req, {\n doc: accessResult,\n headers,\n params: {\n collection: collection.config.slug,\n filename,\n prefix,\n },\n })\n if (customResponse && customResponse instanceof Response) {\n break\n }\n }\n\n if (customResponse instanceof Response) {\n return customResponse\n }\n }\n\n // Local filesystem fallback — cloud storage handlers return a Response above\n // and have their own filename validation via sanitizeFilename.\n const fileDir = collection.config.upload?.staticDir || collection.config.slug\n const resolvedDir = path.resolve(fileDir)\n const filePath = path.resolve(resolvedDir, filename)\n\n if (!filePath.startsWith(resolvedDir + path.sep)) {\n throw new APIError('Invalid filename.', httpStatus.BAD_REQUEST)\n }\n\n let stats: Stats\n\n try {\n stats = await fsPromises.stat(filePath)\n } catch (err) {\n if ((err as { code?: string }).code === 'ENOENT') {\n req.payload.logger.error(\n `File ${filename} for collection ${collection.config.slug} is missing on the disk. Expected path: ${filePath}`,\n )\n\n // Omit going to the routeError handler by returning response instead of\n // throwing an error to cut down log noise. The response still matches what you get with APIError to not leak details to the user.\n return Response.json(\n {\n errors: [\n {\n message: 'Something went wrong.',\n },\n ],\n },\n {\n headers: headersWithCors({\n headers: new Headers(),\n req,\n }),\n status: 500,\n },\n )\n }\n\n throw err\n }\n\n const fileTypeResult = (await fileTypeFromFile(filePath)) || getFileTypeFallback(filePath)\n let mimeType = fileTypeResult.mime\n\n if (filePath.endsWith('.svg') && fileTypeResult.mime === 'application/xml') {\n mimeType = 'image/svg+xml'\n }\n\n // Parse Range header for byte range requests\n const rangeHeader = req.headers.get('range')\n const rangeResult = parseRangeHeader({\n fileSize: stats.size,\n rangeHeader,\n })\n\n if (rangeResult.type === 'invalid') {\n let headers = new Headers()\n headers.set('Content-Range', `bytes */${stats.size}`)\n headers = collection.config.upload?.modifyResponseHeaders\n ? collection.config.upload.modifyResponseHeaders({ headers }) || headers\n : headers\n\n return new Response(null, {\n headers: headersWithCors({\n headers,\n req,\n }),\n status: httpStatus.REQUESTED_RANGE_NOT_SATISFIABLE,\n })\n }\n\n let headers = new Headers()\n headers.set('Content-Type', mimeType)\n headers.set('Accept-Ranges', 'bytes')\n\n if (mimeType === 'image/svg+xml') {\n headers.set('Content-Security-Policy', \"script-src 'none'\")\n }\n\n let data: ReadableStream\n let status: number\n const isPartial = rangeResult.type === 'partial'\n const range = rangeResult.range\n\n if (isPartial && range) {\n const contentLength = range.end - range.start + 1\n headers.set('Content-Length', String(contentLength))\n headers.set('Content-Range', `bytes ${range.start}-${range.end}/${stats.size}`)\n data = streamFile({ filePath, options: { end: range.end, start: range.start } })\n status = httpStatus.PARTIAL_CONTENT\n } else {\n headers.set('Content-Length', String(stats.size))\n data = streamFile({ filePath })\n status = httpStatus.OK\n }\n\n headers = collection.config.upload?.modifyResponseHeaders\n ? collection.config.upload.modifyResponseHeaders({ headers }) || headers\n : headers\n\n return new Response(data, {\n headers: headersWithCors({\n headers,\n req,\n }),\n status,\n })\n}\n"],"names":["fileTypeFromFile","fsPromises","status","httpStatus","path","APIError","checkFileAccess","streamFile","getFileTypeFallback","parseRangeHeader","getRequestCollection","headersWithCors","getFileHandler","req","collection","filename","routeParams","prefix","searchParams","get","undefined","config","upload","slug","BAD_REQUEST","accessResult","Response","handlers","length","customResponse","headers","Headers","handler","doc","params","fileDir","staticDir","resolvedDir","resolve","filePath","startsWith","sep","stats","stat","err","code","payload","logger","error","json","errors","message","fileTypeResult","mimeType","mime","endsWith","rangeHeader","rangeResult","fileSize","size","type","set","modifyResponseHeaders","REQUESTED_RANGE_NOT_SATISFIABLE","data","isPartial","range","contentLength","end","start","String","options","PARTIAL_CONTENT","OK"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/uploads/endpoints/getFile.ts"],"sourcesContent":["import type { Stats } from 'fs'\n\nimport { fileTypeFromFile } from 'file-type'\nimport fsPromises from 'fs/promises'\nimport { status as httpStatus } from 'http-status'\nimport path from 'path'\n\nimport type { PayloadHandler } from '../../config/types.js'\n\nimport { APIError } from '../../errors/APIError.js'\nimport { checkFileAccess } from '../../uploads/checkFileAccess.js'\nimport { streamFile } from '../../uploads/fetchAPI-stream-file/index.js'\nimport { getFileTypeFallback } from '../../uploads/getFileTypeFallback.js'\nimport { getFileExtension, isXmlMimeType } from '../../uploads/getFileTypeIdentity.js'\nimport { parseRangeHeader } from '../../uploads/parseRangeHeader.js'\nimport { UPLOAD_CONTENT_SECURITY_POLICY } from '../../uploads/uploadContentSecurityPolicy.js'\nimport { getRequestCollection } from '../../utilities/getRequestEntity.js'\nimport { headersWithCors } from '../../utilities/headersWithCors.js'\n\nexport const getFileHandler: PayloadHandler = async (req) => {\n const collection = getRequestCollection(req)\n\n const filename = req.routeParams?.filename as string\n const prefix = req.searchParams?.get('prefix') ?? undefined\n\n if (!collection.config.upload) {\n throw new APIError(\n `This collection is not an upload collection: ${collection.config.slug}`,\n httpStatus.BAD_REQUEST,\n )\n }\n\n const accessResult = (await checkFileAccess({\n collection,\n filename,\n prefix,\n req,\n }))!\n\n if (accessResult instanceof Response) {\n return accessResult\n }\n\n if (collection.config.upload.handlers?.length) {\n let customResponse: null | Response | void = null\n const headers = new Headers()\n\n for (const handler of collection.config.upload.handlers) {\n customResponse = await handler(req, {\n doc: accessResult,\n headers,\n params: {\n collection: collection.config.slug,\n filename,\n prefix,\n },\n })\n if (customResponse && customResponse instanceof Response) {\n break\n }\n }\n\n if (customResponse instanceof Response) {\n return customResponse\n }\n }\n\n // Local filesystem fallback — cloud storage handlers return a Response above\n // and have their own filename validation via sanitizeFilename.\n const fileDir = collection.config.upload?.staticDir || collection.config.slug\n const resolvedDir = path.resolve(fileDir)\n const filePath = path.resolve(resolvedDir, filename)\n\n if (!filePath.startsWith(resolvedDir + path.sep)) {\n throw new APIError('Invalid filename.', httpStatus.BAD_REQUEST)\n }\n\n let stats: Stats\n\n try {\n stats = await fsPromises.stat(filePath)\n } catch (err) {\n if ((err as { code?: string }).code === 'ENOENT') {\n req.payload.logger.error(\n `File ${filename} for collection ${collection.config.slug} is missing on the disk. Expected path: ${filePath}`,\n )\n\n // Omit going to the routeError handler by returning response instead of\n // throwing an error to cut down log noise. The response still matches what you get with APIError to not leak details to the user.\n return Response.json(\n {\n errors: [\n {\n message: 'Something went wrong.',\n },\n ],\n },\n {\n headers: headersWithCors({\n headers: new Headers(),\n req,\n }),\n status: 500,\n },\n )\n }\n\n throw err\n }\n\n const fileTypeResult = (await fileTypeFromFile(filePath)) || getFileTypeFallback(filePath)\n let mimeType = fileTypeResult.mime\n\n if (\n getFileExtension(filePath).toLowerCase() === 'svg' &&\n fileTypeResult.mime === 'application/xml'\n ) {\n mimeType = 'image/svg+xml'\n }\n\n // Parse Range header for byte range requests\n const rangeHeader = req.headers.get('range')\n const rangeResult = parseRangeHeader({\n fileSize: stats.size,\n rangeHeader,\n })\n\n if (rangeResult.type === 'invalid') {\n let headers = new Headers()\n headers.set('Content-Range', `bytes */${stats.size}`)\n headers = collection.config.upload?.modifyResponseHeaders\n ? collection.config.upload.modifyResponseHeaders({ headers }) || headers\n : headers\n\n return new Response(null, {\n headers: headersWithCors({\n headers,\n req,\n }),\n status: httpStatus.REQUESTED_RANGE_NOT_SATISFIABLE,\n })\n }\n\n let headers = new Headers()\n headers.set('Content-Type', mimeType)\n headers.set('Accept-Ranges', 'bytes')\n\n if (isXmlMimeType(mimeType)) {\n headers.set('Content-Security-Policy', UPLOAD_CONTENT_SECURITY_POLICY)\n }\n\n let data: ReadableStream\n let status: number\n const isPartial = rangeResult.type === 'partial'\n const range = rangeResult.range\n\n if (isPartial && range) {\n const contentLength = range.end - range.start + 1\n headers.set('Content-Length', String(contentLength))\n headers.set('Content-Range', `bytes ${range.start}-${range.end}/${stats.size}`)\n data = streamFile({ filePath, options: { end: range.end, start: range.start } })\n status = httpStatus.PARTIAL_CONTENT\n } else {\n headers.set('Content-Length', String(stats.size))\n data = streamFile({ filePath })\n status = httpStatus.OK\n }\n\n headers = collection.config.upload?.modifyResponseHeaders\n ? collection.config.upload.modifyResponseHeaders({ headers }) || headers\n : headers\n\n return new Response(data, {\n headers: headersWithCors({\n headers,\n req,\n }),\n status,\n })\n}\n"],"names":["fileTypeFromFile","fsPromises","status","httpStatus","path","APIError","checkFileAccess","streamFile","getFileTypeFallback","getFileExtension","isXmlMimeType","parseRangeHeader","UPLOAD_CONTENT_SECURITY_POLICY","getRequestCollection","headersWithCors","getFileHandler","req","collection","filename","routeParams","prefix","searchParams","get","undefined","config","upload","slug","BAD_REQUEST","accessResult","Response","handlers","length","customResponse","headers","Headers","handler","doc","params","fileDir","staticDir","resolvedDir","resolve","filePath","startsWith","sep","stats","stat","err","code","payload","logger","error","json","errors","message","fileTypeResult","mimeType","mime","toLowerCase","rangeHeader","rangeResult","fileSize","size","type","set","modifyResponseHeaders","REQUESTED_RANGE_NOT_SATISFIABLE","data","isPartial","range","contentLength","end","start","String","options","PARTIAL_CONTENT","OK"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { FetchAPIFileUploadOptions } from '../../config/types.js';
|
|
2
2
|
type Handler = (options: FetchAPIFileUploadOptions, fieldname: string, filename: string) => {
|
|
3
|
-
cleanup: () => void;
|
|
3
|
+
cleanup: () => Promise<void> | void;
|
|
4
4
|
complete: () => Buffer;
|
|
5
|
-
dataHandler: (data: Buffer) => void;
|
|
5
|
+
dataHandler: (data: Buffer) => Promise<void> | void;
|
|
6
6
|
getFilePath: () => string;
|
|
7
7
|
getFileSize: () => number;
|
|
8
8
|
getHash: () => string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/uploads/fetchAPI-multipart/handlers.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAA;AAItE,KAAK,OAAO,GAAG,CACb,OAAO,EAAE,yBAAyB,EAClC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,KACb;IACH,OAAO,EAAE,MAAM,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/uploads/fetchAPI-multipart/handlers.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAA;AAItE,KAAK,OAAO,GAAG,CACb,OAAO,EAAE,yBAAyB,EAClC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,KACb;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACnC,QAAQ,EAAE,MAAM,MAAM,CAAA;IACtB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACnD,WAAW,EAAE,MAAM,MAAM,CAAA;IACzB,WAAW,EAAE,MAAM,MAAM,CAAA;IACzB,OAAO,EAAE,MAAM,MAAM,CAAA;IACrB,eAAe,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;CACxC,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,OA6D7B,CAAA;AAED,eAAO,MAAM,UAAU,EAAE,OAmCxB,CAAA"}
|
|
@@ -15,6 +15,7 @@ export const tempFileHandler = (options, fieldname, filename)=>{
|
|
|
15
15
|
const writeStream = fs.createWriteStream(tempFilePath);
|
|
16
16
|
const writePromise = new Promise((resolve, reject)=>{
|
|
17
17
|
writeStream.on('finish', ()=>resolve(true));
|
|
18
|
+
writeStream.on('close', ()=>resolve(false));
|
|
18
19
|
writeStream.on('error', (err)=>{
|
|
19
20
|
debugLog(options, `Error write temp file: ${err}`);
|
|
20
21
|
reject(err);
|
|
@@ -23,9 +24,15 @@ export const tempFileHandler = (options, fieldname, filename)=>{
|
|
|
23
24
|
return {
|
|
24
25
|
cleanup: ()=>{
|
|
25
26
|
completed = true;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
return new Promise((resolve)=>{
|
|
28
|
+
const remove = ()=>deleteFile(tempFilePath, ()=>resolve());
|
|
29
|
+
if (writeStream.closed) {
|
|
30
|
+
remove();
|
|
31
|
+
} else {
|
|
32
|
+
writeStream.once('close', remove);
|
|
33
|
+
writeStream.destroy();
|
|
34
|
+
}
|
|
35
|
+
});
|
|
29
36
|
},
|
|
30
37
|
complete: ()=>{
|
|
31
38
|
completed = true;
|
|
@@ -41,10 +48,13 @@ export const tempFileHandler = (options, fieldname, filename)=>{
|
|
|
41
48
|
debugLog(options, `Error: got ${fieldname}->${filename} data chunk for completed upload!`);
|
|
42
49
|
return;
|
|
43
50
|
}
|
|
44
|
-
writeStream.write(data);
|
|
51
|
+
const ready = writeStream.write(data);
|
|
45
52
|
hash.update(data);
|
|
46
53
|
fileSize += data.length;
|
|
47
54
|
debugLog(options, `Uploading ${fieldname}->${filename}, bytes:${fileSize}...`);
|
|
55
|
+
if (!ready) {
|
|
56
|
+
return new Promise((resolve)=>writeStream.once('drain', resolve));
|
|
57
|
+
}
|
|
48
58
|
},
|
|
49
59
|
getFilePath: ()=>tempFilePath,
|
|
50
60
|
getFileSize: ()=>fileSize,
|
|
@@ -61,11 +71,14 @@ export const memHandler = (options, fieldname, filename)=>{
|
|
|
61
71
|
return {
|
|
62
72
|
cleanup: ()=>{
|
|
63
73
|
completed = true;
|
|
74
|
+
buffers.length = 0;
|
|
64
75
|
},
|
|
65
76
|
complete: ()=>{
|
|
66
77
|
debugLog(options, `Upload ${fieldname}->${filename} completed, bytes:${fileSize}.`);
|
|
67
78
|
completed = true;
|
|
68
|
-
|
|
79
|
+
const buffer = getBuffer();
|
|
80
|
+
buffers.length = 0;
|
|
81
|
+
return buffer;
|
|
69
82
|
},
|
|
70
83
|
dataHandler: (data)=>{
|
|
71
84
|
if (completed === true) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/uploads/fetchAPI-multipart/handlers.ts"],"sourcesContent":["import crypto from 'crypto'\nimport fs, { WriteStream } from 'fs'\nimport path from 'path'\n\nimport type { FetchAPIFileUploadOptions } from '../../config/types.js'\n\nimport { checkAndMakeDir, debugLog, deleteFile, getTempFilename } from './utilities.js'\n\ntype Handler = (\n options: FetchAPIFileUploadOptions,\n fieldname: string,\n filename: string,\n) => {\n cleanup: () => void\n complete: () => Buffer\n dataHandler: (data: Buffer) => void\n getFilePath: () => string\n getFileSize: () => number\n getHash: () => string\n getWritePromise: () => Promise<boolean>\n}\n\nexport const tempFileHandler: Handler = (options, fieldname, filename) => {\n const tempFilePath = path.resolve(options.tempFileDir!, getTempFilename())\n checkAndMakeDir({ createParentPath: true }, tempFilePath)\n\n debugLog(options, `Temporary file path is ${tempFilePath}`)\n\n const hash = crypto.createHash('md5')\n let fileSize = 0\n let completed = false\n\n debugLog(options, `Opening write stream for ${fieldname}->${filename}...`)\n const writeStream = fs.createWriteStream(tempFilePath)\n const writePromise = new Promise<boolean>((resolve, reject) => {\n writeStream.on('finish', () => resolve(true))\n writeStream.on('error', (err) => {\n debugLog(options, `Error write temp file: ${err}`)\n reject(err)\n })\n })\n\n return {\n cleanup: () => {\n completed = true\n
|
|
1
|
+
{"version":3,"sources":["../../../src/uploads/fetchAPI-multipart/handlers.ts"],"sourcesContent":["import crypto from 'crypto'\nimport fs, { WriteStream } from 'fs'\nimport path from 'path'\n\nimport type { FetchAPIFileUploadOptions } from '../../config/types.js'\n\nimport { checkAndMakeDir, debugLog, deleteFile, getTempFilename } from './utilities.js'\n\ntype Handler = (\n options: FetchAPIFileUploadOptions,\n fieldname: string,\n filename: string,\n) => {\n cleanup: () => Promise<void> | void\n complete: () => Buffer\n dataHandler: (data: Buffer) => Promise<void> | void\n getFilePath: () => string\n getFileSize: () => number\n getHash: () => string\n getWritePromise: () => Promise<boolean>\n}\n\nexport const tempFileHandler: Handler = (options, fieldname, filename) => {\n const tempFilePath = path.resolve(options.tempFileDir!, getTempFilename())\n checkAndMakeDir({ createParentPath: true }, tempFilePath)\n\n debugLog(options, `Temporary file path is ${tempFilePath}`)\n\n const hash = crypto.createHash('md5')\n let fileSize = 0\n let completed = false\n\n debugLog(options, `Opening write stream for ${fieldname}->${filename}...`)\n const writeStream = fs.createWriteStream(tempFilePath)\n const writePromise = new Promise<boolean>((resolve, reject) => {\n writeStream.on('finish', () => resolve(true))\n writeStream.on('close', () => resolve(false))\n writeStream.on('error', (err) => {\n debugLog(options, `Error write temp file: ${err}`)\n reject(err)\n })\n })\n\n return {\n cleanup: () => {\n completed = true\n return new Promise<void>((resolve) => {\n const remove = () => deleteFile(tempFilePath, () => resolve())\n if (writeStream.closed) {\n remove()\n } else {\n writeStream.once('close', remove)\n writeStream.destroy()\n }\n })\n },\n complete: () => {\n completed = true\n debugLog(options, `Upload ${fieldname}->${filename} completed, bytes:${fileSize}.`)\n if (writeStream instanceof WriteStream) {\n writeStream.end()\n }\n // Return empty buff since data was uploaded into a temp file.\n return Buffer.concat([])\n },\n dataHandler: (data) => {\n if (completed === true) {\n debugLog(options, `Error: got ${fieldname}->${filename} data chunk for completed upload!`)\n return\n }\n const ready = writeStream.write(data)\n hash.update(data)\n fileSize += data.length\n debugLog(options, `Uploading ${fieldname}->${filename}, bytes:${fileSize}...`)\n if (!ready) {\n return new Promise<void>((resolve) => writeStream.once('drain', resolve))\n }\n },\n getFilePath: () => tempFilePath,\n getFileSize: () => fileSize,\n getHash: () => hash.digest('hex'),\n getWritePromise: () => writePromise,\n }\n}\n\nexport const memHandler: Handler = (options, fieldname, filename) => {\n const buffers: Buffer[] = []\n const hash = crypto.createHash('md5')\n let fileSize = 0\n let completed = false\n\n const getBuffer = () => Buffer.concat(buffers, fileSize)\n\n return {\n cleanup: () => {\n completed = true\n buffers.length = 0\n },\n complete: () => {\n debugLog(options, `Upload ${fieldname}->${filename} completed, bytes:${fileSize}.`)\n completed = true\n const buffer = getBuffer()\n buffers.length = 0\n return buffer\n },\n dataHandler: (data) => {\n if (completed === true) {\n debugLog(options, `Error: got ${fieldname}->${filename} data chunk for completed upload!`)\n return\n }\n buffers.push(data)\n hash.update(data)\n fileSize += data.length\n debugLog(options, `Uploading ${fieldname}->${filename}, bytes:${fileSize}...`)\n },\n getFilePath: () => '',\n getFileSize: () => fileSize,\n getHash: () => hash.digest('hex'),\n getWritePromise: () => Promise.resolve(true),\n }\n}\n"],"names":["crypto","fs","WriteStream","path","checkAndMakeDir","debugLog","deleteFile","getTempFilename","tempFileHandler","options","fieldname","filename","tempFilePath","resolve","tempFileDir","createParentPath","hash","createHash","fileSize","completed","writeStream","createWriteStream","writePromise","Promise","reject","on","err","cleanup","remove","closed","once","destroy","complete","end","Buffer","concat","dataHandler","data","ready","write","update","length","getFilePath","getFileSize","getHash","digest","getWritePromise","memHandler","buffers","getBuffer","buffer","push"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/uploads/fetchAPI-multipart/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/uploads/fetchAPI-multipart/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAA;AAEtE,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAyBnD,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACpE,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,KAAK,8BAA8B,GAAG;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,0BAA0B,GAAG;IACvC,KAAK,CAAC,EAAE,QAAQ,CAAA;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,8BAA8B,CAAC,CAAA;CACtD,CAAA;AAED,KAAK,kBAAkB,GAAG,CAAC,IAAI,EAAE;IAC/B,OAAO,CAAC,EAAE,yBAAyB,CAAA;IACnC,OAAO,EAAE,OAAO,CAAA;CACjB,KAAK,OAAO,CAAC,0BAA0B,CAAC,CAAA;AAEzC,eAAO,MAAM,wBAAwB,EAAE,kBA2CtC,CAAA"}
|