@@ -22,16 +22,40 @@ import type WebresourceModel from './webresource.js';
2222import { isMultipartUploadAvailable } from './multipartUpload.js' ;
2323import { addAction } from '../sbvr-api/actions.js' ;
2424import { beginUpload , commitUpload , cancelUpload } from './actions/index.js' ;
25+ import type { IncomingHttpHeaders } from 'node:http' ;
2526
2627export * from './handlers/index.js' ;
2728
28- export interface IncomingFile {
29+ // S3 only supports full checksums (on multipart uploads) for these algorithms
30+ // See: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#ChecksumTypes
31+ export const supportedChecksumAlgorithms = [
32+ 'CRC64NVME' ,
33+ 'CRC32' ,
34+ 'CRC32C' ,
35+ ] as const ;
36+ export type SupportedChecksumAlgorithm =
37+ ( typeof supportedChecksumAlgorithms ) [ number ] ;
38+
39+ type ChecksumPayload =
40+ | {
41+ checksum ?: undefined ;
42+ checksumAlgorithm ?: undefined ;
43+ }
44+ | {
45+ checksum : string ;
46+ checksumAlgorithm : SupportedChecksumAlgorithm ;
47+ } ;
48+
49+ export type IncomingFile = {
2950 fieldname : string ;
3051 originalname : string ;
3152 encoding : string ;
3253 mimetype : string ;
3354 stream : stream . Readable ;
34- }
55+ } & ChecksumPayload ;
56+
57+ export const checksumHeaderName = 'x-pinejs-checksum' ;
58+ export const checksumAlgorithmHeaderName = 'x-pinejs-checksum-algorithm' ;
3559
3660export interface UploadResponse {
3761 size : number ;
@@ -57,12 +81,12 @@ export interface BeginMultipartUploadHandlerResponse {
5781 uploadId : string ;
5882}
5983
60- export interface CommitMultipartUploadPayload {
84+ export type CommitMultipartUploadPayload = {
6185 fileKey : string ;
6286 uploadId : string ;
6387 filename : string ;
6488 providerCommitData ?: Record < string , any > ;
65- }
89+ } & ChecksumPayload ;
6690
6791export interface CancelMultipartUploadPayload {
6892 fileKey : string ;
@@ -159,6 +183,31 @@ const getRequestUploadValidator = async (
159183 } ;
160184} ;
161185
186+ export const getChecksumParams = ( headers : IncomingHttpHeaders ) => {
187+ const checksum = headers [ checksumHeaderName ] ;
188+ const checksumAlgorithm = headers [ checksumAlgorithmHeaderName ] as
189+ | SupportedChecksumAlgorithm
190+ | undefined ;
191+
192+ if ( checksum == null || checksumAlgorithm == null ) {
193+ return { checksum : undefined , checksumAlgorithm : undefined } ;
194+ }
195+
196+ if ( typeof checksum !== 'string' || typeof checksumAlgorithm !== 'string' ) {
197+ throw new errors . BadRequestError (
198+ `Invalid ${ checksumHeaderName } or ${ checksumAlgorithmHeaderName } header` ,
199+ ) ;
200+ }
201+
202+ if ( ! supportedChecksumAlgorithms . includes ( checksumAlgorithm ) ) {
203+ throw new errors . BadRequestError (
204+ `Invalid ${ checksumAlgorithmHeaderName } header value: ${ checksumAlgorithm } ` ,
205+ ) ;
206+ }
207+
208+ return { checksum, checksumAlgorithm } ;
209+ } ;
210+
162211export const getUploaderMiddlware = (
163212 handler : WebResourceHandler ,
164213) : Express . RequestHandler => {
@@ -218,14 +267,17 @@ export const getUploaderMiddlware = (
218267 filestream . resume ( ) ;
219268 return ;
220269 }
270+ const checksumPayload = getChecksumParams ( req . headers ) ;
221271 const file : IncomingFile = {
222272 originalname : info . filename ,
223273 encoding : info . encoding ,
224274 mimetype : info . mimeType ,
225275 stream : filestream ,
226276 fieldname,
277+ ...checksumPayload ,
227278 } ;
228279 const result = await handler . handleFile ( file ) ;
280+
229281 req . body [ fieldname ] = {
230282 filename : info . filename ,
231283 content_type : info . mimeType ,
0 commit comments