Skip to content

Commit 3a3b3b3

Browse files
Release/dataprotector deserializer v0.1.1 (#389)
# @iexec/dataprotector-deserializer ## [0.1.1] ### Changed - fixed cryptic TypeError when `@iexec/dataprotector-deserializer` was used in a context without protected data, `getValue()` now rejects with Error "Missing protected data" in such a case.
2 parents 950b88e + 315c314 commit 3a3b3b3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+2933
-1416
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
1+
## [0.1.1]
2+
3+
### Changed
4+
5+
- fixed cryptic TypeError when `@iexec/dataprotector-deserializer` was used in a context without protected data, `getValue()` now rejects with Error "Missing protected data" in such a case.
6+
17
## [0.1.0] Initial release

packages/dataprotector-deserializer/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/dataprotector-deserializer/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@iexec/dataprotector-deserializer",
3-
"version": "0.1.0",
4-
"description": "Helper module to deserialize protected data in trusted dapp",
3+
"version": "0.1.1",
4+
"description": "Helper module to deserialize protected data in trusted iApp",
55
"type": "module",
66
"types": "dist/types/index.d.ts",
77
"main": "./dist/esm/index.js",

packages/dataprotector-deserializer/src/index.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ type BinarySchemaFilter<T> = T extends
2020
type Mode = 'optimistic' | 'legacy' | 'borsh';
2121

2222
/**
23-
* Helper class to deserialize a protected data in trusted dapp
23+
* Helper class to deserialize a protected data in trusted iApp
2424
*
2525
* Usage:
2626
*
@@ -40,23 +40,31 @@ type Mode = 'optimistic' | 'legacy' | 'borsh';
4040
* - `protectedDataPath`: overrides the dataset path, by default use the standard dataset path provided in the iExec worker runtime
4141
*/
4242
class IExecDataProtectorDeserializer {
43-
private protectedDataPath: string;
43+
private protectedDataPath?: string;
4444

4545
private mode: Mode;
4646

47-
private zipPromise: Promise<JSZip>;
47+
private zipPromise?: Promise<JSZip>;
4848

4949
constructor(options?: { mode?: Mode; protectedDataPath?: string }) {
5050
this.mode = options?.mode || 'optimistic';
51-
this.protectedDataPath =
52-
options?.protectedDataPath ||
53-
join(process.env.IEXEC_IN, process.env.IEXEC_DATASET_FILENAME);
54-
this.zipPromise = readFile(this.protectedDataPath).then((buffer) => {
55-
return new JSZip().loadAsync(buffer);
56-
});
57-
this.zipPromise.catch(() => {
58-
/* prevents unhandled promise rejection */
59-
});
51+
if (options?.protectedDataPath) {
52+
this.protectedDataPath = options?.protectedDataPath;
53+
} else if (process.env.IEXEC_DATASET_FILENAME && process.env.IEXEC_IN) {
54+
this.protectedDataPath = join(
55+
process.env.IEXEC_IN,
56+
process.env.IEXEC_DATASET_FILENAME
57+
);
58+
}
59+
60+
if (this.protectedDataPath) {
61+
this.zipPromise = readFile(this.protectedDataPath).then((buffer) => {
62+
return new JSZip().loadAsync(buffer);
63+
});
64+
this.zipPromise.catch(() => {
65+
/* prevents unhandled promise rejection */
66+
});
67+
}
6068
}
6169

6270
/**
@@ -93,6 +101,9 @@ class IExecDataProtectorDeserializer {
93101
| StringSchemaFilter<T>
94102
| BinarySchemaFilter<T>
95103
> {
104+
if (this.zipPromise === undefined) {
105+
throw Error('Missing protected data');
106+
}
96107
const zip = await this.zipPromise.catch(() => {
97108
throw Error('Failed to load protected data');
98109
});

packages/dataprotector-deserializer/tests/index.test.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,20 @@ import { writeFile } from 'fs/promises';
22
import {
33
createZipFromObject as legacyCreateZipFromObject,
44
extractDataSchema as legacyExtractDataSchema,
5-
} from '@iexec/dataprotector/dist/utils/data.js'; // run `prepare-test-deps` script before running this test file
6-
import { describe, it, beforeAll, expect } from '@jest/globals';
5+
} from '@iexec/dataprotector/dist/utils/data.js'; // run `test:prepare` script before running this test file
6+
import { describe, it, beforeAll, expect, beforeEach } from '@jest/globals';
77
import {
88
createZipFromObject,
99
extractDataSchema,
1010
} from '../../sdk/dist/src/utils/data.js';
1111
import { IExecDataProtectorDeserializer } from '../src/index.js';
1212

1313
describe('IExecDataProtectorDeserializer', () => {
14+
beforeEach(() => {
15+
// reset env
16+
delete process.env.IEXEC_IN;
17+
delete process.env.IEXEC_DATASET_FILENAME;
18+
});
1419
describe('constructor', () => {
1520
it('set default protectedDataPath with iexec envs', () => {
1621
process.env.IEXEC_IN = 'iexec_in';
@@ -27,6 +32,15 @@ describe('IExecDataProtectorDeserializer', () => {
2732
expect(protectedDataDeserializer['mode']).toBe('optimistic');
2833
});
2934
});
35+
describe('when used without protected data', () => {
36+
it('getValue() fails with missing protected data', async () => {
37+
process.env.IEXEC_IN = 'iexec_in';
38+
const protectedDataDeserializer = new IExecDataProtectorDeserializer();
39+
await expect(
40+
protectedDataDeserializer.getValue('foo', 'string')
41+
).rejects.toThrow(Error('Missing protected data'));
42+
});
43+
});
3044
describe('with a file that is not a protected data', () => {
3145
it('getValue() fails to load the data', async () => {
3246
const protectedDataDeserializer = new IExecDataProtectorDeserializer({

packages/sdk/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## Next
6+
7+
### Changed
8+
9+
- `processProtectedData` and `getCollectionsByOwner` returns a ValidationError and not a WorkflowError anymore in case of a bad input parameter.
10+
511
## [2.0.0-beta.10] (2024-09-20)
612

713
### Changed

packages/sdk/src/lib/dataProtectorCore/getProtectedData.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export const getProtectedData = async ({
3232
}: GetProtectedDataParams & IExecConsumer & SubgraphConsumer): Promise<
3333
ProtectedData[]
3434
> => {
35-
const vCreationTimestampGte = positiveNumberSchema()
35+
const vCreatedAfterTimestamp = positiveNumberSchema()
3636
.label('createdAfterTimestamp')
3737
.validateSync(createdAfterTimestamp);
3838
const vProtectedDataAddress = addressOrEnsSchema()
@@ -66,8 +66,8 @@ export const getProtectedData = async ({
6666
if (vOwner) {
6767
whereFilters.push({ owner: vOwner });
6868
}
69-
if (vCreationTimestampGte) {
70-
whereFilters.push({ creationTimestamp_gte: vCreationTimestampGte });
69+
if (vCreatedAfterTimestamp) {
70+
whereFilters.push({ creationTimestamp_gte: vCreatedAfterTimestamp });
7171
}
7272
if (requiredSchemas.length > 0) {
7373
whereFilters.push({ schema_contains: requiredSchemas });
@@ -145,7 +145,7 @@ function flattenSchema(
145145
acc.anyOfSchemas.push(value.map((entry) => `${newKey}:${entry}`));
146146
} else {
147147
// Array of only one type. Similar to single type.
148-
acc.requiredSchemas.push(...value);
148+
acc.requiredSchemas.push(`${newKey}:${value[0]}`);
149149
}
150150
}
151151
// nested schema

packages/sdk/src/lib/dataProtectorCore/grantAccess.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ZeroAddress } from 'ethers';
2+
import { NULL_ADDRESS } from 'iexec/utils';
23
import {
34
ValidationError,
45
WorkflowError,
@@ -98,7 +99,9 @@ export const grantAccess = async ({
9899
throw new WorkflowError({
99100
message: grantAccessErrorMessage,
100101
errorCause: Error(
101-
`An access has been already granted to the user: ${vAuthorizedUser} with the app: ${vAuthorizedApp}`
102+
`An access has been already granted to the user: ${
103+
vAuthorizedUser || NULL_ADDRESS
104+
} with the app: ${vAuthorizedApp}`
102105
),
103106
});
104107
}

packages/sdk/src/lib/dataProtectorCore/processProtectedData.ts

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ import { IExecConsumer } from '../types/internalTypes.js';
3333
import { getWhitelistContract } from './smartContract/getWhitelistContract.js';
3434
import { isAddressInWhitelist } from './smartContract/whitelistContract.read.js';
3535

36+
export type ProcessProtectedData = typeof processProtectedData;
37+
3638
export const processProtectedData = async ({
3739
iexec = throwIfMissing(),
38-
protectedData = throwIfMissing(),
39-
app = throwIfMissing(),
40+
protectedData,
41+
app,
4042
userWhitelist,
4143
maxPrice = DEFAULT_MAX_PRICE,
4244
args,
@@ -46,30 +48,31 @@ export const processProtectedData = async ({
4648
onStatusUpdate = () => {},
4749
}: IExecConsumer &
4850
ProcessProtectedDataParams): Promise<ProcessProtectedDataResponse> => {
51+
const vProtectedData = addressOrEnsSchema()
52+
.required()
53+
.label('protectedData')
54+
.validateSync(protectedData);
55+
const vApp = addressOrEnsSchema()
56+
.required()
57+
.label('authorizedApp')
58+
.validateSync(app);
59+
const vUserWhitelist = addressSchema()
60+
.label('userWhitelist')
61+
.validateSync(userWhitelist);
62+
const vMaxPrice = positiveNumberSchema()
63+
.label('maxPrice')
64+
.validateSync(maxPrice);
65+
const vInputFiles = urlArraySchema()
66+
.label('inputFiles')
67+
.validateSync(inputFiles);
68+
const vArgs = stringSchema().label('args').validateSync(args);
69+
const vSecrets = secretsSchema().label('secrets').validateSync(secrets);
70+
const vWorkerpool = addressOrEnsSchema()
71+
.default(WORKERPOOL_ADDRESS) // Default workerpool if none is specified
72+
.label('workerpool')
73+
.validateSync(workerpool);
74+
4975
try {
50-
const vApp = addressOrEnsSchema()
51-
.required()
52-
.label('authorizedApp')
53-
.validateSync(app);
54-
const vProtectedData = addressOrEnsSchema()
55-
.required()
56-
.label('protectedData')
57-
.validateSync(protectedData);
58-
const vUserWhitelist = addressSchema()
59-
.label('userWhitelist')
60-
.validateSync(userWhitelist);
61-
const vMaxPrice = positiveNumberSchema()
62-
.label('maxPrice')
63-
.validateSync(maxPrice);
64-
const vInputFiles = urlArraySchema()
65-
.label('inputFiles')
66-
.validateSync(inputFiles);
67-
const vArgs = stringSchema().label('args').validateSync(args);
68-
const vSecrets = secretsSchema().label('secrets').validateSync(secrets);
69-
const vWorkerpool = addressOrEnsSchema()
70-
.default(WORKERPOOL_ADDRESS) // Default workerpool if none is specified
71-
.label('workerpool')
72-
.validateSync(workerpool);
7376
const vOnStatusUpdate =
7477
validateOnStatusUpdateCallback<
7578
OnStatusUpdateFn<ProcessProtectedDataStatuses>
@@ -95,7 +98,7 @@ export const processProtectedData = async ({
9598

9699
if (!isRequesterInWhitelist) {
97100
throw new Error(
98-
`As a user, you are not in the whitelist. So you can't access to the protectedData in order process it`
101+
"As a user, you are not in the whitelist. You can't access the protectedData so you can't process it."
99102
);
100103
}
101104
requester = vUserWhitelist;
@@ -243,6 +246,7 @@ export const processProtectedData = async ({
243246
result,
244247
};
245248
} catch (error) {
249+
console.error('[processProtectedData] ERROR', error);
246250
handleIfProtocolError(error);
247251
throw new WorkflowError({
248252
message: processProtectedDataErrorMessage,

packages/sdk/src/lib/dataProtectorCore/protectData.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,15 @@ import { getDataProtectorCoreContract } from './smartContract/getDataProtectorCo
3535

3636
const logger = getLogger('protectData');
3737

38+
export type ProtectData = typeof protectData;
39+
3840
export const protectData = async ({
3941
iexec = throwIfMissing(),
4042
dataprotectorContractAddress,
43+
name = DEFAULT_DATA_NAME,
4144
ipfsNode,
4245
ipfsGateway,
4346
data,
44-
name = DEFAULT_DATA_NAME,
4547
onStatusUpdate = () => {},
4648
}: IExecConsumer &
4749
DataProtectorContractConsumer &

0 commit comments

Comments
 (0)