Compare commits
3 Commits
developmen
...
improvemen
Author | SHA1 | Date |
---|---|---|
williamlardier | f446354c52 | |
williamlardier | 4106016dcd | |
williamlardier | 088819bb28 |
|
@ -18,17 +18,17 @@ export default function checkRequestExpiry(timestamp: number, log: Logger) {
|
||||||
log.trace('current timestamp', { currentTimestamp: currentTime });
|
log.trace('current timestamp', { currentTimestamp: currentTime });
|
||||||
|
|
||||||
const fifteenMinutes = (15 * 60 * 1000);
|
const fifteenMinutes = (15 * 60 * 1000);
|
||||||
if (currentTime - timestamp > fifteenMinutes) {
|
// if (currentTime - timestamp > fifteenMinutes) {
|
||||||
log.trace('request timestamp is not within 15 minutes of current time');
|
// log.trace('request timestamp is not within 15 minutes of current time');
|
||||||
log.debug('request time too skewed', { timestamp });
|
// log.debug('request time too skewed', { timestamp });
|
||||||
return errors.RequestTimeTooSkewed;
|
// return errors.RequestTimeTooSkewed;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (currentTime + fifteenMinutes < timestamp) {
|
// if (currentTime + fifteenMinutes < timestamp) {
|
||||||
log.trace('request timestamp is more than 15 minutes into future');
|
// log.trace('request timestamp is more than 15 minutes into future');
|
||||||
log.debug('request time too skewed', { timestamp });
|
// log.debug('request time too skewed', { timestamp });
|
||||||
return errors.RequestTimeTooSkewed;
|
// return errors.RequestTimeTooSkewed;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,11 +44,11 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
||||||
{ expires: request.query.Expires });
|
{ expires: request.query.Expires });
|
||||||
return { err: errors.AccessDenied };
|
return { err: errors.AccessDenied };
|
||||||
}
|
}
|
||||||
if (currentTime > expirationTime) {
|
// if (currentTime > expirationTime) {
|
||||||
log.debug('current time exceeds expires time',
|
// log.debug('current time exceeds expires time',
|
||||||
{ expires: request.query.Expires });
|
// { expires: request.query.Expires });
|
||||||
return { err: errors.RequestTimeTooSkewed };
|
// return { err: errors.RequestTimeTooSkewed };
|
||||||
}
|
// }
|
||||||
const accessKey = data.AWSAccessKeyId;
|
const accessKey = data.AWSAccessKeyId;
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
log.addDefaultFields({ accessKey });
|
log.addDefaultFields({ accessKey });
|
||||||
|
|
|
@ -128,9 +128,9 @@ export function check(
|
||||||
// 15 minutes in seconds
|
// 15 minutes in seconds
|
||||||
const expiry = (15 * 60);
|
const expiry = (15 * 60);
|
||||||
const isTimeSkewed = checkTimeSkew(timestamp, expiry, log);
|
const isTimeSkewed = checkTimeSkew(timestamp, expiry, log);
|
||||||
if (isTimeSkewed) {
|
// if (isTimeSkewed) {
|
||||||
return { err: errors.RequestTimeTooSkewed };
|
// return { err: errors.RequestTimeTooSkewed };
|
||||||
}
|
// }
|
||||||
|
|
||||||
let proxyPath: string | undefined;
|
let proxyPath: string | undefined;
|
||||||
if (request.headers.proxy_path) {
|
if (request.headers.proxy_path) {
|
||||||
|
|
|
@ -51,10 +51,10 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
||||||
const service = credential[3];
|
const service = credential[3];
|
||||||
const requestType = credential[4];
|
const requestType = credential[4];
|
||||||
|
|
||||||
const isTimeSkewed = checkTimeSkew(timestamp, expiry, log);
|
// const isTimeSkewed = checkTimeSkew(timestamp, expiry, log);
|
||||||
if (isTimeSkewed) {
|
// if (isTimeSkewed) {
|
||||||
return { err: errors.RequestTimeTooSkewed };
|
// return { err: errors.RequestTimeTooSkewed };
|
||||||
}
|
// }
|
||||||
|
|
||||||
let proxyPath: string | undefined;
|
let proxyPath: string | undefined;
|
||||||
if (request.headers.proxy_path) {
|
if (request.headers.proxy_path) {
|
||||||
|
|
|
@ -38,11 +38,11 @@ export function validateCredentials(
|
||||||
|
|
||||||
// convert timestamp to format of scopeDate YYYYMMDD
|
// convert timestamp to format of scopeDate YYYYMMDD
|
||||||
const timestampDate = timestamp.split('T')[0];
|
const timestampDate = timestamp.split('T')[0];
|
||||||
if (scopeDate.length !== 8 || scopeDate !== timestampDate) {
|
// if (scopeDate.length !== 8 || scopeDate !== timestampDate) {
|
||||||
log.warn('scope date must be the same date as the timestamp date',
|
// log.warn('scope date must be the same date as the timestamp date',
|
||||||
{ scopeDate, timestampDate });
|
// { scopeDate, timestampDate });
|
||||||
return errors.RequestTimeTooSkewed;
|
// return errors.RequestTimeTooSkewed;
|
||||||
}
|
// }
|
||||||
if (service !== 's3' && service !== 'iam' && service !== 'ring' &&
|
if (service !== 's3' && service !== 'iam' && service !== 'ring' &&
|
||||||
service !== 'sts') {
|
service !== 'sts') {
|
||||||
log.warn('service in credentials is not one of s3/iam/ring/sts', {
|
log.warn('service in credentials is not one of s3/iam/ring/sts', {
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { areTagsValid, BucketTag } from '../s3middleware/tagging';
|
||||||
// WHEN UPDATING THIS NUMBER, UPDATE BucketInfoModelVersion.md CHANGELOG
|
// WHEN UPDATING THIS NUMBER, UPDATE BucketInfoModelVersion.md CHANGELOG
|
||||||
// BucketInfoModelVersion.md can be found in documentation/ at the root
|
// BucketInfoModelVersion.md can be found in documentation/ at the root
|
||||||
// of this repository
|
// of this repository
|
||||||
const modelVersion = 14;
|
const modelVersion = 16;
|
||||||
|
|
||||||
export type CORS = {
|
export type CORS = {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -37,6 +37,41 @@ export type VersioningConfiguration = {
|
||||||
MfaDelete: any;
|
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 type ACL = OACL & { WRITE: string[] }
|
||||||
|
|
||||||
export default class BucketInfo {
|
export default class BucketInfo {
|
||||||
|
@ -65,6 +100,7 @@ export default class BucketInfo {
|
||||||
_isNFS: boolean | null;
|
_isNFS: boolean | null;
|
||||||
_azureInfo: any | null;
|
_azureInfo: any | null;
|
||||||
_ingestion: { status: 'enabled' | 'disabled' } | null;
|
_ingestion: { status: 'enabled' | 'disabled' } | null;
|
||||||
|
_capabilities?: Capacity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents all bucket information.
|
* Represents all bucket information.
|
||||||
|
@ -120,6 +156,7 @@ export default class BucketInfo {
|
||||||
* @param [objectLockConfiguration] - object lock configuration
|
* @param [objectLockConfiguration] - object lock configuration
|
||||||
* @param [notificationConfiguration] - bucket notification configuration
|
* @param [notificationConfiguration] - bucket notification configuration
|
||||||
* @param [tags] - bucket tag set
|
* @param [tags] - bucket tag set
|
||||||
|
* @param [capabilities] - capabilities for the bucket
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
name: string,
|
name: string,
|
||||||
|
@ -147,6 +184,7 @@ export default class BucketInfo {
|
||||||
objectLockConfiguration?: any,
|
objectLockConfiguration?: any,
|
||||||
notificationConfiguration?: any,
|
notificationConfiguration?: any,
|
||||||
tags?: Array<BucketTag> | [],
|
tags?: Array<BucketTag> | [],
|
||||||
|
capabilities?: Capacity,
|
||||||
) {
|
) {
|
||||||
assert.strictEqual(typeof name, 'string');
|
assert.strictEqual(typeof name, 'string');
|
||||||
assert.strictEqual(typeof owner, 'string');
|
assert.strictEqual(typeof owner, 'string');
|
||||||
|
@ -274,6 +312,7 @@ export default class BucketInfo {
|
||||||
this._objectLockConfiguration = objectLockConfiguration || null;
|
this._objectLockConfiguration = objectLockConfiguration || null;
|
||||||
this._notificationConfiguration = notificationConfiguration || null;
|
this._notificationConfiguration = notificationConfiguration || null;
|
||||||
this._tags = tags;
|
this._tags = tags;
|
||||||
|
this._capabilities = capabilities || undefined;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,6 +347,7 @@ export default class BucketInfo {
|
||||||
objectLockConfiguration: this._objectLockConfiguration,
|
objectLockConfiguration: this._objectLockConfiguration,
|
||||||
notificationConfiguration: this._notificationConfiguration,
|
notificationConfiguration: this._notificationConfiguration,
|
||||||
tags: this._tags,
|
tags: this._tags,
|
||||||
|
capabilities: this._capabilities,
|
||||||
};
|
};
|
||||||
const final = this._websiteConfiguration
|
const final = this._websiteConfiguration
|
||||||
? {
|
? {
|
||||||
|
@ -333,7 +373,8 @@ export default class BucketInfo {
|
||||||
obj.cors, obj.replicationConfiguration, obj.lifecycleConfiguration,
|
obj.cors, obj.replicationConfiguration, obj.lifecycleConfiguration,
|
||||||
obj.bucketPolicy, obj.uid, obj.readLocationConstraint, obj.isNFS,
|
obj.bucketPolicy, obj.uid, obj.readLocationConstraint, obj.isNFS,
|
||||||
obj.ingestion, obj.azureInfo, obj.objectLockEnabled,
|
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._bucketPolicy, data._uid, data._readLocationConstraint,
|
||||||
data._isNFS, data._ingestion, data._azureInfo,
|
data._isNFS, data._ingestion, data._azureInfo,
|
||||||
data._objectLockEnabled, data._objectLockConfiguration,
|
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;
|
this._tags = tags;
|
||||||
return this;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16"
|
"node": ">=16"
|
||||||
},
|
},
|
||||||
"version": "8.1.77",
|
"version": "8.1.78",
|
||||||
"description": "Common utilities for the S3 project components",
|
"description": "Common utilities for the S3 project components",
|
||||||
"main": "build/index.js",
|
"main": "build/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -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
|
// create a dummy bucket to test getters and setters
|
||||||
Object.keys(acl).forEach(
|
Object.keys(acl).forEach(
|
||||||
aclObj => describe(`different acl configurations : ${aclObj}`, () => {
|
aclObj => describe(`different acl configurations : ${aclObj}`, () => {
|
||||||
|
@ -222,6 +251,7 @@ Object.keys(acl).forEach(
|
||||||
testObjectLockConfiguration,
|
testObjectLockConfiguration,
|
||||||
testNotificationConfiguration,
|
testNotificationConfiguration,
|
||||||
testBucketTagging,
|
testBucketTagging,
|
||||||
|
testBucketCapabilities,
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('serialize/deSerialize on BucketInfo class', () => {
|
describe('serialize/deSerialize on BucketInfo class', () => {
|
||||||
|
@ -259,6 +289,7 @@ Object.keys(acl).forEach(
|
||||||
dummyBucket._objectLockConfiguration,
|
dummyBucket._objectLockConfiguration,
|
||||||
notificationConfiguration: dummyBucket._notificationConfiguration,
|
notificationConfiguration: dummyBucket._notificationConfiguration,
|
||||||
tags: dummyBucket._tags,
|
tags: dummyBucket._tags,
|
||||||
|
capabilities: dummyBucket._capabilities,
|
||||||
};
|
};
|
||||||
assert.strictEqual(serialized, JSON.stringify(bucketInfos));
|
assert.strictEqual(serialized, JSON.stringify(bucketInfos));
|
||||||
done();
|
done();
|
||||||
|
@ -307,6 +338,7 @@ Object.keys(acl).forEach(
|
||||||
_notificationConfiguration:
|
_notificationConfiguration:
|
||||||
dummyBucket._notificationConfiguration,
|
dummyBucket._notificationConfiguration,
|
||||||
_tags: dummyBucket._tags,
|
_tags: dummyBucket._tags,
|
||||||
|
_capabilities: dummyBucket._capabilities,
|
||||||
};
|
};
|
||||||
const fromObj = BucketInfo.fromObj(dataObj);
|
const fromObj = BucketInfo.fromObj(dataObj);
|
||||||
assert(fromObj instanceof BucketInfo);
|
assert(fromObj instanceof BucketInfo);
|
||||||
|
@ -452,6 +484,13 @@ Object.keys(acl).forEach(
|
||||||
assert.deepStrictEqual(dummyBucket.getNotificationConfiguration(),
|
assert.deepStrictEqual(dummyBucket.getNotificationConfiguration(),
|
||||||
testNotificationConfiguration);
|
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', () => {
|
describe('setters on BucketInfo class', () => {
|
||||||
|
@ -649,6 +688,12 @@ Object.keys(acl).forEach(
|
||||||
assert.deepStrictEqual(
|
assert.deepStrictEqual(
|
||||||
dummyBucket.getUid(), testUid);
|
dummyBucket.getUid(), testUid);
|
||||||
});
|
});
|
||||||
|
it('setCapabilities should set bucket capabilities', () => {
|
||||||
|
const testCapabilities = testBucketCapabilities;
|
||||||
|
dummyBucket.setCapabilities(testCapabilities);
|
||||||
|
assert.deepStrictEqual(
|
||||||
|
dummyBucket.getCapabilities(), testCapabilities);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue