Skip to content

Commit dfa27be

Browse files
committed
NC | implement object lock functionality
Signed-off-by: nadav mizrahi <nadav.mizrahi16@gmail.com>
1 parent 009d219 commit dfa27be

16 files changed

+743
-69
lines changed

src/api/common_api.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,6 +1592,7 @@ module.exports = {
15921592
},
15931593
object_lock_configuration: {
15941594
type: 'object',
1595+
required: ['object_lock_enabled'],
15951596
properties: {
15961597
object_lock_enabled: {
15971598
type: 'string',
@@ -1606,7 +1607,10 @@ module.exports = {
16061607
required: ['years', 'mode'],
16071608
additionalProperties: false,
16081609
properties: {
1609-
years: { type: 'integer' },
1610+
years: {
1611+
type: 'integer',
1612+
"minimum": 1
1613+
},
16101614
mode: {
16111615
type: 'string',
16121616
enum: ['GOVERNANCE', 'COMPLIANCE']
@@ -1618,7 +1622,10 @@ module.exports = {
16181622
required: ['days', 'mode'],
16191623
additionalProperties: false,
16201624
properties: {
1621-
days: { type: 'integer' },
1625+
days: {
1626+
type: 'integer',
1627+
"minimum": 1
1628+
},
16221629
mode: {
16231630
type: 'string',
16241631
enum: ['GOVERNANCE', 'COMPLIANCE']

src/endpoint/s3/ops/s3_post_object_uploads.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ async function post_object_uploads(req, res) {
1414
const tagging = s3_utils.parse_tagging_header(req);
1515
const encryption = s3_utils.parse_encryption(req);
1616
const storage_class = s3_utils.parse_storage_class_header(req);
17+
const lock_settings = config.WORM_ENABLED ? s3_utils.parse_lock_header(req) : undefined;
1718
if (config.DENY_UPLOAD_TO_STORAGE_CLASS_STANDARD && storage_class === s3_utils.STORAGE_CLASS_STANDARD) {
1819
throw new S3Error(S3Error.InvalidStorageClass);
1920
}
@@ -26,7 +27,8 @@ async function post_object_uploads(req, res) {
2627
xattr: s3_utils.get_request_xattr(req),
2728
storage_class,
2829
tagging,
29-
encryption
30+
encryption,
31+
lock_settings
3032
});
3133

3234
s3_utils.set_encryption_response_headers(req, res, reply.encryption);

src/endpoint/s3/ops/s3_put_bucket_object_lock.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,19 @@ async function put_bucket_object_lock(req, res) {
1717
}
1818
const lock_configuration = s3_utils.parse_body_object_lock_conf_xml(req);
1919

20-
await req.object_sdk.put_object_lock_configuration({
21-
name: req.params.bucket,
22-
object_lock_configuration: lock_configuration,
23-
});
20+
try {
21+
await req.object_sdk.put_object_lock_configuration({
22+
name: req.params.bucket,
23+
object_lock_configuration: lock_configuration,
24+
});
25+
} catch (err) {
26+
let error = err;
27+
if (err.rpc_code === 'INVALID_SCHEMA' || err.rpc_code === 'INVALID_SCHEMA_PARAMS') {
28+
console.error('put_bucket_object_lock: Invalid schema provided', err);
29+
error = new S3Error(S3Error.MalformedXML);
30+
}
31+
throw error;
32+
}
2433
}
2534

2635
module.exports = {

src/endpoint/s3/s3_utils.js

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -538,35 +538,48 @@ function parse_body_encryption_xml(req) {
538538

539539
function parse_body_object_lock_conf_xml(req) {
540540
const configuration = req.body.ObjectLockConfiguration;
541-
const retention = configuration.Rule[0].DefaultRetention[0];
542-
543-
if ((retention.Days && retention.Years) || (!retention.Days && !retention.Years) ||
544-
(retention.Mode[0] !== 'GOVERNANCE' && retention.Mode[0] !== 'COMPLIANCE')) throw new S3Error(S3Error.MalformedXML);
545-
546-
const conf = {
547-
object_lock_enabled: configuration.ObjectLockEnabled[0],
548-
rule: { default_retention: { mode: retention.Mode[0], } }
549-
};
541+
try {
542+
const retention = configuration?.Rule?.[0]?.DefaultRetention?.[0];
543+
const object_lock_enabled = configuration?.ObjectLockEnabled?.[0];
544+
if (object_lock_enabled !== 'Enabled') {
545+
throw new S3Error(S3Error.MalformedXML);
546+
}
547+
const conf = {
548+
object_lock_enabled,
549+
};
550550

551-
if (retention.Days) {
552-
const days = parseInt(retention.Days[0], 10);
553-
if (days <= 0) {
554-
const err = new S3Error(S3Error.InvalidArgument);
555-
err.message = 'Default retention period must be a positive integer value';
556-
throw err;
551+
if (retention) {
552+
conf.rule = { default_retention: { mode: retention.Mode[0] } };
553+
if ((!retention.Days && !retention.Years) || (retention.Mode[0] !== 'GOVERNANCE' && retention.Mode[0] !== 'COMPLIANCE')) {
554+
throw new S3Error(S3Error.MalformedXML);
555+
}
556+
if (retention.Days) {
557+
const days = parseInt(retention.Days[0], 10);
558+
if (!Number.isInteger(days) || days <= 0) {
559+
const err = new S3Error(S3Error.InvalidArgument);
560+
err.message = 'Default retention period must be a positive integer value';
561+
throw err;
562+
}
563+
conf.rule.default_retention.days = days;
564+
}
565+
if (retention.Years) {
566+
const years = parseInt(retention.Years[0], 10);
567+
if (!Number.isInteger(years) || years <= 0) {
568+
const err = new S3Error(S3Error.InvalidArgument);
569+
err.message = 'Default retention period must be a positive integer value';
570+
throw err;
571+
}
572+
conf.rule.default_retention.years = years;
573+
}
557574
}
558-
conf.rule.default_retention.days = days;
559-
}
560-
if (retention.Years) {
561-
const years = parseInt(retention.Years[0], 10);
562-
if (years <= 0) {
563-
const err = new S3Error(S3Error.InvalidArgument);
564-
err.message = 'Default retention period must be a positive integer value';
575+
return conf;
576+
} catch (err) {
577+
dbg.error('parse_body_object_lock_conf_xml failed', err);
578+
if (err instanceof S3Error) {
565579
throw err;
566580
}
567-
conf.rule.default_retention.years = years;
581+
throw new S3Error(S3Error.MalformedXML);
568582
}
569-
return conf;
570583
}
571584

572585
function parse_body_website_xml(req) {

0 commit comments

Comments
 (0)