Backend half
This commit is contained in:
+283
@@ -0,0 +1,283 @@
|
||||
var AWS = require('../core');
|
||||
var regionUtil = require('../region_config');
|
||||
|
||||
var s3util = {
|
||||
/**
|
||||
* @api private
|
||||
*/
|
||||
isArnInParam: function isArnInParam(req, paramName) {
|
||||
var inputShape = (req.service.api.operations[req.operation] || {}).input || {};
|
||||
var inputMembers = inputShape.members || {};
|
||||
if (!req.params[paramName] || !inputMembers[paramName]) return false;
|
||||
return AWS.util.ARN.validate(req.params[paramName]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate service component from ARN supplied in Bucket parameter
|
||||
*/
|
||||
validateArnService: function validateArnService(req) {
|
||||
var parsedArn = req._parsedArn;
|
||||
|
||||
if (parsedArn.service !== 's3'
|
||||
&& parsedArn.service !== 's3-outposts'
|
||||
&& parsedArn.service !== 's3-object-lambda') {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidARN',
|
||||
message: 'expect \'s3\' or \'s3-outposts\' or \'s3-object-lambda\' in ARN service component'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate account ID from ARN supplied in Bucket parameter is a valid account
|
||||
*/
|
||||
validateArnAccount: function validateArnAccount(req) {
|
||||
var parsedArn = req._parsedArn;
|
||||
|
||||
if (!/[0-9]{12}/.exec(parsedArn.accountId)) {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidARN',
|
||||
message: 'ARN accountID does not match regex "[0-9]{12}"'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate ARN supplied in Bucket parameter is a valid access point ARN
|
||||
*/
|
||||
validateS3AccessPointArn: function validateS3AccessPointArn(req) {
|
||||
var parsedArn = req._parsedArn;
|
||||
|
||||
//can be ':' or '/'
|
||||
var delimiter = parsedArn.resource['accesspoint'.length];
|
||||
|
||||
if (parsedArn.resource.split(delimiter).length !== 2) {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidARN',
|
||||
message: 'Access Point ARN should have one resource accesspoint/{accesspointName}'
|
||||
});
|
||||
}
|
||||
|
||||
var accessPoint = parsedArn.resource.split(delimiter)[1];
|
||||
var accessPointPrefix = accessPoint + '-' + parsedArn.accountId;
|
||||
if (!s3util.dnsCompatibleBucketName(accessPointPrefix) || accessPointPrefix.match(/\./)) {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidARN',
|
||||
message: 'Access point resource in ARN is not DNS compatible. Got ' + accessPoint
|
||||
});
|
||||
}
|
||||
|
||||
//set parsed valid access point
|
||||
req._parsedArn.accessPoint = accessPoint;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate Outposts ARN supplied in Bucket parameter is a valid outposts ARN
|
||||
*/
|
||||
validateOutpostsArn: function validateOutpostsArn(req) {
|
||||
var parsedArn = req._parsedArn;
|
||||
|
||||
if (
|
||||
parsedArn.resource.indexOf('outpost:') !== 0 &&
|
||||
parsedArn.resource.indexOf('outpost/') !== 0
|
||||
) {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidARN',
|
||||
message: 'ARN resource should begin with \'outpost/\''
|
||||
});
|
||||
}
|
||||
|
||||
//can be ':' or '/'
|
||||
var delimiter = parsedArn.resource['outpost'.length];
|
||||
var outpostId = parsedArn.resource.split(delimiter)[1];
|
||||
var dnsHostRegex = new RegExp(/^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])$/);
|
||||
if (!dnsHostRegex.test(outpostId)) {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidARN',
|
||||
message: 'Outpost resource in ARN is not DNS compatible. Got ' + outpostId
|
||||
});
|
||||
}
|
||||
req._parsedArn.outpostId = outpostId;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate Outposts ARN supplied in Bucket parameter is a valid outposts ARN
|
||||
*/
|
||||
validateOutpostsAccessPointArn: function validateOutpostsAccessPointArn(req) {
|
||||
var parsedArn = req._parsedArn;
|
||||
|
||||
//can be ':' or '/'
|
||||
var delimiter = parsedArn.resource['outpost'.length];
|
||||
|
||||
if (parsedArn.resource.split(delimiter).length !== 4) {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidARN',
|
||||
message: 'Outposts ARN should have two resources outpost/{outpostId}/accesspoint/{accesspointName}'
|
||||
});
|
||||
}
|
||||
|
||||
var accessPoint = parsedArn.resource.split(delimiter)[3];
|
||||
var accessPointPrefix = accessPoint + '-' + parsedArn.accountId;
|
||||
if (!s3util.dnsCompatibleBucketName(accessPointPrefix) || accessPointPrefix.match(/\./)) {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidARN',
|
||||
message: 'Access point resource in ARN is not DNS compatible. Got ' + accessPoint
|
||||
});
|
||||
}
|
||||
|
||||
//set parsed valid access point
|
||||
req._parsedArn.accessPoint = accessPoint;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate region field in ARN supplied in Bucket parameter is a valid region
|
||||
*/
|
||||
validateArnRegion: function validateArnRegion(req, options) {
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
var useArnRegion = s3util.loadUseArnRegionConfig(req);
|
||||
var regionFromArn = req._parsedArn.region;
|
||||
var clientRegion = req.service.config.region;
|
||||
var useFipsEndpoint = req.service.config.useFipsEndpoint;
|
||||
var allowFipsEndpoint = options.allowFipsEndpoint || false;
|
||||
|
||||
if (!regionFromArn) {
|
||||
var message = 'ARN region is empty';
|
||||
if (req._parsedArn.service === 's3') {
|
||||
message = message + '\nYou may want to use multi-regional ARN. The feature is not supported in current SDK. ' +
|
||||
'You should consider switching to V3(https://github.com/aws/aws-sdk-js-v3).';
|
||||
}
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidARN',
|
||||
message: message
|
||||
});
|
||||
}
|
||||
|
||||
if (useFipsEndpoint && !allowFipsEndpoint) {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidConfiguration',
|
||||
message: 'ARN endpoint is not compatible with FIPS region'
|
||||
});
|
||||
}
|
||||
|
||||
if (regionFromArn.indexOf('fips') >= 0) {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidConfiguration',
|
||||
message: 'FIPS region not allowed in ARN'
|
||||
});
|
||||
}
|
||||
|
||||
if (!useArnRegion && regionFromArn !== clientRegion) {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidConfiguration',
|
||||
message: 'Configured region conflicts with access point region'
|
||||
});
|
||||
} else if (
|
||||
useArnRegion &&
|
||||
regionUtil.getEndpointSuffix(regionFromArn) !== regionUtil.getEndpointSuffix(clientRegion)
|
||||
) {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidConfiguration',
|
||||
message: 'Configured region and access point region not in same partition'
|
||||
});
|
||||
}
|
||||
|
||||
if (req.service.config.useAccelerateEndpoint) {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidConfiguration',
|
||||
message: 'useAccelerateEndpoint config is not supported with access point ARN'
|
||||
});
|
||||
}
|
||||
|
||||
if (req._parsedArn.service === 's3-outposts' && req.service.config.useDualstackEndpoint) {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidConfiguration',
|
||||
message: 'Dualstack is not supported with outposts access point ARN'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
loadUseArnRegionConfig: function loadUseArnRegionConfig(req) {
|
||||
var envName = 'AWS_S3_USE_ARN_REGION';
|
||||
var configName = 's3_use_arn_region';
|
||||
var useArnRegion = true;
|
||||
var originalConfig = req.service._originalConfig || {};
|
||||
if (req.service.config.s3UseArnRegion !== undefined) {
|
||||
return req.service.config.s3UseArnRegion;
|
||||
} else if (originalConfig.s3UseArnRegion !== undefined) {
|
||||
useArnRegion = originalConfig.s3UseArnRegion === true;
|
||||
} else if (AWS.util.isNode()) {
|
||||
//load from environmental variable AWS_USE_ARN_REGION
|
||||
if (process.env[envName]) {
|
||||
var value = process.env[envName].trim().toLowerCase();
|
||||
if (['false', 'true'].indexOf(value) < 0) {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidConfiguration',
|
||||
message: envName + ' only accepts true or false. Got ' + process.env[envName],
|
||||
retryable: false
|
||||
});
|
||||
}
|
||||
useArnRegion = value === 'true';
|
||||
} else { //load from shared config property use_arn_region
|
||||
var profiles = {};
|
||||
var profile = {};
|
||||
try {
|
||||
profiles = AWS.util.getProfilesFromSharedConfig(AWS.util.iniLoader);
|
||||
profile = profiles[process.env.AWS_PROFILE || AWS.util.defaultProfile];
|
||||
} catch (e) {}
|
||||
if (profile[configName]) {
|
||||
if (['false', 'true'].indexOf(profile[configName].trim().toLowerCase()) < 0) {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidConfiguration',
|
||||
message: configName + ' only accepts true or false. Got ' + profile[configName],
|
||||
retryable: false
|
||||
});
|
||||
}
|
||||
useArnRegion = profile[configName].trim().toLowerCase() === 'true';
|
||||
}
|
||||
}
|
||||
}
|
||||
req.service.config.s3UseArnRegion = useArnRegion;
|
||||
return useArnRegion;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validations before URI can be populated
|
||||
*/
|
||||
validatePopulateUriFromArn: function validatePopulateUriFromArn(req) {
|
||||
if (req.service._originalConfig && req.service._originalConfig.endpoint) {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidConfiguration',
|
||||
message: 'Custom endpoint is not compatible with access point ARN'
|
||||
});
|
||||
}
|
||||
|
||||
if (req.service.config.s3ForcePathStyle) {
|
||||
throw AWS.util.error(new Error(), {
|
||||
code: 'InvalidConfiguration',
|
||||
message: 'Cannot construct path-style endpoint with access point'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if the bucket name is DNS compatible. Buckets created
|
||||
* outside of the classic region MUST be DNS compatible.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
dnsCompatibleBucketName: function dnsCompatibleBucketName(bucketName) {
|
||||
var b = bucketName;
|
||||
var domain = new RegExp(/^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$/);
|
||||
var ipAddress = new RegExp(/(\d+\.){3}\d+/);
|
||||
var dots = new RegExp(/\.\./);
|
||||
return (b.match(domain) && !b.match(ipAddress) && !b.match(dots)) ? true : false;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @api private
|
||||
*/
|
||||
module.exports = s3util;
|
||||
Reference in New Issue
Block a user