diff --git a/keyserver/src/uploads/uploads.js b/keyserver/src/uploads/uploads.js --- a/keyserver/src/uploads/uploads.js +++ b/keyserver/src/uploads/uploads.js @@ -4,16 +4,17 @@ import invariant from 'invariant'; import multer from 'multer'; import { Readable } from 'stream'; -import t from 'tcomb'; +import t, { type TInterface } from 'tcomb'; -import type { - UploadMediaMetadataRequest, - UploadMultimediaResult, - UploadDeletionRequest, - Dimensions, +import { + type UploadMediaMetadataRequest, + type UploadMultimediaResult, + uploadMultimediaResultValidator, + type UploadDeletionRequest, + type Dimensions, } from 'lib/types/media-types.js'; import { ServerError } from 'lib/utils/errors.js'; -import { tShape } from 'lib/utils/validation-utils.js'; +import { tShape, tID } from 'lib/utils/validation-utils.js'; import { getMediaType, validateAndConvert } from './media-utils.js'; import type { UploadInput } from '../creators/upload-creator.js'; @@ -26,7 +27,7 @@ } from '../fetchers/upload-fetchers.js'; import type { MulterRequest } from '../responders/handlers.js'; import type { Viewer } from '../session/viewer.js'; -import { validateInput } from '../utils/validation-utils.js'; +import { validateInput, validateOutput } from '../utils/validation-utils.js'; const upload = multer(); const multerProcessor: Middleware<> = upload.array('multimedia'); @@ -34,6 +35,10 @@ type MultimediaUploadResult = { results: UploadMultimediaResult[], }; +const MultimediaUploadResultValidator = tShape({ + results: t.list(uploadMultimediaResultValidator), +}); + async function multimediaUploadResponder( viewer: Viewer, req: MulterRequest, @@ -91,7 +96,13 @@ throw new ServerError('invalid_parameters'); } const results = await createUploads(viewer, uploadInfos); - return { results }; + return validateOutput( + viewer.platformDetails, + MultimediaUploadResultValidator, + { + results, + }, + ); } const uploadMediaMetadataInputValidator = tShape({ @@ -141,9 +152,14 @@ if (!uploadID || !secret) { throw new ServerError('invalid_parameters'); } + const convertedUploadID = await validateInput(viewer, tID, uploadID); if (!req.headers.range) { - const { content, mime } = await fetchUpload(viewer, uploadID, secret); + const { content, mime } = await fetchUpload( + viewer, + convertedUploadID, + secret, + ); res.type(mime); res.set('Cache-Control', 'public, max-age=31557600, immutable'); if (process.env.NODE_ENV === 'development') { @@ -154,7 +170,7 @@ } res.send(content); } else { - const totalUploadSize = await getUploadSize(uploadID, secret); + const totalUploadSize = await getUploadSize(convertedUploadID, secret); const range = req.range(totalUploadSize); if (typeof range === 'number' && range < 0) { throw new ServerError( @@ -169,7 +185,7 @@ const { start, end } = range[0]; const respWidth = end - start + 1; const { content, mime } = await fetchUploadChunk( - uploadID, + convertedUploadID, secret, start, respWidth, @@ -198,11 +214,20 @@ } } +const uploadDeletionRequestInputValidator: TInterface = + tShape({ + id: tID, + }); async function uploadDeletionResponder( viewer: Viewer, - request: UploadDeletionRequest, + input: mixed, ): Promise { - const { id } = request; + const { id } = await validateInput( + viewer, + uploadDeletionRequestInputValidator, + input, + ); + await deleteUpload(viewer, id); } diff --git a/lib/types/media-types.js b/lib/types/media-types.js --- a/lib/types/media-types.js +++ b/lib/types/media-types.js @@ -17,6 +17,7 @@ }); export type MediaType = 'photo' | 'video'; +const mediaTypeValidator = t.enums.of(['photo', 'video']); export type EncryptedMediaType = 'encrypted_photo' | 'encrypted_video'; @@ -64,6 +65,14 @@ +mediaType: MediaType, +loop: boolean, }; +export const uploadMultimediaResultValidator: TInterface = + tShape({ + id: tID, + uri: t.String, + dimensions: dimensionsValidator, + mediaType: mediaTypeValidator, + loop: t.Boolean, + }); export type UpdateMultimediaMessageMediaPayload = { +messageID: string,