@iexec/dataprotector
Version:
This product enables users to confidentially store data–such as mail address, documents, personal information ...
137 lines • 5.59 kB
JavaScript
import { ZeroAddress } from 'ethers';
import { DATASET_INFINITE_VOLUME, NULL_ADDRESS } from 'iexec/utils';
import { ValidationError, WorkflowError, grantAccessErrorMessage, handleIfProtocolError, } from '../../utils/errors.js';
import { formatGrantedAccess } from '../../utils/formatGrantedAccess.js';
import { addressOrEnsSchema, booleanSchema, isEnsTest, positiveIntegerStringSchema, positiveStrictIntegerStringSchema, throwIfMissing, validateOnStatusUpdateCallback, } from '../../utils/validators.js';
import { isERC734 } from '../../utils/whitelist.js';
import { getGrantedAccess } from './getGrantedAccess.js';
const inferTagFromAppMREnclave = (mrenclave) => {
const tag = ['tee'];
try {
const { framework } = JSON.parse(mrenclave);
if (framework.toLowerCase() === 'scone') {
tag.push('scone');
return tag;
}
}
catch (e) {
// noop
}
throw new WorkflowError({
message: grantAccessErrorMessage,
errorCause: Error('App does not use a supported TEE framework'),
});
};
export const grantAccess = async ({ iexec = throwIfMissing(), protectedData, authorizedApp, authorizedUser, pricePerAccess = 0, numberOfAccess, allowBulk = false, onStatusUpdate = () => { }, }) => {
const vProtectedData = addressOrEnsSchema()
.required()
.label('protectedData')
.validateSync(protectedData);
let vAuthorizedApp = addressOrEnsSchema()
.required()
.label('authorizedApp')
.validateSync(authorizedApp);
const vAuthorizedUser = addressOrEnsSchema()
.label('authorizedUser')
.validateSync(authorizedUser);
let vPricePerAccess = positiveIntegerStringSchema()
.label('pricePerAccess')
.validateSync(pricePerAccess);
let vNumberOfAccess = positiveStrictIntegerStringSchema()
.label('numberOfAccess')
.validateSync(numberOfAccess);
const vAllowBulk = booleanSchema().label('allowBulk').validateSync(allowBulk);
const vOnStatusUpdate = validateOnStatusUpdateCallback(onStatusUpdate);
// Validate consistency between allowBulk, pricePerAccess and numberOfAccess
if (vAllowBulk) {
if (vPricePerAccess && vPricePerAccess !== '0') {
throw new ValidationError('allowBulk requires pricePerAccess to be 0 or undefined');
}
vPricePerAccess = '0';
if (vNumberOfAccess &&
vNumberOfAccess !== DATASET_INFINITE_VOLUME.toString()) {
throw new ValidationError(`allowBulk requires numberOfAccess to be ${DATASET_INFINITE_VOLUME.toString()} or undefined`);
}
vNumberOfAccess = DATASET_INFINITE_VOLUME.toString();
}
if (vAuthorizedApp && isEnsTest(vAuthorizedApp)) {
const resolved = await iexec.ens.resolveName(vAuthorizedApp);
if (!resolved) {
throw new ValidationError('authorizedApp ENS name is not valid');
}
vAuthorizedApp = resolved.toLowerCase();
}
if (vAuthorizedApp === ZeroAddress) {
throw Error(`Forbidden to use ${ZeroAddress} as authorizedApp, this would give access to any app`);
}
const { grantedAccess: publishedDatasetOrders } = await getGrantedAccess({
iexec,
protectedData: vProtectedData,
authorizedApp: vAuthorizedApp,
authorizedUser: vAuthorizedUser,
isUserStrict: true,
});
if (publishedDatasetOrders.length > 0) {
throw new WorkflowError({
message: grantAccessErrorMessage,
errorCause: Error(`An access has been already granted to the user: ${vAuthorizedUser || NULL_ADDRESS} with the app: ${vAuthorizedApp}`),
});
}
let tag;
const isDeployedApp = await iexec.app.checkDeployedApp(authorizedApp);
if (isDeployedApp) {
tag = await iexec.app.showApp(authorizedApp).then(({ app }) => {
return inferTagFromAppMREnclave(app.appMREnclave);
});
}
else if (await isERC734(iexec, authorizedApp)) {
tag = ['tee', 'scone'];
}
else {
throw new WorkflowError({
message: grantAccessErrorMessage,
errorCause: Error(`Invalid app set for address ${authorizedApp}. The app either has an invalid tag (possibly non-TEE) or an invalid whitelist smart contract address.`),
});
}
vOnStatusUpdate({
title: 'CREATE_DATASET_ORDER',
isDone: false,
});
const datasetorder = await iexec.order
.createDatasetorder({
dataset: vProtectedData,
apprestrict: vAuthorizedApp,
requesterrestrict: vAuthorizedUser,
datasetprice: vPricePerAccess,
volume: vNumberOfAccess,
tag,
})
.then((datasetorderTemplate) => iexec.order.signDatasetorder(datasetorderTemplate))
.catch((e) => {
throw new WorkflowError({
message: 'Failed to sign data access',
errorCause: e,
});
});
vOnStatusUpdate({
title: 'CREATE_DATASET_ORDER',
isDone: true,
});
vOnStatusUpdate({
title: 'PUBLISH_DATASET_ORDER',
isDone: false,
});
await iexec.order.publishDatasetorder(datasetorder).catch((e) => {
handleIfProtocolError(e);
throw new WorkflowError({
message: 'Failed to publish data access',
errorCause: e,
});
});
vOnStatusUpdate({
title: 'PUBLISH_DATASET_ORDER',
isDone: true,
});
return formatGrantedAccess(datasetorder, parseInt(datasetorder.volume));
};
//# sourceMappingURL=grantAccess.js.map