Compare commits
9 Commits
developmen
...
improvemen
Author | SHA1 | Date |
---|---|---|
williamlardier | eb698d1bc7 | |
williamlardier | 3ddcc613ed | |
williamlardier | 5ca13df675 | |
williamlardier | e7fc18ee98 | |
williamlardier | 941941acc2 | |
williamlardier | 618c23faa9 | |
williamlardier | aaae5dae2d | |
williamlardier | 020aabdb5a | |
williamlardier | 36d652d356 |
|
@ -17,7 +17,7 @@ const { preprocessingVersioningDelete }
|
||||||
= require('./apiUtils/object/versioning');
|
= require('./apiUtils/object/versioning');
|
||||||
const createAndStoreObject = require('./apiUtils/object/createAndStoreObject');
|
const createAndStoreObject = require('./apiUtils/object/createAndStoreObject');
|
||||||
const monitoring = require('../utilities/monitoringHandler');
|
const monitoring = require('../utilities/monitoringHandler');
|
||||||
const { metadataGetObject } = require('../metadata/metadataUtils');
|
const { metadataGetObject, metadataGetObjects } = require('../metadata/metadataUtils');
|
||||||
const { config } = require('../Config');
|
const { config } = require('../Config');
|
||||||
const { isRequesterNonAccountUser } = require('./apiUtils/authorization/permissionChecks');
|
const { isRequesterNonAccountUser } = require('./apiUtils/authorization/permissionChecks');
|
||||||
const { hasGovernanceBypassHeader, checkUserGovernanceBypass, ObjectLockInfo }
|
const { hasGovernanceBypassHeader, checkUserGovernanceBypass, ObjectLockInfo }
|
||||||
|
@ -25,6 +25,8 @@ const { hasGovernanceBypassHeader, checkUserGovernanceBypass, ObjectLockInfo }
|
||||||
const requestUtils = policies.requestUtils;
|
const requestUtils = policies.requestUtils;
|
||||||
const { validObjectKeys } = require('../routes/routeVeeam');
|
const { validObjectKeys } = require('../routes/routeVeeam');
|
||||||
const { deleteVeeamCapabilities } = require('../routes/veeam/delete');
|
const { deleteVeeamCapabilities } = require('../routes/veeam/delete');
|
||||||
|
const { data } = require('../data/wrapper');
|
||||||
|
const logger = require('../utilities/logger');
|
||||||
|
|
||||||
const versionIdUtils = versioning.VersionID;
|
const versionIdUtils = versioning.VersionID;
|
||||||
|
|
||||||
|
@ -169,6 +171,27 @@ function _parseXml(xmlToParse, next) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* processObjectVersion - process object version to be deleted
|
||||||
|
* @param {object} entry - entry from data model
|
||||||
|
* @param {string} bucketName - bucket name
|
||||||
|
* @param {function} next - callback to call with error or decoded version
|
||||||
|
* @return {undefined}
|
||||||
|
**/
|
||||||
|
function processObjectVersion(entry, bucketName) {
|
||||||
|
let decodedVersionId;
|
||||||
|
if (entry.versionId) {
|
||||||
|
decodedVersionId = entry.versionId === 'null' ?
|
||||||
|
'null' : versionIdUtils.decode(entry.versionId);
|
||||||
|
}
|
||||||
|
if (decodedVersionId instanceof Error) {
|
||||||
|
monitoring.promMetrics('DELETE', bucketName, 404,
|
||||||
|
'multiObjectDelete');
|
||||||
|
return [errors.NoSuchVersion];
|
||||||
|
}
|
||||||
|
return [null, decodedVersionId];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gets object metadata and deletes object
|
* gets object metadata and deletes object
|
||||||
* @param {AuthInfo} authInfo - Instance of AuthInfo class with requester's info
|
* @param {AuthInfo} authInfo - Instance of AuthInfo class with requester's info
|
||||||
|
@ -194,165 +217,206 @@ function getObjMetadataAndDelete(authInfo, canonicalID, request,
|
||||||
let numOfObjectsRemoved = 0;
|
let numOfObjectsRemoved = 0;
|
||||||
const skipError = new Error('skip');
|
const skipError = new Error('skip');
|
||||||
const objectLockedError = new Error('object locked');
|
const objectLockedError = new Error('object locked');
|
||||||
|
let deleteFromStorage = [];
|
||||||
// doing 5 requests at a time. note that the data wrapper
|
const backendSupportsBatching = ['mongodb'].includes(config.backends.metadata);
|
||||||
// will do 5 parallel requests to data backend to delete parts
|
let initialStep = callback => callback();
|
||||||
return async.forEachLimit(inPlay, 5, (entry, moveOn) => {
|
// If the backend supports batching, we want to optimize the API latency by
|
||||||
async.waterfall([
|
// first getting all the objects metadata, stored in memory, for later use
|
||||||
callback => {
|
// in the API. This approach does not change the API architecture, but
|
||||||
let decodedVersionId;
|
// transplants an additional piece of code that can greatly improve the API
|
||||||
if (entry.versionId) {
|
// latency when the database supports batching.
|
||||||
decodedVersionId = entry.versionId === 'null' ?
|
if (backendSupportsBatching) {
|
||||||
'null' : versionIdUtils.decode(entry.versionId);
|
const objectKeys = Object.keys(inPlay).map(entry => {
|
||||||
}
|
const [err, versionId] = processObjectVersion(inPlay[entry], bucketName);
|
||||||
if (decodedVersionId instanceof Error) {
|
if (err) {
|
||||||
monitoring.promMetrics('DELETE', bucketName, 404,
|
return null;
|
||||||
'multiObjectDelete');
|
|
||||||
return callback(errors.NoSuchVersion);
|
|
||||||
}
|
|
||||||
return callback(null, decodedVersionId);
|
|
||||||
},
|
|
||||||
// for obj deletes, no need to check acl's at object level
|
|
||||||
// (authority is at the bucket level for obj deletes)
|
|
||||||
(versionId, callback) => metadataGetObject(bucketName, entry.key,
|
|
||||||
versionId, log, (err, objMD) => {
|
|
||||||
// if general error from metadata return error
|
|
||||||
if (err) {
|
|
||||||
monitoring.promMetrics('DELETE', bucketName, err.code,
|
|
||||||
'multiObjectDelete');
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
if (!objMD) {
|
|
||||||
const verCfg = bucket.getVersioningConfiguration();
|
|
||||||
// To adhere to AWS behavior, create a delete marker
|
|
||||||
// if trying to delete an object that does not exist
|
|
||||||
// when versioning has been configured
|
|
||||||
if (verCfg && !entry.versionId) {
|
|
||||||
log.debug('trying to delete specific version ' +
|
|
||||||
' that does not exist');
|
|
||||||
return callback(null, objMD, versionId);
|
|
||||||
}
|
|
||||||
// otherwise if particular key does not exist, AWS
|
|
||||||
// returns success for key so add to successfullyDeleted
|
|
||||||
// list and move on
|
|
||||||
successfullyDeleted.push({ entry });
|
|
||||||
return callback(skipError);
|
|
||||||
}
|
|
||||||
if (versionId && objMD.location &&
|
|
||||||
Array.isArray(objMD.location) && objMD.location[0]) {
|
|
||||||
// we need this information for data deletes to AWS
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
|
||||||
objMD.location[0].deleteVersion = true;
|
|
||||||
}
|
|
||||||
return callback(null, objMD, versionId);
|
|
||||||
}),
|
|
||||||
(objMD, versionId, callback) => {
|
|
||||||
// AWS only returns an object lock error if a version id
|
|
||||||
// is specified, else continue to create a delete marker
|
|
||||||
if (!versionId || !bucket.isObjectLockEnabled()) {
|
|
||||||
return callback(null, null, objMD, versionId);
|
|
||||||
}
|
|
||||||
const hasGovernanceBypass = hasGovernanceBypassHeader(request.headers);
|
|
||||||
if (hasGovernanceBypass && isRequesterNonAccountUser(authInfo)) {
|
|
||||||
return checkUserGovernanceBypass(request, authInfo, bucket, entry.key, log, error => {
|
|
||||||
if (error && error.is.AccessDenied) {
|
|
||||||
log.debug('user does not have BypassGovernanceRetention and object is locked', { error });
|
|
||||||
return callback(objectLockedError);
|
|
||||||
}
|
|
||||||
if (error) {
|
|
||||||
return callback(error);
|
|
||||||
}
|
|
||||||
return callback(null, hasGovernanceBypass, objMD, versionId);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return callback(null, hasGovernanceBypass, objMD, versionId);
|
|
||||||
},
|
|
||||||
(hasGovernanceBypass, objMD, versionId, callback) => {
|
|
||||||
// AWS only returns an object lock error if a version id
|
|
||||||
// is specified, else continue to create a delete marker
|
|
||||||
if (!versionId || !bucket.isObjectLockEnabled()) {
|
|
||||||
return callback(null, objMD, versionId);
|
|
||||||
}
|
|
||||||
const objLockInfo = new ObjectLockInfo({
|
|
||||||
mode: objMD.retentionMode,
|
|
||||||
date: objMD.retentionDate,
|
|
||||||
legalHold: objMD.legalHold || false,
|
|
||||||
});
|
|
||||||
|
|
||||||
// If the object can not be deleted raise an error
|
|
||||||
if (!objLockInfo.canModifyObject(hasGovernanceBypass)) {
|
|
||||||
log.debug('trying to delete locked object');
|
|
||||||
return callback(objectLockedError);
|
|
||||||
}
|
|
||||||
|
|
||||||
return callback(null, objMD, versionId);
|
|
||||||
},
|
|
||||||
(objMD, versionId, callback) => {
|
|
||||||
const options = preprocessingVersioningDelete(
|
|
||||||
bucketName, bucket, objMD, versionId, config.nullVersionCompatMode);
|
|
||||||
const deleteInfo = {};
|
|
||||||
if (options && options.deleteData) {
|
|
||||||
deleteInfo.deleted = true;
|
|
||||||
if (objMD.uploadId) {
|
|
||||||
// eslint-disable-next-line
|
|
||||||
options.replayId = objMD.uploadId;
|
|
||||||
}
|
|
||||||
return services.deleteObject(bucketName, objMD,
|
|
||||||
entry.key, options, log, 's3:ObjectRemoved:Delete', err =>
|
|
||||||
callback(err, objMD, deleteInfo));
|
|
||||||
}
|
|
||||||
deleteInfo.newDeleteMarker = true;
|
|
||||||
// This call will create a delete-marker
|
|
||||||
return createAndStoreObject(bucketName, bucket, entry.key,
|
|
||||||
objMD, authInfo, canonicalID, null, request,
|
|
||||||
deleteInfo.newDeleteMarker, null, log, 's3:ObjectRemoved:DeleteMarkerCreated',
|
|
||||||
(err, result) =>
|
|
||||||
callback(err, objMD, deleteInfo, result.versionId));
|
|
||||||
},
|
|
||||||
], (err, objMD, deleteInfo, versionId) => {
|
|
||||||
if (err === skipError) {
|
|
||||||
return moveOn();
|
|
||||||
} else if (err === objectLockedError) {
|
|
||||||
errorResults.push({ entry, error: errors.AccessDenied, objectLocked: true });
|
|
||||||
return moveOn();
|
|
||||||
} else if (err) {
|
|
||||||
log.error('error deleting object', { error: err, entry });
|
|
||||||
errorResults.push({ entry, error: err });
|
|
||||||
return moveOn();
|
|
||||||
}
|
}
|
||||||
if (deleteInfo.deleted && objMD['content-length']) {
|
return {
|
||||||
numOfObjectsRemoved++;
|
versionId,
|
||||||
totalContentLengthDeleted += objMD['content-length'];
|
inPlay: inPlay[entry],
|
||||||
}
|
};
|
||||||
let isDeleteMarker;
|
});
|
||||||
let deleteMarkerVersionId;
|
initialStep = callback => metadataGetObjects(bucketName, objectKeys, log, callback);
|
||||||
// - If trying to delete an object that does not exist (if a new
|
}
|
||||||
// delete marker was created)
|
|
||||||
// - Or if an object exists but no version was specified
|
return initialStep((err, cache) => {
|
||||||
// return DeleteMarkerVersionId equals the versionID of the marker
|
if (err) {
|
||||||
// you just generated and DeleteMarker tag equals true
|
return next(err);
|
||||||
if (deleteInfo.newDeleteMarker) {
|
}
|
||||||
isDeleteMarker = true;
|
// doing 5 requests at a time. note that the data wrapper
|
||||||
deleteMarkerVersionId = versionIdUtils.encode(versionId);
|
// will do 5 parallel requests to data backend to delete parts
|
||||||
// In this case we are putting a new object (i.e., the delete
|
return async.forEachLimit(inPlay, 50, (entry, moveOn) => {
|
||||||
// marker), so we decrement the numOfObjectsRemoved value.
|
async.waterfall([
|
||||||
numOfObjectsRemoved--;
|
callback => callback(...processObjectVersion(entry, bucketName)),
|
||||||
// If trying to delete a delete marker, DeleteMarkerVersionId equals
|
// for obj deletes, no need to check acl's at object level
|
||||||
// deleteMarker's versionID and DeleteMarker equals true
|
// (authority is at the bucket level for obj deletes)
|
||||||
} else if (objMD && objMD.isDeleteMarker) {
|
(versionId, callback) => metadataGetObject(bucketName, entry.key,
|
||||||
isDeleteMarker = true;
|
versionId, log, (err, objMD) => {
|
||||||
deleteMarkerVersionId = entry.versionId;
|
// if general error from metadata return error
|
||||||
}
|
if (err) {
|
||||||
successfullyDeleted.push({ entry, isDeleteMarker,
|
monitoring.promMetrics('DELETE', bucketName, err.code,
|
||||||
deleteMarkerVersionId });
|
'multiObjectDelete');
|
||||||
return moveOn();
|
return callback(err);
|
||||||
|
}
|
||||||
|
if (!objMD) {
|
||||||
|
const verCfg = bucket.getVersioningConfiguration();
|
||||||
|
// To adhere to AWS behavior, create a delete marker
|
||||||
|
// if trying to delete an object that does not exist
|
||||||
|
// when versioning has been configured
|
||||||
|
if (verCfg && !entry.versionId) {
|
||||||
|
log.debug('trying to delete specific version ' +
|
||||||
|
' that does not exist');
|
||||||
|
return callback(null, objMD, versionId);
|
||||||
|
}
|
||||||
|
// otherwise if particular key does not exist, AWS
|
||||||
|
// returns success for key so add to successfullyDeleted
|
||||||
|
// list and move on
|
||||||
|
successfullyDeleted.push({ entry });
|
||||||
|
return callback(skipError);
|
||||||
|
}
|
||||||
|
if (versionId && objMD.location &&
|
||||||
|
Array.isArray(objMD.location) && objMD.location[0]) {
|
||||||
|
// we need this information for data deletes to AWS
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
objMD.location[0].deleteVersion = true;
|
||||||
|
}
|
||||||
|
return callback(null, objMD, versionId);
|
||||||
|
}, cache?.[`${entry.key}${versionId}`]),
|
||||||
|
(objMD, versionId, callback) => {
|
||||||
|
// AWS only returns an object lock error if a version id
|
||||||
|
// is specified, else continue to create a delete marker
|
||||||
|
if (!versionId || !bucket.isObjectLockEnabled()) {
|
||||||
|
return callback(null, null, objMD, versionId);
|
||||||
|
}
|
||||||
|
const hasGovernanceBypass = hasGovernanceBypassHeader(request.headers);
|
||||||
|
if (hasGovernanceBypass && isRequesterNonAccountUser(authInfo)) {
|
||||||
|
return checkUserGovernanceBypass(request, authInfo, bucket, entry.key, log, error => {
|
||||||
|
if (error && error.is.AccessDenied) {
|
||||||
|
log.debug('user does not have BypassGovernanceRetention and object is locked',
|
||||||
|
{ error });
|
||||||
|
return callback(objectLockedError);
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
return callback(error);
|
||||||
|
}
|
||||||
|
return callback(null, hasGovernanceBypass, objMD, versionId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return callback(null, hasGovernanceBypass, objMD, versionId);
|
||||||
|
},
|
||||||
|
(hasGovernanceBypass, objMD, versionId, callback) => {
|
||||||
|
// AWS only returns an object lock error if a version id
|
||||||
|
// is specified, else continue to create a delete marker
|
||||||
|
if (!versionId || !bucket.isObjectLockEnabled()) {
|
||||||
|
return callback(null, objMD, versionId);
|
||||||
|
}
|
||||||
|
const objLockInfo = new ObjectLockInfo({
|
||||||
|
mode: objMD.retentionMode,
|
||||||
|
date: objMD.retentionDate,
|
||||||
|
legalHold: objMD.legalHold || false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// If the object can not be deleted raise an error
|
||||||
|
if (!objLockInfo.canModifyObject(hasGovernanceBypass)) {
|
||||||
|
log.debug('trying to delete locked object');
|
||||||
|
return callback(objectLockedError);
|
||||||
|
}
|
||||||
|
|
||||||
|
return callback(null, objMD, versionId);
|
||||||
|
},
|
||||||
|
(objMD, versionId, callback) => {
|
||||||
|
const options = preprocessingVersioningDelete(
|
||||||
|
bucketName, bucket, objMD, versionId, config.nullVersionCompatMode);
|
||||||
|
const deleteInfo = {};
|
||||||
|
if (options && options.deleteData) {
|
||||||
|
deleteInfo.deleted = true;
|
||||||
|
if (!bucket.getLifecycleConfiguration?.() && !bucket.getNotificationConfiguration?.()) {
|
||||||
|
options.shouldOnlyDelete = true;
|
||||||
|
}
|
||||||
|
if (objMD.uploadId) {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
options.replayId = objMD.uploadId;
|
||||||
|
}
|
||||||
|
return services.deleteObject(bucketName, objMD,
|
||||||
|
entry.key, options, log, 's3:ObjectRemoved:Delete', (err, toDelete) => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
if (toDelete) {
|
||||||
|
deleteFromStorage = deleteFromStorage.concat(toDelete);
|
||||||
|
}
|
||||||
|
return callback(null, objMD, deleteInfo);
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
deleteInfo.newDeleteMarker = true;
|
||||||
|
// This call will create a delete-marker
|
||||||
|
return createAndStoreObject(bucketName, bucket, entry.key,
|
||||||
|
objMD, authInfo, canonicalID, null, request,
|
||||||
|
deleteInfo.newDeleteMarker, null, log, 's3:ObjectRemoved:DeleteMarkerCreated',
|
||||||
|
(err, result) =>
|
||||||
|
callback(err, objMD, deleteInfo, result.versionId));
|
||||||
|
},
|
||||||
|
], (err, objMD, deleteInfo, versionId) => {
|
||||||
|
if (err === skipError) {
|
||||||
|
return moveOn();
|
||||||
|
} else if (err === objectLockedError) {
|
||||||
|
errorResults.push({ entry, error: errors.AccessDenied, objectLocked: true });
|
||||||
|
return moveOn();
|
||||||
|
} else if (err) {
|
||||||
|
log.error('error deleting object', { error: err, entry });
|
||||||
|
errorResults.push({ entry, error: err });
|
||||||
|
return moveOn();
|
||||||
|
}
|
||||||
|
if (deleteInfo.deleted && objMD['content-length']) {
|
||||||
|
numOfObjectsRemoved++;
|
||||||
|
totalContentLengthDeleted += objMD['content-length'];
|
||||||
|
}
|
||||||
|
let isDeleteMarker;
|
||||||
|
let deleteMarkerVersionId;
|
||||||
|
// - If trying to delete an object that does not exist (if a new
|
||||||
|
// delete marker was created)
|
||||||
|
// - Or if an object exists but no version was specified
|
||||||
|
// return DeleteMarkerVersionId equals the versionID of the marker
|
||||||
|
// you just generated and DeleteMarker tag equals true
|
||||||
|
if (deleteInfo.newDeleteMarker) {
|
||||||
|
isDeleteMarker = true;
|
||||||
|
deleteMarkerVersionId = versionIdUtils.encode(versionId);
|
||||||
|
// In this case we are putting a new object (i.e., the delete
|
||||||
|
// marker), so we decrement the numOfObjectsRemoved value.
|
||||||
|
numOfObjectsRemoved--;
|
||||||
|
// If trying to delete a delete marker, DeleteMarkerVersionId equals
|
||||||
|
// deleteMarker's versionID and DeleteMarker equals true
|
||||||
|
} else if (objMD && objMD.isDeleteMarker) {
|
||||||
|
isDeleteMarker = true;
|
||||||
|
deleteMarkerVersionId = entry.versionId;
|
||||||
|
}
|
||||||
|
successfullyDeleted.push({ entry, isDeleteMarker,
|
||||||
|
deleteMarkerVersionId });
|
||||||
|
return moveOn();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// end of forEach func
|
||||||
|
err => {
|
||||||
|
// Batch delete all objects
|
||||||
|
const onDone = () => next(err, quietSetting, errorResults, numOfObjectsRemoved,
|
||||||
|
successfullyDeleted, totalContentLengthDeleted, bucket);
|
||||||
|
|
||||||
|
if (err && deleteFromStorage.length === 0) {
|
||||||
|
log.trace('no objects to delete from data backend');
|
||||||
|
return onDone();
|
||||||
|
}
|
||||||
|
// If error but we have objects in the list, delete them to ensure
|
||||||
|
// consistent state.
|
||||||
|
log.trace('deleting objects from data backend');
|
||||||
|
const deleteLog = logger.newRequestLoggerFromSerializedUids(log.getSerializedUids());
|
||||||
|
return data.batchDelete(deleteFromStorage, null, null, deleteLog, err => {
|
||||||
|
if (err) {
|
||||||
|
log.error('error deleting objects from data backend', { error: err });
|
||||||
|
return onDone();
|
||||||
|
}
|
||||||
|
return onDone();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
|
||||||
// end of forEach func
|
|
||||||
err => {
|
|
||||||
log.trace('finished deleting objects', { numOfObjectsRemoved });
|
|
||||||
return next(err, quietSetting, errorResults, numOfObjectsRemoved,
|
|
||||||
successfullyDeleted, totalContentLengthDeleted, bucket);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,11 +62,16 @@ function getNullVersionFromMaster(bucketName, objectKey, log, cb) {
|
||||||
* @param {string} [versionId] - version of object to retrieve
|
* @param {string} [versionId] - version of object to retrieve
|
||||||
* @param {RequestLogger} log - request logger
|
* @param {RequestLogger} log - request logger
|
||||||
* @param {function} cb - callback
|
* @param {function} cb - callback
|
||||||
|
* @param {object} cachedDocument - cached version of the document used for
|
||||||
|
* abstraction purposes
|
||||||
* @return {undefined} - and call callback with err, bucket md and object md
|
* @return {undefined} - and call callback with err, bucket md and object md
|
||||||
*/
|
*/
|
||||||
function metadataGetObject(bucketName, objectKey, versionId, log, cb) {
|
function metadataGetObject(bucketName, objectKey, versionId, log, cb, cachedDocument = null) {
|
||||||
// versionId may be 'null', which asks metadata to fetch the null key specifically
|
// versionId may be 'null', which asks metadata to fetch the null key specifically
|
||||||
const options = { versionId, getDeleteMarker: true };
|
const options = { versionId, getDeleteMarker: true };
|
||||||
|
if (cachedDocument) {
|
||||||
|
return cb(null, cachedDocument);
|
||||||
|
}
|
||||||
return metadata.getObjectMD(bucketName, objectKey, options, log,
|
return metadata.getObjectMD(bucketName, objectKey, options, log,
|
||||||
(err, objMD) => {
|
(err, objMD) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -84,6 +89,40 @@ function metadataGetObject(bucketName, objectKey, versionId, log, cb) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** metadataGetObjects - retrieves specified object or version from metadata. This
|
||||||
|
* method uses cursors, hence is only compatible with a MongoDB DB backend.
|
||||||
|
* @param {string} bucketName - name of bucket
|
||||||
|
* @param {string} objectsKeys - name of object key
|
||||||
|
* @param {RequestLogger} log - request logger
|
||||||
|
* @param {function} cb - callback
|
||||||
|
* @return {undefined} - and call callback with err, bucket md and object md
|
||||||
|
*/
|
||||||
|
function metadataGetObjects(bucketName, objectsKeys, log, cb) {
|
||||||
|
const options = { getDeleteMarker: true };
|
||||||
|
const objects = objectsKeys.map(objectKey => ({
|
||||||
|
key: objectKey?.inPlay.key,
|
||||||
|
params: options,
|
||||||
|
versionId: objectKey?.versionId,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Returned objects are following the following format: { key, doc, versionId }
|
||||||
|
// That is required with batching to properly map the objects
|
||||||
|
return metadata.getObjectsMD(bucketName, objects, log, (err, objMds) => {
|
||||||
|
if (err) {
|
||||||
|
log.debug('err getting object MD from metadata', { error: err });
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = {};
|
||||||
|
objMds.forEach(objMd => {
|
||||||
|
if (objMd.doc) {
|
||||||
|
result[`${objMd.doc.key}${objMd.versionId}`] = objMd.doc;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return cb(null, result);
|
||||||
|
});
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Validate that a bucket is accessible and authorized to the user,
|
* Validate that a bucket is accessible and authorized to the user,
|
||||||
* return a specific error code otherwise
|
* return a specific error code otherwise
|
||||||
|
@ -215,6 +254,7 @@ function metadataValidateBucket(params, log, callback) {
|
||||||
module.exports = {
|
module.exports = {
|
||||||
validateBucket,
|
validateBucket,
|
||||||
metadataGetObject,
|
metadataGetObject,
|
||||||
|
metadataGetObjects,
|
||||||
metadataValidateBucketAndObj,
|
metadataValidateBucketAndObj,
|
||||||
metadataValidateBucket,
|
metadataValidateBucket,
|
||||||
};
|
};
|
||||||
|
|
|
@ -309,9 +309,12 @@ const services = {
|
||||||
* @param {Log} log - logger instance
|
* @param {Log} log - logger instance
|
||||||
* @param {string} originOp - origin operation
|
* @param {string} originOp - origin operation
|
||||||
* @param {function} cb - callback from async.waterfall in objectGet
|
* @param {function} cb - callback from async.waterfall in objectGet
|
||||||
|
* @param {boolean} deferDeletion - true if the object should not be removed
|
||||||
|
* from the storage, but be returned
|
||||||
|
* instead.
|
||||||
* @return {undefined}
|
* @return {undefined}
|
||||||
*/
|
*/
|
||||||
deleteObject(bucketName, objectMD, objectKey, options, log, originOp, cb) {
|
deleteObject(bucketName, objectMD, objectKey, options, log, originOp, cb, deferDeletion) {
|
||||||
log.trace('deleting object from bucket');
|
log.trace('deleting object from bucket');
|
||||||
assert.strictEqual(typeof bucketName, 'string');
|
assert.strictEqual(typeof bucketName, 'string');
|
||||||
assert.strictEqual(typeof objectMD, 'object');
|
assert.strictEqual(typeof objectMD, 'object');
|
||||||
|
@ -328,12 +331,16 @@ const services = {
|
||||||
log.getSerializedUids());
|
log.getSerializedUids());
|
||||||
if (objectMD.location === null) {
|
if (objectMD.location === null) {
|
||||||
return cb(null, res);
|
return cb(null, res);
|
||||||
} else if (!Array.isArray(objectMD.location)) {
|
|
||||||
data.delete(objectMD.location, deleteLog);
|
|
||||||
return cb(null, res);
|
|
||||||
}
|
}
|
||||||
return data.batchDelete(objectMD.location, null, null,
|
|
||||||
deleteLog, err => {
|
const locations = Array.isArray(objectMD.location)
|
||||||
|
? objectMD.location : [objectMD.location];
|
||||||
|
|
||||||
|
if (deferDeletion) {
|
||||||
|
return cb(null, locations);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.batchDelete(locations, null, null, deleteLog, err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return cb(err);
|
return cb(err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@azure/storage-blob": "^12.12.0",
|
"@azure/storage-blob": "^12.12.0",
|
||||||
"@hapi/joi": "^17.1.0",
|
"@hapi/joi": "^17.1.0",
|
||||||
"arsenal": "git+https://github.com/scality/arsenal#8.1.101",
|
"arsenal": "git+https://github.com/scality/arsenal#6b5139ebaae770b7c212c796405c6bcfd0db3e37",
|
||||||
"async": "~2.5.0",
|
"async": "~2.5.0",
|
||||||
"aws-sdk": "2.905.0",
|
"aws-sdk": "2.905.0",
|
||||||
"bucketclient": "scality/bucketclient#8.1.9",
|
"bucketclient": "scality/bucketclient#8.1.9",
|
||||||
|
|
148
yarn.lock
148
yarn.lock
|
@ -399,6 +399,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz#5981a8db18b56ba38ef0efb7d995b12aa7b51918"
|
resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz#5981a8db18b56ba38ef0efb7d995b12aa7b51918"
|
||||||
integrity sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==
|
integrity sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==
|
||||||
|
|
||||||
|
"@socket.io/component-emitter@~3.1.0":
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553"
|
||||||
|
integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==
|
||||||
|
|
||||||
"@tootallnate/once@1":
|
"@tootallnate/once@1":
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||||
|
@ -414,6 +419,18 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/async/-/async-3.2.20.tgz#53517caaa68c94f99da1c4e986cf7f2954981515"
|
resolved "https://registry.yarnpkg.com/@types/async/-/async-3.2.20.tgz#53517caaa68c94f99da1c4e986cf7f2954981515"
|
||||||
integrity sha512-6jSBQQugzyX1aWto0CbvOnmxrU9tMoXfA9gc4IrLEtvr3dTwSg5GLGoWiZnGLI6UG/kqpB3JOQKQrqnhUWGKQA==
|
integrity sha512-6jSBQQugzyX1aWto0CbvOnmxrU9tMoXfA9gc4IrLEtvr3dTwSg5GLGoWiZnGLI6UG/kqpB3JOQKQrqnhUWGKQA==
|
||||||
|
|
||||||
|
"@types/cookie@^0.4.1":
|
||||||
|
version "0.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d"
|
||||||
|
integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==
|
||||||
|
|
||||||
|
"@types/cors@^2.8.12":
|
||||||
|
version "2.8.13"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.13.tgz#b8ade22ba455a1b8cb3b5d3f35910fd204f84f94"
|
||||||
|
integrity sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/json5@^0.0.29":
|
"@types/json5@^0.0.29":
|
||||||
version "0.0.29"
|
version "0.0.29"
|
||||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||||
|
@ -432,6 +449,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.2.3.tgz#b31eb300610c3835ac008d690de6f87e28f9b878"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.2.3.tgz#b31eb300610c3835ac008d690de6f87e28f9b878"
|
||||||
integrity sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw==
|
integrity sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw==
|
||||||
|
|
||||||
|
"@types/node@>=10.0.0":
|
||||||
|
version "20.2.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.2.5.tgz#26d295f3570323b2837d322180dfbf1ba156fefb"
|
||||||
|
integrity sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==
|
||||||
|
|
||||||
"@types/triple-beam@^1.3.2":
|
"@types/triple-beam@^1.3.2":
|
||||||
version "1.3.2"
|
version "1.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.2.tgz#38ecb64f01aa0d02b7c8f4222d7c38af6316fef8"
|
resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.2.tgz#38ecb64f01aa0d02b7c8f4222d7c38af6316fef8"
|
||||||
|
@ -767,9 +789,9 @@ arraybuffer.slice@~0.0.7:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
ioctl "^2.0.2"
|
ioctl "^2.0.2"
|
||||||
|
|
||||||
"arsenal@git+https://github.com/scality/arsenal#8.1.101":
|
"arsenal@git+https://github.com/scality/arsenal#6b5139ebaae770b7c212c796405c6bcfd0db3e37":
|
||||||
version "8.1.101"
|
version "8.1.101"
|
||||||
resolved "git+https://github.com/scality/arsenal#25be9014c9af1bd3ea6bf6f2f30f4cc30f5586eb"
|
resolved "git+https://github.com/scality/arsenal#6b5139ebaae770b7c212c796405c6bcfd0db3e37"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@azure/identity" "^3.1.1"
|
"@azure/identity" "^3.1.1"
|
||||||
"@azure/storage-blob" "^12.12.0"
|
"@azure/storage-blob" "^12.12.0"
|
||||||
|
@ -799,8 +821,8 @@ arraybuffer.slice@~0.0.7:
|
||||||
node-forge "^1.3.0"
|
node-forge "^1.3.0"
|
||||||
prom-client "14.2.0"
|
prom-client "14.2.0"
|
||||||
simple-glob "^0.2.0"
|
simple-glob "^0.2.0"
|
||||||
socket.io "2.4.1"
|
socket.io "~4.6.1"
|
||||||
socket.io-client "2.4.0"
|
socket.io-client "~4.6.1"
|
||||||
sproxydclient "git+https://github.com/scality/sproxydclient#8.0.9"
|
sproxydclient "git+https://github.com/scality/sproxydclient#8.0.9"
|
||||||
utf8 "3.0.0"
|
utf8 "3.0.0"
|
||||||
uuid "^3.0.1"
|
uuid "^3.0.1"
|
||||||
|
@ -1025,7 +1047,7 @@ base64-js@^1.0.2, base64-js@^1.3.1:
|
||||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||||
|
|
||||||
base64id@2.0.0:
|
base64id@2.0.0, base64id@~2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
|
resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
|
||||||
integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==
|
integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==
|
||||||
|
@ -1460,6 +1482,14 @@ core-util-is@~1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
|
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
|
||||||
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
|
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
|
||||||
|
|
||||||
|
cors@~2.8.5:
|
||||||
|
version "2.8.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
|
||||||
|
integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
|
||||||
|
dependencies:
|
||||||
|
object-assign "^4"
|
||||||
|
vary "^1"
|
||||||
|
|
||||||
cron-parser@^2.11.0, cron-parser@^2.15.0, cron-parser@^2.18.0:
|
cron-parser@^2.11.0, cron-parser@^2.15.0, cron-parser@^2.18.0:
|
||||||
version "2.18.0"
|
version "2.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.18.0.tgz#de1bb0ad528c815548371993f81a54e5a089edcf"
|
resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.18.0.tgz#de1bb0ad528c815548371993f81a54e5a089edcf"
|
||||||
|
@ -1532,7 +1562,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.6.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms "2.0.0"
|
ms "2.0.0"
|
||||||
|
|
||||||
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3:
|
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@~4.3.1, debug@~4.3.2:
|
||||||
version "4.3.4"
|
version "4.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||||
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
||||||
|
@ -1733,6 +1763,17 @@ engine.io-client@~3.5.0:
|
||||||
xmlhttprequest-ssl "~1.6.2"
|
xmlhttprequest-ssl "~1.6.2"
|
||||||
yeast "0.1.2"
|
yeast "0.1.2"
|
||||||
|
|
||||||
|
engine.io-client@~6.4.0:
|
||||||
|
version "6.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.4.0.tgz#88cd3082609ca86d7d3c12f0e746d12db4f47c91"
|
||||||
|
integrity sha512-GyKPDyoEha+XZ7iEqam49vz6auPnNJ9ZBfy89f+rMMas8AuiMWOZ9PVzu8xb9ZC6rafUqiGHSCfu22ih66E+1g==
|
||||||
|
dependencies:
|
||||||
|
"@socket.io/component-emitter" "~3.1.0"
|
||||||
|
debug "~4.3.1"
|
||||||
|
engine.io-parser "~5.0.3"
|
||||||
|
ws "~8.11.0"
|
||||||
|
xmlhttprequest-ssl "~2.0.0"
|
||||||
|
|
||||||
engine.io-parser@~2.2.0:
|
engine.io-parser@~2.2.0:
|
||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.1.tgz#57ce5611d9370ee94f99641b589f94c97e4f5da7"
|
resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.1.tgz#57ce5611d9370ee94f99641b589f94c97e4f5da7"
|
||||||
|
@ -1744,6 +1785,11 @@ engine.io-parser@~2.2.0:
|
||||||
blob "0.0.5"
|
blob "0.0.5"
|
||||||
has-binary2 "~1.0.2"
|
has-binary2 "~1.0.2"
|
||||||
|
|
||||||
|
engine.io-parser@~5.0.3:
|
||||||
|
version "5.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.7.tgz#ed5eae76c71f398284c578ab6deafd3ba7e4e4f6"
|
||||||
|
integrity sha512-P+jDFbvK6lE3n1OL+q9KuzdOFWkkZ/cMV9gol/SbVfpyqfvrfrFTOFJ6fQm2VC3PZHlU3QPhVwmbsCnauHF2MQ==
|
||||||
|
|
||||||
engine.io@~3.5.0:
|
engine.io@~3.5.0:
|
||||||
version "3.5.0"
|
version "3.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.5.0.tgz#9d6b985c8a39b1fe87cd91eb014de0552259821b"
|
resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.5.0.tgz#9d6b985c8a39b1fe87cd91eb014de0552259821b"
|
||||||
|
@ -1756,6 +1802,22 @@ engine.io@~3.5.0:
|
||||||
engine.io-parser "~2.2.0"
|
engine.io-parser "~2.2.0"
|
||||||
ws "~7.4.2"
|
ws "~7.4.2"
|
||||||
|
|
||||||
|
engine.io@~6.4.2:
|
||||||
|
version "6.4.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.4.2.tgz#ffeaf68f69b1364b0286badddf15ff633476473f"
|
||||||
|
integrity sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==
|
||||||
|
dependencies:
|
||||||
|
"@types/cookie" "^0.4.1"
|
||||||
|
"@types/cors" "^2.8.12"
|
||||||
|
"@types/node" ">=10.0.0"
|
||||||
|
accepts "~1.3.4"
|
||||||
|
base64id "2.0.0"
|
||||||
|
cookie "~0.4.1"
|
||||||
|
cors "~2.8.5"
|
||||||
|
debug "~4.3.1"
|
||||||
|
engine.io-parser "~5.0.3"
|
||||||
|
ws "~8.11.0"
|
||||||
|
|
||||||
entities@~2.0.0:
|
entities@~2.0.0:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f"
|
resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f"
|
||||||
|
@ -1969,14 +2031,26 @@ eslint-plugin-mocha@^10.1.0:
|
||||||
eslint-utils "^3.0.0"
|
eslint-utils "^3.0.0"
|
||||||
rambda "^7.1.0"
|
rambda "^7.1.0"
|
||||||
|
|
||||||
eslint-scope@^7.1.1:
|
eslint-scope@^7.2.0:
|
||||||
version "7.1.1"
|
version "7.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642"
|
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b"
|
||||||
integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==
|
integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==
|
||||||
dependencies:
|
dependencies:
|
||||||
esrecurse "^4.3.0"
|
esrecurse "^4.3.0"
|
||||||
estraverse "^5.2.0"
|
estraverse "^5.2.0"
|
||||||
|
|
||||||
|
eslint-utils@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672"
|
||||||
|
integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==
|
||||||
|
dependencies:
|
||||||
|
eslint-visitor-keys "^2.0.0"
|
||||||
|
|
||||||
|
eslint-visitor-keys@^2.0.0:
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
|
||||||
|
integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
|
||||||
|
|
||||||
eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1:
|
eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1:
|
||||||
version "3.4.1"
|
version "3.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994"
|
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994"
|
||||||
|
@ -4312,6 +4386,11 @@ oauth-sign@~0.9.0:
|
||||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||||
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
|
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
|
||||||
|
|
||||||
|
object-assign@^4:
|
||||||
|
version "4.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||||
|
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
|
||||||
|
|
||||||
object-inspect@^1.12.3, object-inspect@^1.9.0:
|
object-inspect@^1.12.3, object-inspect@^1.9.0:
|
||||||
version "1.12.3"
|
version "1.12.3"
|
||||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9"
|
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9"
|
||||||
|
@ -5078,6 +5157,13 @@ socket.io-adapter@~1.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9"
|
resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9"
|
||||||
integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==
|
integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==
|
||||||
|
|
||||||
|
socket.io-adapter@~2.5.2:
|
||||||
|
version "2.5.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz#5de9477c9182fdc171cd8c8364b9a8894ec75d12"
|
||||||
|
integrity sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==
|
||||||
|
dependencies:
|
||||||
|
ws "~8.11.0"
|
||||||
|
|
||||||
socket.io-client@2.4.0:
|
socket.io-client@2.4.0:
|
||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.4.0.tgz#aafb5d594a3c55a34355562fc8aea22ed9119a35"
|
resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.4.0.tgz#aafb5d594a3c55a34355562fc8aea22ed9119a35"
|
||||||
|
@ -5095,6 +5181,16 @@ socket.io-client@2.4.0:
|
||||||
socket.io-parser "~3.3.0"
|
socket.io-parser "~3.3.0"
|
||||||
to-array "0.1.4"
|
to-array "0.1.4"
|
||||||
|
|
||||||
|
socket.io-client@~4.6.1:
|
||||||
|
version "4.6.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.6.2.tgz#2bfde952e74625d54e622718a7cb1d591ee62fd6"
|
||||||
|
integrity sha512-OwWrMbbA8wSqhBAR0yoPK6EdQLERQAYjXb3A0zLpgxfM1ZGLKoxHx8gVmCHA6pcclRX5oA/zvQf7bghAS11jRA==
|
||||||
|
dependencies:
|
||||||
|
"@socket.io/component-emitter" "~3.1.0"
|
||||||
|
debug "~4.3.2"
|
||||||
|
engine.io-client "~6.4.0"
|
||||||
|
socket.io-parser "~4.2.4"
|
||||||
|
|
||||||
socket.io-parser@~3.3.0:
|
socket.io-parser@~3.3.0:
|
||||||
version "3.3.3"
|
version "3.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.3.tgz#3a8b84823eba87f3f7624e64a8aaab6d6318a72f"
|
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.3.tgz#3a8b84823eba87f3f7624e64a8aaab6d6318a72f"
|
||||||
|
@ -5113,6 +5209,14 @@ socket.io-parser@~3.4.0:
|
||||||
debug "~4.1.0"
|
debug "~4.1.0"
|
||||||
isarray "2.0.1"
|
isarray "2.0.1"
|
||||||
|
|
||||||
|
socket.io-parser@~4.2.4:
|
||||||
|
version "4.2.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83"
|
||||||
|
integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==
|
||||||
|
dependencies:
|
||||||
|
"@socket.io/component-emitter" "~3.1.0"
|
||||||
|
debug "~4.3.1"
|
||||||
|
|
||||||
socket.io@2.4.1:
|
socket.io@2.4.1:
|
||||||
version "2.4.1"
|
version "2.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.4.1.tgz#95ad861c9a52369d7f1a68acf0d4a1b16da451d2"
|
resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.4.1.tgz#95ad861c9a52369d7f1a68acf0d4a1b16da451d2"
|
||||||
|
@ -5125,6 +5229,18 @@ socket.io@2.4.1:
|
||||||
socket.io-client "2.4.0"
|
socket.io-client "2.4.0"
|
||||||
socket.io-parser "~3.4.0"
|
socket.io-parser "~3.4.0"
|
||||||
|
|
||||||
|
socket.io@~4.6.1:
|
||||||
|
version "4.6.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.6.2.tgz#d597db077d4df9cbbdfaa7a9ed8ccc3d49439786"
|
||||||
|
integrity sha512-Vp+lSks5k0dewYTfwgPT9UeGGd+ht7sCpB7p0e83VgO4X/AHYWhXITMrNk/pg8syY2bpx23ptClCQuHhqi2BgQ==
|
||||||
|
dependencies:
|
||||||
|
accepts "~1.3.4"
|
||||||
|
base64id "~2.0.0"
|
||||||
|
debug "~4.3.2"
|
||||||
|
engine.io "~6.4.2"
|
||||||
|
socket.io-adapter "~2.5.2"
|
||||||
|
socket.io-parser "~4.2.4"
|
||||||
|
|
||||||
socks-proxy-agent@^6.0.0:
|
socks-proxy-agent@^6.0.0:
|
||||||
version "6.2.1"
|
version "6.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce"
|
resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce"
|
||||||
|
@ -5771,7 +5887,7 @@ validator@^13.0.0, validator@^13.6.0:
|
||||||
resolved "https://registry.yarnpkg.com/validator/-/validator-13.9.0.tgz#33e7b85b604f3bbce9bb1a05d5c3e22e1c2ff855"
|
resolved "https://registry.yarnpkg.com/validator/-/validator-13.9.0.tgz#33e7b85b604f3bbce9bb1a05d5c3e22e1c2ff855"
|
||||||
integrity sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==
|
integrity sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==
|
||||||
|
|
||||||
vary@~1.1.2:
|
vary@^1, vary@~1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||||
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
|
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
|
||||||
|
@ -5953,6 +6069,11 @@ ws@~7.4.2:
|
||||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"
|
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"
|
||||||
integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
|
integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
|
||||||
|
|
||||||
|
ws@~8.11.0:
|
||||||
|
version "8.11.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143"
|
||||||
|
integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==
|
||||||
|
|
||||||
xml2js@0.4.19:
|
xml2js@0.4.19:
|
||||||
version "0.4.19"
|
version "0.4.19"
|
||||||
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7"
|
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7"
|
||||||
|
@ -5997,6 +6118,11 @@ xmlhttprequest-ssl@~1.6.2:
|
||||||
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz#03b713873b01659dfa2c1c5d056065b27ddc2de6"
|
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz#03b713873b01659dfa2c1c5d056065b27ddc2de6"
|
||||||
integrity sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q==
|
integrity sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q==
|
||||||
|
|
||||||
|
xmlhttprequest-ssl@~2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67"
|
||||||
|
integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==
|
||||||
|
|
||||||
xtend@^4.0.2, xtend@~4.0.0:
|
xtend@^4.0.2, xtend@~4.0.0:
|
||||||
version "4.0.2"
|
version "4.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
||||||
|
|
Loading…
Reference in New Issue