Compare commits

...

3 Commits

Author SHA1 Message Date
williamlardier f446354c52
temp 2023-01-02 16:53:38 +01:00
williamlardier 4106016dcd
ARSN-291: bump arsenal to 8.1.78 2022-12-26 14:39:03 +01:00
williamlardier 088819bb28
ARSN-291: new bucket field for capabilities 2022-12-26 14:39:03 +01:00
8 changed files with 138 additions and 31 deletions

View File

@ -18,17 +18,17 @@ export default function checkRequestExpiry(timestamp: number, log: Logger) {
log.trace('current timestamp', { currentTimestamp: currentTime });
const fifteenMinutes = (15 * 60 * 1000);
if (currentTime - timestamp > fifteenMinutes) {
log.trace('request timestamp is not within 15 minutes of current time');
log.debug('request time too skewed', { timestamp });
return errors.RequestTimeTooSkewed;
}
// if (currentTime - timestamp > fifteenMinutes) {
// log.trace('request timestamp is not within 15 minutes of current time');
// log.debug('request time too skewed', { timestamp });
// return errors.RequestTimeTooSkewed;
// }
if (currentTime + fifteenMinutes < timestamp) {
log.trace('request timestamp is more than 15 minutes into future');
log.debug('request time too skewed', { timestamp });
return errors.RequestTimeTooSkewed;
}
// if (currentTime + fifteenMinutes < timestamp) {
// log.trace('request timestamp is more than 15 minutes into future');
// log.debug('request time too skewed', { timestamp });
// return errors.RequestTimeTooSkewed;
// }
return undefined;
}

View File

@ -44,11 +44,11 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
{ expires: request.query.Expires });
return { err: errors.AccessDenied };
}
if (currentTime > expirationTime) {
log.debug('current time exceeds expires time',
{ expires: request.query.Expires });
return { err: errors.RequestTimeTooSkewed };
}
// if (currentTime > expirationTime) {
// log.debug('current time exceeds expires time',
// { expires: request.query.Expires });
// return { err: errors.RequestTimeTooSkewed };
// }
const accessKey = data.AWSAccessKeyId;
// @ts-ignore
log.addDefaultFields({ accessKey });

View File

@ -128,9 +128,9 @@ export function check(
// 15 minutes in seconds
const expiry = (15 * 60);
const isTimeSkewed = checkTimeSkew(timestamp, expiry, log);
if (isTimeSkewed) {
return { err: errors.RequestTimeTooSkewed };
}
// if (isTimeSkewed) {
// return { err: errors.RequestTimeTooSkewed };
// }
let proxyPath: string | undefined;
if (request.headers.proxy_path) {

View File

@ -51,10 +51,10 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
const service = credential[3];
const requestType = credential[4];
const isTimeSkewed = checkTimeSkew(timestamp, expiry, log);
if (isTimeSkewed) {
return { err: errors.RequestTimeTooSkewed };
}
// const isTimeSkewed = checkTimeSkew(timestamp, expiry, log);
// if (isTimeSkewed) {
// return { err: errors.RequestTimeTooSkewed };
// }
let proxyPath: string | undefined;
if (request.headers.proxy_path) {

View File

@ -38,11 +38,11 @@ export function validateCredentials(
// convert timestamp to format of scopeDate YYYYMMDD
const timestampDate = timestamp.split('T')[0];
if (scopeDate.length !== 8 || scopeDate !== timestampDate) {
log.warn('scope date must be the same date as the timestamp date',
{ scopeDate, timestampDate });
return errors.RequestTimeTooSkewed;
}
// if (scopeDate.length !== 8 || scopeDate !== timestampDate) {
// log.warn('scope date must be the same date as the timestamp date',
// { scopeDate, timestampDate });
// return errors.RequestTimeTooSkewed;
// }
if (service !== 's3' && service !== 'iam' && service !== 'ring' &&
service !== 'sts') {
log.warn('service in credentials is not one of s3/iam/ring/sts', {

View File

@ -13,7 +13,7 @@ import { areTagsValid, BucketTag } from '../s3middleware/tagging';
// WHEN UPDATING THIS NUMBER, UPDATE BucketInfoModelVersion.md CHANGELOG
// BucketInfoModelVersion.md can be found in documentation/ at the root
// of this repository
const modelVersion = 14;
const modelVersion = 16;
export type CORS = {
id: string;
@ -37,6 +37,41 @@ export type VersioningConfiguration = {
MfaDelete: any;
};
export type VeeamCapacity = {
SystemInfo?: {
ProtocolVersion: string,
ModelName: string,
ProtocolCapabilities: {
CapacityInfo: boolean,
UploadSessions: boolean,
IAMSTS?: boolean,
},
APIEndpoints?: {
IAMEndpoint: string,
STSEndpoint: string,
},
SystemRecommendations?: {
S3ConcurrentTaskLimit: number,
S3MultiObjectDelete: number,
StorageCurrentTasksLimit: number,
KbBlockSize: number,
}
LastModified?: string,
},
CapacityInfo?: {
Capacity: number,
Available: number,
Used: number,
LastModified?: string,
},
};
// Capacity contains all specifics from external products supported by
// our S3 implementation, at bucket level
export type Capacity = {
VeeamSOSApi?: VeeamCapacity,
};
export type ACL = OACL & { WRITE: string[] }
export default class BucketInfo {
@ -65,6 +100,7 @@ export default class BucketInfo {
_isNFS: boolean | null;
_azureInfo: any | null;
_ingestion: { status: 'enabled' | 'disabled' } | null;
_capabilities?: Capacity;
/**
* Represents all bucket information.
@ -120,6 +156,7 @@ export default class BucketInfo {
* @param [objectLockConfiguration] - object lock configuration
* @param [notificationConfiguration] - bucket notification configuration
* @param [tags] - bucket tag set
* @param [capabilities] - capabilities for the bucket
*/
constructor(
name: string,
@ -147,6 +184,7 @@ export default class BucketInfo {
objectLockConfiguration?: any,
notificationConfiguration?: any,
tags?: Array<BucketTag> | [],
capabilities?: Capacity,
) {
assert.strictEqual(typeof name, 'string');
assert.strictEqual(typeof owner, 'string');
@ -274,6 +312,7 @@ export default class BucketInfo {
this._objectLockConfiguration = objectLockConfiguration || null;
this._notificationConfiguration = notificationConfiguration || null;
this._tags = tags;
this._capabilities = capabilities || undefined;
return this;
}
@ -308,6 +347,7 @@ export default class BucketInfo {
objectLockConfiguration: this._objectLockConfiguration,
notificationConfiguration: this._notificationConfiguration,
tags: this._tags,
capabilities: this._capabilities,
};
const final = this._websiteConfiguration
? {
@ -333,7 +373,8 @@ export default class BucketInfo {
obj.cors, obj.replicationConfiguration, obj.lifecycleConfiguration,
obj.bucketPolicy, obj.uid, obj.readLocationConstraint, obj.isNFS,
obj.ingestion, obj.azureInfo, obj.objectLockEnabled,
obj.objectLockConfiguration, obj.notificationConfiguration, obj.tags);
obj.objectLockConfiguration, obj.notificationConfiguration, obj.tags,
obj.capabilities);
}
/**
@ -360,7 +401,7 @@ export default class BucketInfo {
data._bucketPolicy, data._uid, data._readLocationConstraint,
data._isNFS, data._ingestion, data._azureInfo,
data._objectLockEnabled, data._objectLockConfiguration,
data._notificationConfiguration, data._tags);
data._notificationConfiguration, data._tags, data._capabilities);
}
/**
@ -868,4 +909,25 @@ export default class BucketInfo {
this._tags = tags;
return this;
}
/**
* Get the value of bucket capabilities
* @param capability? - if provided, will return a specific capacity
* @return - capabilities of the bucket, or null
*/
getCapabilities(capability?: string) {
if (capability && this._capabilities && this._capabilities[capability]) {
return this._capabilities[capability];
}
return this._capabilities;
}
/**
* Set bucket capabilities
* @return - bucket info instance
*/
setCapabilities(capabilities: Capacity) {
this._capabilities = capabilities;
return this;
}
}

View File

@ -3,7 +3,7 @@
"engines": {
"node": ">=16"
},
"version": "8.1.77",
"version": "8.1.78",
"description": "Common utilities for the S3 project components",
"main": "build/index.js",
"repository": {

View File

@ -199,6 +199,35 @@ const testBucketTagging = [
},
];
const testBucketCapabilities = {
VeeamSOSApi: {
SystemInfo: {
ProtocolVersion: '"1.0"',
ModelName: 'ARTESCA',
ProtocolCapabilities: {
CapacityInfo: true,
UploadSessions: false,
IAMSTS: false,
},
APIEndpoints: {
IAMEndpoint: '',
STSEndpoint: '',
},
SystemRecommendations: {
S3ConcurrentTaskLimit: 64,
S3MultiObjectDelete: 1000,
StorageCurrentTasksLimit: 0,
KbBlockSize: 1024,
},
},
CapacityInfo: {
Capacity: 1,
Available: 1,
Used: 0,
},
},
};
// create a dummy bucket to test getters and setters
Object.keys(acl).forEach(
aclObj => describe(`different acl configurations : ${aclObj}`, () => {
@ -222,6 +251,7 @@ Object.keys(acl).forEach(
testObjectLockConfiguration,
testNotificationConfiguration,
testBucketTagging,
testBucketCapabilities,
);
describe('serialize/deSerialize on BucketInfo class', () => {
@ -259,6 +289,7 @@ Object.keys(acl).forEach(
dummyBucket._objectLockConfiguration,
notificationConfiguration: dummyBucket._notificationConfiguration,
tags: dummyBucket._tags,
capabilities: dummyBucket._capabilities,
};
assert.strictEqual(serialized, JSON.stringify(bucketInfos));
done();
@ -307,6 +338,7 @@ Object.keys(acl).forEach(
_notificationConfiguration:
dummyBucket._notificationConfiguration,
_tags: dummyBucket._tags,
_capabilities: dummyBucket._capabilities,
};
const fromObj = BucketInfo.fromObj(dataObj);
assert(fromObj instanceof BucketInfo);
@ -452,6 +484,13 @@ Object.keys(acl).forEach(
assert.deepStrictEqual(dummyBucket.getNotificationConfiguration(),
testNotificationConfiguration);
});
it('getCapabilities should return capabilities', () => {
assert.deepStrictEqual(dummyBucket.getCapabilities(), testBucketCapabilities);
});
it('getCapabilities should return capabilities with specific path', () => {
assert.deepStrictEqual(dummyBucket.getCapabilities('VeeamSOSApi'),
testBucketCapabilities.VeeamSOSApi);
});
});
describe('setters on BucketInfo class', () => {
@ -649,6 +688,12 @@ Object.keys(acl).forEach(
assert.deepStrictEqual(
dummyBucket.getUid(), testUid);
});
it('setCapabilities should set bucket capabilities', () => {
const testCapabilities = testBucketCapabilities;
dummyBucket.setCapabilities(testCapabilities);
assert.deepStrictEqual(
dummyBucket.getCapabilities(), testCapabilities);
});
});
}),
);