@@ -6,8 +6,10 @@ import { $Json } from '@opendatacapture/schemas/core';
66import { AssignmentsService } from '@/assignments/assignments.service' ;
77import { ConfigurationService } from '@/configuration/configuration.service' ;
88import { InstrumentRecordsService } from '@/instrument-records/instrument-records.service' ;
9+ import { InstrumentsService } from '@/instruments/instruments.service' ;
910import { SessionsService } from '@/sessions/sessions.service' ;
1011import { SetupService } from '@/setup/setup.service' ;
12+ import { VirtualizationService } from '@/virtualization/virtualization.service' ;
1113
1214import { GatewayService } from './gateway.service' ;
1315
@@ -20,9 +22,11 @@ export class GatewaySynchronizer implements OnApplicationBootstrap {
2022 configurationService : ConfigurationService ,
2123 private readonly assignmentsService : AssignmentsService ,
2224 private readonly gatewayService : GatewayService ,
25+ private readonly instrumentsService : InstrumentsService ,
2326 private readonly instrumentRecordsService : InstrumentRecordsService ,
2427 private readonly sessionsService : SessionsService ,
25- private readonly setupService : SetupService
28+ private readonly setupService : SetupService ,
29+ private readonly virtualizationService : VirtualizationService
2630 ) {
2731 this . refreshInterval = configurationService . get ( 'GATEWAY_REFRESH_INTERVAL' ) ;
2832 }
@@ -37,54 +41,98 @@ export class GatewaySynchronizer implements OnApplicationBootstrap {
3741 }
3842 const assignment = await this . assignmentsService . findById ( remoteAssignment . id ) ;
3943
40- const completedAt = remoteAssignment . completedAt ;
41- const symmetricKey = remoteAssignment . symmetricKey ;
42- if ( ! completedAt ) {
44+ if ( ! remoteAssignment . completedAt ) {
4345 this . logger . error ( `Field 'completedAt' is null for assignment '${ assignment . id } '` ) ;
4446 return ;
45- } else if ( ! symmetricKey ) {
47+ } else if ( ! remoteAssignment . symmetricKey ) {
4648 this . logger . error ( `Field 'symmetricKey' is null for assignment '${ assignment . id } '` ) ;
4749 return ;
4850 }
4951
50- const data = await $Json . parseAsync (
51- JSON . parse (
52- await HybridCrypto . decrypt ( {
53- cipherText : remoteAssignment . encryptedData ,
54- privateKey : await HybridCrypto . deserializePrivateKey ( assignment . encryptionKeyPair . privateKey ) ,
55- symmetricKey
56- } )
57- )
58- ) ;
52+ const instrument = await this . instrumentsService . findById ( assignment . instrumentId ) ;
5953
6054 const session = await this . sessionsService . create ( {
61- date : completedAt ,
55+ date : remoteAssignment . completedAt ,
6256 groupId : remoteAssignment . groupId ?? null ,
6357 subjectData : {
6458 id : assignment . subjectId
6559 } ,
6660 type : 'REMOTE'
6761 } ) ;
6862
69- const record = await this . instrumentRecordsService . create ( {
70- assignmentId : assignment . id ,
71- data,
72- date : completedAt ,
73- groupId : assignment . groupId ?? undefined ,
74- instrumentId : assignment . instrumentId ,
75- sessionId : session . id ,
76- subjectId : assignment . subjectId
77- } ) ;
63+ const cipherTexts : string [ ] = [ ] ;
64+ const symmetricKeys : string [ ] = [ ] ;
7865
79- this . logger . log ( `Created record with ID: ${ record . id } ` ) ;
66+ if ( instrument . kind === 'SERIES' ) {
67+ if ( ! ( remoteAssignment . encryptedData . startsWith ( '$' ) && remoteAssignment . symmetricKey . startsWith ( '$' ) ) ) {
68+ this . logger . error ( { remoteAssignment } ) ;
69+ throw new InternalServerErrorException ( 'Malformed remote assignment for series instrument' ) ;
70+ }
71+ cipherTexts . push ( ...remoteAssignment . encryptedData . slice ( 1 ) . split ( '$' ) ) ;
72+ symmetricKeys . push ( ...remoteAssignment . symmetricKey . slice ( 1 ) . split ( '$' ) ) ;
73+ if ( cipherTexts . length !== instrument . content . length ) {
74+ throw new InternalServerErrorException (
75+ `Expected length of cypher texts '${ cipherTexts . length } ' to match length of series instrument content '${ symmetricKeys . length } '`
76+ ) ;
77+ } else if ( symmetricKeys . length !== instrument . content . length ) {
78+ throw new InternalServerErrorException (
79+ `Expected length of symmetric keys '${ cipherTexts . length } ' to match length of series instrument content '${ symmetricKeys . length } '`
80+ ) ;
81+ }
82+ } else if ( remoteAssignment . encryptedData . includes ( '$' ) || remoteAssignment . symmetricKey . includes ( '$' ) ) {
83+ this . logger . error ( { remoteAssignment } ) ;
84+ throw new InternalServerErrorException ( 'Malformed remote assignment for scalar instrument' ) ;
85+ } else {
86+ cipherTexts . push ( remoteAssignment . encryptedData ) ;
87+ symmetricKeys . push ( remoteAssignment . symmetricKey ) ;
88+ }
89+
90+ const createdRecordIds : string [ ] = [ ] ;
8091 try {
92+ for ( let i = 0 ; i < cipherTexts . length ; i ++ ) {
93+ const cipherText = cipherTexts [ i ] ! ;
94+ const symmetricKey = symmetricKeys [ i ] ! ;
95+ const data = await $Json . parseAsync (
96+ JSON . parse (
97+ await HybridCrypto . decrypt ( {
98+ cipherText : Buffer . from ( cipherText , 'base64' ) ,
99+ privateKey : await HybridCrypto . deserializePrivateKey ( assignment . encryptionKeyPair . privateKey ) ,
100+ symmetricKey : Buffer . from ( symmetricKey , 'base64' )
101+ } )
102+ )
103+ ) ;
104+ const record = await this . instrumentRecordsService . create ( {
105+ assignmentId : assignment . id ,
106+ data,
107+ date : remoteAssignment . completedAt ,
108+ groupId : assignment . groupId ?? undefined ,
109+ instrumentId :
110+ instrument . kind === 'SERIES'
111+ ? this . instrumentsService . generateScalarInstrumentId ( { internal : instrument . content [ i ] ! } )
112+ : instrument . id ,
113+ sessionId : session . id ,
114+ subjectId : assignment . subjectId
115+ } ) ;
116+ this . logger . log ( `Created record with ID: ${ record . id } ` ) ;
117+ createdRecordIds . push ( record . id ) ;
118+ }
81119 await this . gatewayService . deleteRemoteAssignment ( assignment . id ) ;
82120 } catch ( err ) {
83- await this . instrumentRecordsService . deleteById ( record . id ) ;
84- this . logger . log ( `Deleted Record with ID: ${ record . id } ` ) ;
85- throw new InternalServerErrorException ( 'Failed to Delete Remote Assignments' , {
86- cause : err
121+ this . logger . error ( {
122+ data : {
123+ assignment,
124+ cipherTexts,
125+ remoteAssignment,
126+ symmetricKeys
127+ } ,
128+ message : 'Failed to Process Data'
87129 } ) ;
130+ this . logger . error ( err ) ;
131+ for ( const id of createdRecordIds ) {
132+ await this . instrumentRecordsService . deleteById ( id ) ;
133+ this . logger . log ( `Deleted Record with ID: ${ id } ` ) ;
134+ }
135+ throw err ;
88136 }
89137 }
90138
0 commit comments