Skip to content

Commit 8142c3d

Browse files
authored
feat(transaction-manager): decrypt channels (#516)
**Transaction-manager**: * Decrypt encrypted channel * add CleatTransaction class * add EncryptedTransaction class * parse persistedTransaction with TransactionParser **Epk-decryption**: - add isIdentityRegistered()
1 parent 4ec82c6 commit 8142c3d

21 files changed

+1311
-183
lines changed

.eslintrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
"metadata",
7373
"mul",
7474
"namespace",
75+
"parallelize",
7576
"param",
7677
"params",
7778
"parsable",

packages/epk-decryption/src/ethereum-private-key-decryption-provider.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,19 @@ export default class EthereumPrivateKeyDecryptionProvider
5555
return Utils.encryption.decrypt(data, decryptionParameters);
5656
}
5757

58+
/**
59+
* Check if an identity is registered in the provider
60+
*
61+
* @param identity identity to check
62+
*
63+
* @returns true if the identity is registered, false otherwise
64+
*/
65+
public async isIdentityRegistered(identity: IdentityTypes.IIdentity): Promise<boolean> {
66+
return Array.from(this.decryptionParametersDictionary.keys()).some(
67+
address => identity.value.toLowerCase() === address.toLowerCase(),
68+
);
69+
}
70+
5871
/**
5972
* Adds a new private key in the provider
6073
*

packages/epk-decryption/test/ethereum-private-key-decryption-provider-test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,4 +224,22 @@ describe('ethereum-private-key-decryption-provider', () => {
224224
).to.eventually.be.rejectedWith('private key unknown for the identity: 0x000');
225225
});
226226
});
227+
describe('isIdentityRegistered', () => {
228+
it('can check if an identity is registered', async () => {
229+
const decryptionProvider = new EthereumPrivateKeyDecryptionProvider(id1Raw.decryptionParams);
230+
231+
expect(
232+
await decryptionProvider.isIdentityRegistered(id1Raw.identity),
233+
'id1Raw must be registered',
234+
).to.be.true;
235+
});
236+
237+
it('can check if an identity is NOT registered', async () => {
238+
const decryptionProvider = new EthereumPrivateKeyDecryptionProvider(id1Raw.decryptionParams);
239+
expect(
240+
await decryptionProvider.isIdentityRegistered(id2Raw.identity),
241+
'id2Raw must not be registered',
242+
).to.be.false;
243+
});
244+
});
227245
});

packages/request-logic/src/request-logic.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,9 +282,8 @@ export default class RequestLogic implements RequestLogicTypes.IRequestLogic {
282282
requestId: string,
283283
): Promise<RequestLogicTypes.IReturnGetRequestFromId> {
284284
const resultGetTx = await this.transactionManager.getTransactionsByChannelId(requestId);
285-
286285
const actions = resultGetTx.result.transactions
287-
// remove the actions ignored by the under layer
286+
// filter the actions ignored by the previous layers
288287
.filter(action => action !== null);
289288
let ignoredTransactions: any[] = [];
290289

packages/transaction-manager/specs/decryption-provider.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@ This read-only property lists in an array all the identity types the decryption
2626

2727
Possible values: `'ethereumAddress'`
2828

29+
### `isIdentityRegistered()`
30+
31+
This function checks if it is possible to decrypt from a specific identity.
32+
33+
| Parameters | Type | Description |
34+
| ------------ | -------- | ----------------- |
35+
| **identity** | Identity | Identity to check |
36+
37+
Returns: `true` if the identity is registered in the provider, `false` otherwise.
38+
2939
### `decrypt()`
3040

3141
This function is able to decrypt encrypted data with the methods listed in `supportedMethods` and for the identity types listed in `supportedIdentityTypes`
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { TransactionTypes } from '@requestnetwork/types';
2+
import Utils from '@requestnetwork/utils';
3+
4+
/**
5+
* Class representing a clear transaction
6+
*/
7+
export default class ClearTransaction implements TransactionTypes.ITransaction {
8+
private data: TransactionTypes.ITransactionData;
9+
10+
constructor(data: TransactionTypes.ITransactionData) {
11+
this.data = data;
12+
}
13+
14+
/**
15+
* Gets the data of the transaction
16+
*
17+
* @returns a promise resolving the transaction data
18+
*/
19+
public async getData(): Promise<TransactionTypes.ITransactionData> {
20+
return this.data;
21+
}
22+
23+
/**
24+
* Gets the transaction data hash
25+
*
26+
* @returns a promise resolving the transaction data hash
27+
*/
28+
public async getHash(): Promise<string> {
29+
return Utils.crypto.normalizeKeccak256Hash(JSON.parse(this.data));
30+
}
31+
32+
/**
33+
* Gets the transaction error
34+
*
35+
* @returns a promise resolving a string of the error if any, otherwise an empty string
36+
*/
37+
public async getError(): Promise<string> {
38+
try {
39+
JSON.parse(this.data);
40+
return '';
41+
} catch (e) {
42+
return 'Impossible to JSON parse the transaction';
43+
}
44+
}
45+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { EncryptionTypes, TransactionTypes } from '@requestnetwork/types';
2+
import Utils from '@requestnetwork/utils';
3+
4+
/**
5+
* Class representing an encrypted transaction
6+
*/
7+
export default class EncryptedTransaction implements TransactionTypes.ITransaction {
8+
/** Decrypted data - start empty then filled by getData() */
9+
private data: TransactionTypes.ITransactionData = '';
10+
11+
/** Hash computed from the decrypted data - start empty then filled by getHash() */
12+
private dataHash: string = '';
13+
14+
/** Encrypted data */
15+
private encryptedData: TransactionTypes.ITransactionData;
16+
17+
/** hash given by the persisted transaction */
18+
private hashFromPersistedTransaction: string;
19+
20+
/** channel key to decrypt the encrypted data */
21+
private channelKey: EncryptionTypes.IDecryptionParameters;
22+
23+
/**
24+
* Creates an instance of EncryptedTransaction.
25+
* @param encryptedData the encrypted data of the transaction
26+
* @param hashFromPersistedTransaction the hash of the decrypted data (not checked)
27+
* @param channelKey decryption parameters to decrypted the encrypted data
28+
*/
29+
constructor(
30+
encryptedData: TransactionTypes.ITransactionData,
31+
hashFromPersistedTransaction: string,
32+
channelKey: EncryptionTypes.IDecryptionParameters,
33+
) {
34+
this.encryptedData = encryptedData;
35+
this.channelKey = channelKey;
36+
this.hashFromPersistedTransaction = hashFromPersistedTransaction;
37+
}
38+
39+
/**
40+
* Gets the data of the transaction
41+
*
42+
* @returns a promise resolving the transaction data
43+
*/
44+
public async getData(): Promise<TransactionTypes.ITransactionData> {
45+
if (this.data === '') {
46+
try {
47+
this.data = await Utils.encryption.decrypt(this.encryptedData, this.channelKey);
48+
} catch {
49+
throw new Error('Impossible to decrypt the transaction');
50+
}
51+
}
52+
return this.data;
53+
}
54+
55+
/**
56+
* Gets the transaction data hash
57+
*
58+
* @returns a promise resolving the transaction data hash
59+
*/
60+
public async getHash(): Promise<string> {
61+
if (this.dataHash === '') {
62+
const data = await this.getData();
63+
try {
64+
this.dataHash = await Utils.crypto.normalizeKeccak256Hash(JSON.parse(data));
65+
} catch (e) {
66+
throw new Error('Impossible to JSON parse the decrypted transaction data');
67+
}
68+
}
69+
return this.dataHash;
70+
}
71+
72+
/**
73+
* Gets the transaction error
74+
*
75+
* @returns a promise resolving a string of the error if any, otherwise an empty string
76+
*/
77+
public async getError(): Promise<string> {
78+
try {
79+
if ((await this.getHash()) !== this.hashFromPersistedTransaction) {
80+
throw Error('The given hash does not match the hash of the decrypted data');
81+
}
82+
return '';
83+
} catch (error) {
84+
return error.message;
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)