Skip to content

Commit 5f4a77e

Browse files
authored
feat(transaction-manager): get encrypted channels by topic (#519)
1 parent efc0d4f commit 5f4a77e

File tree

4 files changed

+245
-3
lines changed

4 files changed

+245
-3
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,8 @@ export default class RequestLogic implements RequestLogicTypes.IRequestLogic {
368368

369369
const actionsConfirmedWithoutDuplicates = Utils.uniqueByProperty(
370370
transactionsByChannel[channelId]
371+
// filter the actions ignored by the previous layers
372+
.filter(action => action !== null)
371373
.map((t: any) => {
372374
try {
373375
return { action: JSON.parse(t.transaction.data), timestamp: t.timestamp };

packages/transaction-manager/src/transactions-parser.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ export default class TransactionsParser {
103103
keys: TransactionTypes.IKeysDictionary,
104104
encryptionMethod: string,
105105
): Promise<EncryptionTypes.IDecryptionParameters> {
106+
// Check if the decryption provider is given
107+
if (!this.decryptionProvider) {
108+
throw new Error(`No decryption provider given`);
109+
}
110+
106111
// Check the encryption method
107112
if (
108113
encryptionMethod !== `${EncryptionTypes.METHOD.ECIES}-${EncryptionTypes.METHOD.AES256_CBC}`

packages/transaction-manager/test/index.test.ts

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const tx: DataAccessTypes.IConfirmedTransaction = { transaction: { data }, times
2424
const tx2: DataAccessTypes.IConfirmedTransaction = { transaction: { data: data2 }, timestamp: 1 };
2525

2626
const channelId = Utils.crypto.normalizeKeccak256Hash(JSON.parse(data));
27+
const channelId2 = Utils.crypto.normalizeKeccak256Hash(JSON.parse(data2));
2728

2829
const fakeMetaDataAccessPersistReturn: DataAccessTypes.IReturnPersistTransaction = {
2930
meta: { transactionStorageLocation: 'fakeDataId', topics: extraTopics },
@@ -223,6 +224,42 @@ describe('index', () => {
223224
});
224225
});
225226

227+
it('cannot get a transaction from an encrypted channel without decryption provider', async () => {
228+
const encryptedTx = await TransactionsFactory.createEncryptedTransaction(data, [
229+
TestData.idRaw1.encryptionParams,
230+
TestData.idRaw2.encryptionParams,
231+
TestData.idRaw3.encryptionParams,
232+
]);
233+
const fakeMetaDataAccessGetReturnWithEncryptedTransaction: DataAccessTypes.IReturnGetTransactions = {
234+
meta: { transactionsStorageLocation: ['fakeDataId1'] },
235+
result: { transactions: [{ transaction: encryptedTx, timestamp: 1 }] },
236+
};
237+
238+
fakeDataAccess = {
239+
getChannelsByTopic: chai.spy(),
240+
getTransactionsByChannelId: chai.spy.returns(
241+
fakeMetaDataAccessGetReturnWithEncryptedTransaction,
242+
),
243+
initialize: chai.spy(),
244+
persistTransaction: chai.spy(),
245+
};
246+
247+
const transactionManager = new TransactionManager(fakeDataAccess);
248+
const ret = await transactionManager.getTransactionsByChannelId(channelId);
249+
250+
expect(ret, 'return is wrong').to.be.deep.equal({
251+
meta: {
252+
dataAccessMeta: { transactionsStorageLocation: ['fakeDataId1'] },
253+
ignoredTransactions: [
254+
{
255+
reason: 'No decryption provider given',
256+
transaction: { transaction: encryptedTx, timestamp: 1 },
257+
},
258+
],
259+
},
260+
result: { transactions: [null] },
261+
});
262+
});
226263
it('can get two transactions with different encryptions from the same encrypted channel', async () => {
227264
const encryptedTx = await TransactionsFactory.createEncryptedTransaction(data, [
228265
TestData.idRaw1.encryptionParams,
@@ -513,6 +550,155 @@ describe('index', () => {
513550
expect(fakeDataAccess.getChannelsByTopic).to.have.been.called.with(extraTopics[0]);
514551
});
515552

553+
it('can get an encrypted channel indexed by topic', async () => {
554+
const encryptedTx = await TransactionsFactory.createEncryptedTransaction(data, [
555+
TestData.idRaw1.encryptionParams,
556+
TestData.idRaw2.encryptionParams,
557+
TestData.idRaw3.encryptionParams,
558+
]);
559+
560+
const fakeMetaDataAccessGetReturnWithEncryptedTransaction: DataAccessTypes.IReturnGetChannelsByTopic = {
561+
meta: {
562+
transactionsStorageLocation: {
563+
[channelId]: ['fakeDataId1'],
564+
},
565+
},
566+
result: {
567+
transactions: {
568+
[channelId]: [{ transaction: encryptedTx, timestamp: 1 }],
569+
},
570+
},
571+
};
572+
fakeDataAccess = {
573+
getChannelsByTopic: chai.spy.returns(fakeMetaDataAccessGetReturnWithEncryptedTransaction),
574+
getTransactionsByChannelId: chai.spy(),
575+
initialize: chai.spy(),
576+
persistTransaction: chai.spy(),
577+
};
578+
579+
const transactionManager = new TransactionManager(
580+
fakeDataAccess,
581+
TestData.fakeDecryptionProvider,
582+
);
583+
584+
const ret = await transactionManager.getChannelsByTopic(extraTopics[0]);
585+
586+
expect(ret.result, 'ret.result is wrong').to.be.deep.equal({
587+
transactions: {
588+
[channelId]: [tx],
589+
},
590+
});
591+
expect(ret.meta, 'ret.meta is wrong').to.be.deep.equal({
592+
dataAccessMeta: fakeMetaDataAccessGetReturnWithEncryptedTransaction.meta,
593+
ignoredTransactions: {
594+
[channelId]: [null],
595+
},
596+
});
597+
expect(fakeDataAccess.getChannelsByTopic).to.have.been.called.with(extraTopics[0]);
598+
});
599+
600+
it('cannot get an encrypted channel indexed by topic without decryptionProvider', async () => {
601+
const encryptedTx = await TransactionsFactory.createEncryptedTransaction(data, [
602+
TestData.idRaw1.encryptionParams,
603+
TestData.idRaw2.encryptionParams,
604+
TestData.idRaw3.encryptionParams,
605+
]);
606+
607+
const fakeMetaDataAccessGetReturnWithEncryptedTransaction: DataAccessTypes.IReturnGetChannelsByTopic = {
608+
meta: {
609+
transactionsStorageLocation: {
610+
[channelId]: ['fakeDataId1'],
611+
},
612+
},
613+
result: {
614+
transactions: {
615+
[channelId]: [{ transaction: encryptedTx, timestamp: 1 }],
616+
},
617+
},
618+
};
619+
fakeDataAccess = {
620+
getChannelsByTopic: chai.spy.returns(fakeMetaDataAccessGetReturnWithEncryptedTransaction),
621+
getTransactionsByChannelId: chai.spy(),
622+
initialize: chai.spy(),
623+
persistTransaction: chai.spy(),
624+
};
625+
626+
const transactionManager = new TransactionManager(fakeDataAccess);
627+
628+
const ret = await transactionManager.getChannelsByTopic(extraTopics[0]);
629+
630+
expect(ret.result, 'ret.result is wrong').to.be.deep.equal({
631+
transactions: {
632+
[channelId]: [null],
633+
},
634+
});
635+
expect(ret.meta, 'ret.meta is wrong').to.be.deep.equal({
636+
dataAccessMeta: fakeMetaDataAccessGetReturnWithEncryptedTransaction.meta,
637+
ignoredTransactions: {
638+
[channelId]: [
639+
{
640+
reason: 'No decryption provider given',
641+
transaction: { transaction: encryptedTx, timestamp: 1 },
642+
},
643+
],
644+
},
645+
});
646+
expect(fakeDataAccess.getChannelsByTopic).to.have.been.called.with(extraTopics[0]);
647+
});
648+
649+
it('can get an clear channel indexed by topic without decryptionProvider even if an encrypted transaction happen first', async () => {
650+
const encryptedTx = await TransactionsFactory.createEncryptedTransaction(data, [
651+
TestData.idRaw1.encryptionParams,
652+
TestData.idRaw2.encryptionParams,
653+
TestData.idRaw3.encryptionParams,
654+
]);
655+
656+
const fakeMetaDataAccessGetReturnWithEncryptedTransaction: DataAccessTypes.IReturnGetChannelsByTopic = {
657+
meta: {
658+
transactionsStorageLocation: {
659+
[channelId]: ['fakeDataId1', 'fakeDataId2'],
660+
},
661+
},
662+
result: {
663+
transactions: {
664+
[channelId]: [
665+
{ transaction: encryptedTx, timestamp: 1 },
666+
{ transaction: { data }, timestamp: 2 },
667+
],
668+
},
669+
},
670+
};
671+
fakeDataAccess = {
672+
getChannelsByTopic: chai.spy.returns(fakeMetaDataAccessGetReturnWithEncryptedTransaction),
673+
getTransactionsByChannelId: chai.spy(),
674+
initialize: chai.spy(),
675+
persistTransaction: chai.spy(),
676+
};
677+
678+
const transactionManager = new TransactionManager(fakeDataAccess);
679+
680+
const ret = await transactionManager.getChannelsByTopic(extraTopics[0]);
681+
682+
expect(ret.result, 'ret.result is wrong').to.be.deep.equal({
683+
transactions: {
684+
[channelId]: [null, { transaction: { data }, timestamp: 2 }],
685+
},
686+
});
687+
expect(ret.meta, 'ret.meta is wrong').to.be.deep.equal({
688+
dataAccessMeta: fakeMetaDataAccessGetReturnWithEncryptedTransaction.meta,
689+
ignoredTransactions: {
690+
[channelId]: [
691+
{
692+
reason: 'No decryption provider given',
693+
transaction: { transaction: encryptedTx, timestamp: 1 },
694+
},
695+
null,
696+
],
697+
},
698+
});
699+
expect(fakeDataAccess.getChannelsByTopic).to.have.been.called.with(extraTopics[0]);
700+
});
701+
516702
it('can get channels indexed by topics with channelId not matching the first transaction hash', async () => {
517703
const txWrongHash: DataAccessTypes.IConfirmedTransaction = {
518704
timestamp: 1,
@@ -557,5 +743,56 @@ describe('index', () => {
557743
});
558744
expect(fakeDataAccess.getChannelsByTopic).to.have.been.called.with(extraTopics[0]);
559745
});
746+
747+
it('can get channels encrypted and clear', async () => {
748+
const encryptedTx = await TransactionsFactory.createEncryptedTransaction(data, [
749+
TestData.idRaw1.encryptionParams,
750+
TestData.idRaw2.encryptionParams,
751+
TestData.idRaw3.encryptionParams,
752+
]);
753+
754+
const fakeMetaDataAccessGetReturnWithEncryptedTransaction: DataAccessTypes.IReturnGetChannelsByTopic = {
755+
meta: {
756+
transactionsStorageLocation: {
757+
[channelId]: ['fakeDataId1'],
758+
[channelId2]: ['fakeDataId2'],
759+
},
760+
},
761+
result: {
762+
transactions: {
763+
[channelId]: [{ transaction: encryptedTx, timestamp: 1 }],
764+
[channelId2]: [{ transaction: { data: data2 }, timestamp: 1 }],
765+
},
766+
},
767+
};
768+
fakeDataAccess = {
769+
getChannelsByTopic: chai.spy.returns(fakeMetaDataAccessGetReturnWithEncryptedTransaction),
770+
getTransactionsByChannelId: chai.spy(),
771+
initialize: chai.spy(),
772+
persistTransaction: chai.spy(),
773+
};
774+
775+
const transactionManager = new TransactionManager(
776+
fakeDataAccess,
777+
TestData.fakeDecryptionProvider,
778+
);
779+
780+
const ret = await transactionManager.getChannelsByTopic(extraTopics[0]);
781+
782+
expect(ret.result, 'ret.result is wrong').to.be.deep.equal({
783+
transactions: {
784+
[channelId]: [tx],
785+
[channelId2]: [tx2],
786+
},
787+
});
788+
expect(ret.meta, 'ret.meta is wrong').to.be.deep.equal({
789+
dataAccessMeta: fakeMetaDataAccessGetReturnWithEncryptedTransaction.meta,
790+
ignoredTransactions: {
791+
[channelId]: [null],
792+
[channelId2]: [null],
793+
},
794+
});
795+
expect(fakeDataAccess.getChannelsByTopic).to.have.been.called.with(extraTopics[0]);
796+
});
560797
});
561798
});

packages/transaction-manager/test/unit/transactions-parser-test.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,7 @@ describe('transaction-parser', () => {
123123
TransactionTypes.ChannelType.UNKNOWN,
124124
),
125125
'must reject',
126-
).to.eventually.be.rejectedWith(
127-
`Impossible to decrypt the channel key from this transaction`,
128-
);
126+
).to.eventually.be.rejectedWith(`No decryption provider given`);
129127
});
130128
it('cannot parse encrypted transaction with keys corrupted', async () => {
131129
const encryptedParsedTx = await TransactionsFactory.createEncryptedTransaction(data, [

0 commit comments

Comments
 (0)