UNPKG

@iexec/dataprotector

Version:

This product enables users to confidentially store data–such as mail address, documents, personal information ...

137 lines 5.59 kB
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