Skip to content

Commit

Permalink
fixup: update for content-type checking
Browse files Browse the repository at this point in the history
  • Loading branch information
Will Toozs committed Jul 22, 2024
1 parent 2a41094 commit 1e7711f
Show file tree
Hide file tree
Showing 2 changed files with 993 additions and 315 deletions.
55 changes: 48 additions & 7 deletions lib/api/apiUtils/apiCallers/callPostObject.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,56 @@ const os = require('os');
const MAX_FIELD_SIZE = 20 * 1024; // 20KB
/** @see doc: https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html */
const MAX_KEY_SIZE = 1024;
const POST_OBJECT_OPTIONAL_FIELDS = [
'acl',
'awsaccesskeyid',
'bucket',
'cache-control',
'content-disposition',
'content-encoding',
'content-type',
'expires',
'policy',
'redirect',
'tagging',
'success_action_redirect',
'success_action_status',
'x-amz-meta-',
'x-amz-storage-class',
'x-amz-security-token',
'x-amz-signgnature',
'x-amz-website-redirect-location',
];

async function authenticateRequest(request, requestContexts, log) {
return new Promise(resolve => {
// TODO RING-45960 remove ignore for POST object here
// if (err) {
// log.trace('authentication error', { error: err });
// return reject(err);
// }
auth.server.doAuth(request, log, (err, userInfo, authorizationResults, streamingV4Params) =>
resolve({ userInfo, authorizationResults, streamingV4Params }), 's3', requestContexts);
});
}

async function parseFormData(request, response, requestContexts, log) {
/* eslint-disable no-param-reassign */
const formDataParser = busboy({ headers: request.headers });
let formDataParser;
if (!request.headers
|| !request.headers['content-type']
|| !request.headers['content-type'].startsWith('multipart/form-data')) {
return Promise.reject(errors.PreconditionFailed
.customizeDescription('Bucket POST must be of the enclosure-type multipart/form-data'));
}
try {
formDataParser = busboy({ headers: request.headers });
} catch (err) {
log.trace('Error creating form data parser', { error: err.toString() });
return Promise.reject(errors.PreconditionFailed);
}

// formDataParser = busboy({ headers: request.headers });
writeContinue(request, response);

return new Promise((resolve, reject) => {
Expand All @@ -37,20 +75,28 @@ async function parseFormData(request, response, requestContexts, log) {
const formParserFinishedPromise = new Promise((res) => { formParserFinishedPromiseResolve = res; });

formDataParser.on('field', (fieldname, val) => {
// Check if we have exceeded the max size allowed for all fields
totalFieldSize += Buffer.byteLength(val, 'utf8');
if (totalFieldSize > MAX_FIELD_SIZE) {
return reject(errors.MaxPostPreDataLengthExceeded);
}

// validate the fieldname
const lowerFieldname = fieldname.toLowerCase();
// special handling for key field
if (lowerFieldname === 'key') {
if (val.length > MAX_KEY_SIZE) {
return reject(errors.KeyTooLong);
} else if (val.length === 0) {
return reject(errors.InvalidArgument
.customizeDescription('User key must have a length greater than 0.'));
}
request.formData[lowerFieldname] = val;
}
// add only the recognized fields to the formData object
if (POST_OBJECT_OPTIONAL_FIELDS.some(field => lowerFieldname.startsWith(field))) {
request.formData[lowerFieldname] = val;
}
request.formData[lowerFieldname] = val;
return undefined;
});

Expand Down Expand Up @@ -140,11 +186,6 @@ function getFileStat(filePath, log) {
}

async function processPostForm(request, response, requestContexts, log, callback) {
if (!request.headers || !request.headers['content-type'].includes('multipart/form-data')) {
const contentTypeError = errors.PreconditionFailed
.customizeDescription('Bucket POST must be of the enclosure-type multipart/form-data');
return process.nextTick(callback, contentTypeError);
}
try {
const { userInfo, authorizationResults, streamingV4Params } =
await parseFormData(request, response, requestContexts, log);
Expand Down
Loading

0 comments on commit 1e7711f

Please sign in to comment.