@iexec/dataprotector-deserializer
Version:
Helper module to deserialize protected data in trusted iApp
168 lines • 7.77 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.IExecDataProtectorDeserializer = void 0;
const promises_1 = require("fs/promises");
const path_1 = require("path");
const borsh_1 = require("borsh");
const jszip_1 = __importDefault(require("jszip"));
/**
* Helper class to deserialize a protected data in trusted iApp
*
* Usage:
*
* ```js
* const dataprotectorDeserializer = new IExecDataProtectorDeserializer();
*
* const value1 = await dataprotectorDeserializer.getValue("path.to.value1", "bool");
* const value2 = await dataprotectorDeserializer.getValue("path.to.value2", "string");
* ```
*
* Options:
*
* - `mode`: specify the deserialization mode (default `"optimistic"`)
* - `"borsh"` for current protected data
* - `"legacy"` for protected data created with `@iexec/dataprotector@0`
* - `"optimistic"` try both
* - `protectedDataPath`: overrides the dataset path, by default use the standard dataset path provided in the iExec worker runtime
*/
class IExecDataProtectorDeserializer {
constructor(options) {
this.mode = (options === null || options === void 0 ? void 0 : options.mode) || 'optimistic';
if (options === null || options === void 0 ? void 0 : options.protectedDataPath) {
this.protectedDataPath = options === null || options === void 0 ? void 0 : options.protectedDataPath;
}
else if (process.env.IEXEC_DATASET_FILENAME && process.env.IEXEC_IN) {
this.protectedDataPath = (0, path_1.join)(process.env.IEXEC_IN, process.env.IEXEC_DATASET_FILENAME);
}
if (this.protectedDataPath) {
this.zipPromise = (0, promises_1.readFile)(this.protectedDataPath).then((buffer) => {
return new jszip_1.default().loadAsync(buffer);
});
this.zipPromise.catch(() => {
/* prevents unhandled promise rejection */
});
}
}
/**
* Deserializes the value at a given `path` with the value `schema`
*
* Params:
*
* - `path`: path to the desired value in the data object
* - `schema`: schema of the desired data (see list )
*
* | schema | deserializes to |
* | ---|---|
* | `"bool"` | `boolean` |
* | `"f64"` | `number` |
* | `"i128"` | `bigint` |
* | `"string"` | `string` |
* | `"boolean"` (legacy schema) | `boolean` |
* | `"number"` (legacy schema) | `number` |
* | any other value | `Uint8Array` |
*
* Usage:
*
* ```js
* const value = await dataprotectorDeserializer.getValue("path.to.string.value", "string");
* ```
*/
getValue(path, schema) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
if (this.zipPromise === undefined) {
throw Error('Missing protected data');
}
const zip = yield this.zipPromise.catch(() => {
throw Error('Failed to load protected data');
});
const serialized = yield ((_a = zip
.file(path.split('.').join('/'))) === null || _a === void 0 ? void 0 : _a.async('uint8array'));
if (!serialized) {
throw Error(`Failed to load path ${path}`);
}
switch (schema) {
case 'bool':
case 'i128':
case 'f64':
if (this.mode === 'legacy') {
throw Error(`Unsupported schema "${schema}" in "${this.mode}" mode`);
}
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (0, borsh_1.deserialize)(schema, serialized);
}
catch (e) {
throw Error(`Failed to deserialize "${path}" as "${schema}" in "${this.mode}" mode`);
}
case 'string':
try {
if (this.mode === 'legacy') {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return Buffer.from(serialized).toString('utf8');
}
try {
// try borsh deserialization first
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (0, borsh_1.deserialize)(schema, serialized);
}
catch (e) {
if (this.mode === 'optimistic') {
// fallback to legacy
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return Buffer.from(serialized).toString('utf8');
}
throw e;
}
}
catch (e) {
// avoid sensitive information leakage in error
throw Error(`Failed to deserialize "${path}" as "${schema}" in "${this.mode}" mode`);
}
case 'number':
if (this.mode === 'borsh') {
throw Error(`Unsupported schema "${schema}" in "${this.mode}" mode`);
}
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return Number(Buffer.from(serialized).toString());
}
catch (e) {
// avoid sensitive information leakage in error
throw Error(`Failed to deserialize "${path}" as "${schema}" in "${this.mode}" mode`);
}
case 'boolean':
if (this.mode === 'borsh') {
throw Error(`Unsupported schema "${schema}" in "${this.mode}" mode`);
}
try {
// legacy serialization spec for 'boolean' matches borsh spec 'bool'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (0, borsh_1.deserialize)('bool', serialized);
}
catch (e) {
// avoid sensitive information leakage in error
throw Error(`Failed to deserialize "${path}" as "${schema}" in "${this.mode}" mode`);
}
default:
// everything else should be binary data
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return serialized;
}
});
}
}
exports.IExecDataProtectorDeserializer = IExecDataProtectorDeserializer;
//# sourceMappingURL=index.js.map