@iexec/dataprotector
Version:
This product enables users to confidentially store data–such as mail address, documents, personal information ...
155 lines • 6.46 kB
JavaScript
import { NULL_ADDRESS } from 'iexec/utils';
import { MAX_DESIRED_APP_ORDER_PRICE, MAX_DESIRED_WORKERPOOL_ORDER_PRICE, SCONE_TAG, } from '../../config/config.js';
import { ValidationError, WorkflowError, handleIfProtocolError, prepareBulkRequestErrorMessage, } from '../../utils/errors.js';
import { pushRequesterSecret } from '../../utils/pushRequesterSecret.js';
import { getPemFormattedKeyPair, formatPemPublicKeyForSMS, } from '../../utils/rsa.js';
import { addressOrEnsSchema, booleanSchema, positiveNumberSchema, secretsSchema, stringSchema, throwIfMissing, urlArraySchema, validateOnStatusUpdateCallback, } from '../../utils/validators.js';
export const prepareBulkRequest = async ({ iexec = throwIfMissing(), bulkAccesses, app, maxProtectedDataPerTask = 100, appMaxPrice = MAX_DESIRED_APP_ORDER_PRICE, workerpoolMaxPrice = MAX_DESIRED_WORKERPOOL_ORDER_PRICE, args, inputFiles, secrets, workerpool, encryptResult = false, pemPrivateKey, onStatusUpdate = () => { }, }) => {
const vApp = addressOrEnsSchema().required().label('app').validateSync(app);
const vMaxProtectedDataPerTask = positiveNumberSchema()
.label('maxProtectedDataPerTask')
.validateSync(maxProtectedDataPerTask);
const vAppMaxPrice = positiveNumberSchema()
.label('appMaxPrice')
.validateSync(appMaxPrice);
const vWorkerpoolMaxPrice = positiveNumberSchema()
.label('workerpoolMaxPrice')
.validateSync(workerpoolMaxPrice);
const vInputFiles = urlArraySchema()
.label('inputFiles')
.validateSync(inputFiles);
const vArgs = stringSchema().label('args').validateSync(args);
const vSecrets = secretsSchema().label('secrets').validateSync(secrets);
const vWorkerpool = addressOrEnsSchema()
.default(NULL_ADDRESS)
.label('workerpool')
.validateSync(workerpool);
const vEncryptResult = booleanSchema()
.label('encryptResult')
.validateSync(encryptResult);
const vPemPrivateKey = stringSchema()
.label('pemPrivateKey')
.validateSync(pemPrivateKey);
const vOnStatusUpdate = validateOnStatusUpdateCallback(onStatusUpdate);
// Validate that if pemPrivateKey is provided, encryptResult must be true
if (vPemPrivateKey && !vEncryptResult) {
throw new Error('pemPrivateKey can only be provided when encryptResult is true');
}
if (!bulkAccesses || bulkAccesses.length === 0) {
throw new ValidationError('bulkAccesses is required and must not be empty');
}
// TODO validate bulkOrders?
// price, volume, app, workerpool, requester, signature (including whitelists)
const vBulkAccesses = bulkAccesses;
try {
vOnStatusUpdate({
title: 'PUSH_REQUESTER_SECRET',
isDone: false,
});
const secretsId = await pushRequesterSecret(iexec, vSecrets);
vOnStatusUpdate({
title: 'PUSH_REQUESTER_SECRET',
isDone: true,
});
vOnStatusUpdate({
title: 'GENERATE_ENCRYPTION_KEY',
isDone: false,
});
// Handle result encryption
let privateKey;
if (vEncryptResult) {
if (!vPemPrivateKey) {
vOnStatusUpdate({
title: 'GENERATE_ENCRYPTION_KEY',
isDone: false,
});
}
const pemKeyPair = await getPemFormattedKeyPair({
pemPrivateKey: vPemPrivateKey,
});
privateKey = pemKeyPair.pemPrivateKey;
// Notify user if a new key was generated
if (!vPemPrivateKey) {
vOnStatusUpdate({
title: 'GENERATE_ENCRYPTION_KEY',
isDone: true,
payload: {
pemPrivateKey: pemKeyPair.pemPrivateKey,
},
});
}
vOnStatusUpdate({
title: 'PUSH_ENCRYPTION_KEY',
isDone: false,
payload: {
pemPublicKey: pemKeyPair.pemPublicKey,
},
});
await iexec.result.pushResultEncryptionKey(formatPemPublicKeyForSMS(pemKeyPair.pemPublicKey), {
forceUpdate: true,
});
vOnStatusUpdate({
title: 'PUSH_ENCRYPTION_KEY',
isDone: true,
payload: {
pemPublicKey: pemKeyPair.pemPublicKey,
},
});
}
// Prepare dataset bulk
vOnStatusUpdate({
title: 'PREPARE_PROTECTED_DATA_BULK',
isDone: false,
});
const { cid, volume } = await iexec.order.prepareDatasetBulk(vBulkAccesses, {
maxDatasetPerTask: parseInt(vMaxProtectedDataPerTask.toString()),
});
vOnStatusUpdate({
title: 'PREPARE_PROTECTED_DATA_BULK',
isDone: true,
});
// Create request order for the whole bulk (only once)
vOnStatusUpdate({
title: 'CREATE_BULK_REQUEST',
isDone: false,
});
const requestorderToSign = await iexec.order.createRequestorder({
app: vApp,
appmaxprice: vAppMaxPrice,
workerpool: vWorkerpool,
workerpoolmaxprice: vWorkerpoolMaxPrice,
volume,
category: 0,
tag: SCONE_TAG,
params: {
bulk_cid: cid,
iexec_input_files: vInputFiles,
iexec_secrets: secretsId,
iexec_args: vArgs,
...(vEncryptResult ? { iexec_result_encryption: true } : {}),
},
trust: 0,
// bulk order
datasetmaxprice: 0,
dataset: NULL_ADDRESS,
});
const requestorder = await iexec.order.signRequestorder(requestorderToSign);
vOnStatusUpdate({
title: 'CREATE_BULK_REQUEST',
isDone: true,
});
return {
bulkRequest: requestorder,
...(privateKey ? { pemPrivateKey: privateKey } : {}),
};
}
catch (error) {
console.error('[prepareBulkRequest] ERROR', error);
handleIfProtocolError(error);
throw new WorkflowError({
message: prepareBulkRequestErrorMessage,
errorCause: error,
});
}
};
//# sourceMappingURL=prepareBulkRequest.js.map