rxome-generator 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +484 -0
- package/demos/demo_data_full.json +149 -0
- package/demos/demo_data_full_compressed.json +76 -0
- package/demos/demo_from_gui.json +64 -0
- package/demos/rxome.decrypt.json +1 -0
- package/demos/rxome.encrypt.json +1 -0
- package/demos/testmessage_cipher +19 -0
- package/index.js +3 -0
- package/lib/phenopackets.json +1948 -0
- package/lib/rxome-api-demo.js +56 -0
- package/lib/rxome-api.js +119 -0
- package/lib/rxome-api.test.js +22 -0
- package/lib/rxome-generator.js +349 -0
- package/lib/rxome-generator.test.js +379 -0
- package/package.json +50 -0
- package/rxcode +401 -0
- package/rxcode.test.js +104 -0
package/rxcode
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const Coder = require( './lib/rxome-generator' );
|
|
4
|
+
const ApiDemo = require( './lib/rxome-api-demo' );
|
|
5
|
+
const RxAPI = require( './lib/rxome-api' );
|
|
6
|
+
const { program } = require('commander');
|
|
7
|
+
|
|
8
|
+
const FS = require( 'fs' );
|
|
9
|
+
const Path = require('path');
|
|
10
|
+
const { cp } = require('fs/promises');
|
|
11
|
+
//const TXT = require( './assets/scripts/modules/texte.js')
|
|
12
|
+
|
|
13
|
+
const DEMO_CREDENTIALS = ApiDemo.DEMO_CREDENTIALS
|
|
14
|
+
const DEMO_PRIVATE_KEY = ApiDemo.CRYPT_PRIVATE_KEY
|
|
15
|
+
const DEMO_PUBLIC_KEY = ApiDemo.CRYPT_PUBLIC_KEY
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
program
|
|
19
|
+
.name('rxcode')
|
|
20
|
+
.description(
|
|
21
|
+
`Basic usage: rxcode g <input json file>: generates QR Code with the basefilename of the inputfile.
|
|
22
|
+
Before first use, please generate an API access key (rxcode -k) and deposit the public key on the RxOME server.
|
|
23
|
+
`)
|
|
24
|
+
.version('1.0.0')
|
|
25
|
+
.addHelpText('beforeAll', 'RxOME.net QR Code generation tool\n')
|
|
26
|
+
.addHelpText('afterAll', '\nAuthor: Tom Kamphans, GeneTalk GmbH, 2022');
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
program.command('generate')
|
|
30
|
+
.alias('g')
|
|
31
|
+
.summary('generate QR Code from PhenoPacket JSON')
|
|
32
|
+
.description(
|
|
33
|
+
`Generate QR Code from PhenoPacket JSON. The credential information keyId and either key or keyFile
|
|
34
|
+
are mandatory and can be specified either in the input JSON file or by command line arguments.
|
|
35
|
+
The command line arguments precede the data from the JSON input file.
|
|
36
|
+
Output: prints the given or new pseudonym.`)
|
|
37
|
+
.argument('[input file]', 'Input JSON file (default: STDIN)')
|
|
38
|
+
.option('-o, --output <filename>', 'Filename for the QR code (default: <inputfile>.png)')
|
|
39
|
+
.option('-p, --pseudonym', 'vPseudonym for patient, if known. Otherwise a new is generated', '')
|
|
40
|
+
.option('-i, --keyId <id>', 'API access ID (default: input file, credentials.keyId or metaData.createdBy)')
|
|
41
|
+
.option('-k, --keyFile <filename>', 'Filename with API access key (default: use -s)')
|
|
42
|
+
.option('-s, --key <key string>', 'API access key (default: input file, credentials.key)')
|
|
43
|
+
.option('-u, --user <user string>', 'API access user (default: credentials.user or metaData.submittedBy or info@rxome.net)')
|
|
44
|
+
.option('-c, --created <date>', 'Date (default: input file, metaData.created)')
|
|
45
|
+
.option('-l, --lab <lab>', 'Laboratory name (default: input file, metaData.createdBy)')
|
|
46
|
+
.option('-e, --email <email>', 'Laboratory email (default: input file, metaData.submittedBy)')
|
|
47
|
+
.option('-S, --snake', 'Read payload formatted in snake_case (default: camelCase)')
|
|
48
|
+
.option('-t, --test', 'Use test API instead of production API')
|
|
49
|
+
.option('-D, --debug', 'Some output for debugging')
|
|
50
|
+
.action( async (inputfile, options) => {
|
|
51
|
+
const rawdata = FS.readFileSync( inputfile || '/dev/stdin' );
|
|
52
|
+
const jsonData = JSON.parse( rawdata );
|
|
53
|
+
const qrData = options.snake ? Coder.convertToCamelCase( jsonData ) : jsonData;
|
|
54
|
+
|
|
55
|
+
('metaData' in qrData) || (qrData.metaData = {});
|
|
56
|
+
options.lab && (qrData.metaData.createdBy = options.lab);
|
|
57
|
+
options.created && (qrData.metaData.created = options.created);
|
|
58
|
+
options.email && (qrData.metaData.submittedBy = options.email);
|
|
59
|
+
options.pseudonym && (qrData.metaData.pseudonym = options.pseudonym);
|
|
60
|
+
const qrApi = options.test ? RxAPI.TESTAPI : RxAPI.API;
|
|
61
|
+
|
|
62
|
+
('credentials' in qrData) || (qrData.credentials = {});
|
|
63
|
+
if ( options.key ) {
|
|
64
|
+
qrData.credentials.key = options.key;
|
|
65
|
+
delete qrData.credentials.keyFile;
|
|
66
|
+
} else if ( options.keyFile ){
|
|
67
|
+
qrData.credentials.keyFile = options.keyFile;
|
|
68
|
+
delete qrData.credentials.key;
|
|
69
|
+
}
|
|
70
|
+
qrData.credentials.keyId = options.keyId || qrData.credentials.keyId || qrData.metaData.createdBy
|
|
71
|
+
qrData.credentials.user = options.user || qrData.credentials.user || qrData.metaData.submittedBy || 'info@rxome.net';
|
|
72
|
+
|
|
73
|
+
if (! (qrData.credentials.keyId )) {
|
|
74
|
+
console.log( 'Error: no API ID.');
|
|
75
|
+
return 1;
|
|
76
|
+
}
|
|
77
|
+
if (! (qrData.credentials.keyFile || qrData.credentials.key)) {
|
|
78
|
+
console.log( 'Error: no API access key.');
|
|
79
|
+
return 1;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
options.debug && console.log( "Data ", qrData );
|
|
83
|
+
|
|
84
|
+
const outputfile = options.output || `${Path.basename((inputfile || 'qrcode.json'), '.json')}.png`
|
|
85
|
+
const psLab = await Coder.writeQR( outputfile, qrData, qrApi );
|
|
86
|
+
console.log( psLab );
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
program.command('convert')
|
|
91
|
+
.alias('c')
|
|
92
|
+
.description('convert case style of keys in JSON files from snake_case to camelCase (and vice versa)')
|
|
93
|
+
.argument('[input file]', 'Input JSON file (default: STDIN)')
|
|
94
|
+
.option('-o, --output <output file>', 'Output JSON file (default: stdout)', '/dev/stdout')
|
|
95
|
+
.option('-s, --snake', 'Convert to snake_case (default: convert to camelCase')
|
|
96
|
+
.action( async (inputfile, options) => {
|
|
97
|
+
const data = JSON.parse(FS.readFileSync( inputfile || '/dev/stdin' ));
|
|
98
|
+
let newData;
|
|
99
|
+
if ( options.snake ) {
|
|
100
|
+
newData = Coder.convert_to_snake_case( data );
|
|
101
|
+
} else {
|
|
102
|
+
newData = Coder.convertToCamelCase( data );
|
|
103
|
+
}
|
|
104
|
+
FS.writeFileSync( options.output, JSON.stringify( newData ))
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
program.command('preprocess')
|
|
109
|
+
.alias('p')
|
|
110
|
+
.description('perform preprocessing steps')
|
|
111
|
+
.argument('[input file]', 'Input JSON file (default: STDIN)')
|
|
112
|
+
.option('-o, --output <output file>', 'Output JSON file (default: stdout)', '/dev/stdout')
|
|
113
|
+
.option('-C, --case', 'Apply case style converter from snake_case to camelCase')
|
|
114
|
+
.option('-w, --whitelist', 'Apply whitelist filtering (remove unnecessary sections)')
|
|
115
|
+
.option('-s, --sanitize', 'A pply sanitizing step (remove common mistakes)')
|
|
116
|
+
.option('-c, --compress', 'Compact HPO term list')
|
|
117
|
+
.action( async (inputfile, options) => {
|
|
118
|
+
let data = JSON.parse(FS.readFileSync( inputfile || '/dev/stdin' ));
|
|
119
|
+
options.case && (data = Coder.convertToCamelCase( data ));
|
|
120
|
+
options.whitelist && (data = Coder.whiteListPhenoPacket( data ));
|
|
121
|
+
options.sanitize && (data = Coder.sanitizePhenoPacket( data ));
|
|
122
|
+
options.compress && (data = Coder.compressPhenoPacket( data ));
|
|
123
|
+
FS.writeFileSync( options.output, JSON.stringify( data ))
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
program.command('verify')
|
|
128
|
+
.alias('v')
|
|
129
|
+
.description('verify input file against phenopacket schema')
|
|
130
|
+
.argument('[input file]', 'Input JSON file (default: STDIN)')
|
|
131
|
+
.action( async (inputfile) => {
|
|
132
|
+
let data = JSON.parse(FS.readFileSync( inputfile || '/dev/stdin' ));
|
|
133
|
+
let result = await Coder.verifyPhenoPacket( data );
|
|
134
|
+
console.log( result || 'No error found' );
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
program.command('apikeys')
|
|
139
|
+
.summary('generate key pair for API access')
|
|
140
|
+
.alias('k')
|
|
141
|
+
.description('Generate key pair. A pair of these keys is necessary to communicate with the rxome API. Keep the private key and deposit the public key on the RxOme server.')
|
|
142
|
+
.argument('[file prefix]', 'Prefix for file names (default: rxome)')
|
|
143
|
+
.option('-d, --directory <dir>', 'output directory', '.')
|
|
144
|
+
.action( (prefix, options) => {
|
|
145
|
+
RxAPI.generateApiKeys( prefix || 'rxome', options.directory )
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
program.command('ping')
|
|
150
|
+
.summary('Ping API/check API credentials')
|
|
151
|
+
.alias('P')
|
|
152
|
+
.argument('id', 'API access key ID (default: rxome)')
|
|
153
|
+
.argument('key', 'API access key')
|
|
154
|
+
.option('-t, --test', 'Connect to test API')
|
|
155
|
+
.option('-l, --localhost', 'Connect to localhost API')
|
|
156
|
+
.option('-D, --debug', 'Some output for debugging')
|
|
157
|
+
.action( async (id, key, options) => {
|
|
158
|
+
let qrApi = RxAPI.API;
|
|
159
|
+
options.test && (qrApi = RxAPI.TESTAPI);
|
|
160
|
+
options.localhost && (qrApi = 'http://localhost:3000/');
|
|
161
|
+
const credentials = {
|
|
162
|
+
keyId: id || 'rxome',
|
|
163
|
+
key: key,
|
|
164
|
+
user: 'info@rxome.net'
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
options.debug && console.log( "Sending " , credentials , " to ", qrApi );
|
|
168
|
+
|
|
169
|
+
Coder.fetchKey( credentials, 'HANSMOTKAMP', qrApi, options.debug )
|
|
170
|
+
.then( result => {console.log( (result?.key && result?.pseudonym === '') ? 'OK' : 'An error occured')} )
|
|
171
|
+
.catch( error => {
|
|
172
|
+
console.log( error.code );
|
|
173
|
+
if (error.response) { // status !== 2xx
|
|
174
|
+
options.debug && console.log('\nResp. Data:\n', error.response.data);
|
|
175
|
+
options.debug && console.log('\nResp. Headers:\n', error.response.headers);
|
|
176
|
+
console.log('\nError ', error.response.status);
|
|
177
|
+
} else if (error.request) { // request send, but no response
|
|
178
|
+
options.debug && console.log('\nError client-request:\n', error.request);
|
|
179
|
+
} else { // request could not be send
|
|
180
|
+
options.debug && console.log('Error', error.message);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
program.command('encode')
|
|
187
|
+
.alias('e')
|
|
188
|
+
.description('encrypt message (just for testing)')
|
|
189
|
+
.argument('[input file]', 'Input text file (default: STDIN)')
|
|
190
|
+
.option('-o, --output <output file>', 'Output file (default: stdout)', '/dev/stdout')
|
|
191
|
+
.option('-k, --keyfile <keyfile>', 'name of public data encryption key file (not to be confused with the API access key!)', 'rxome.public.key')
|
|
192
|
+
.option('-j, --json', 'treat inputfile as json {key: ..., message: ...}', false)
|
|
193
|
+
.action( async (inputfile, options) => {
|
|
194
|
+
const data = FS.readFileSync( inputfile || '/dev/stdin' );
|
|
195
|
+
let message;
|
|
196
|
+
let key;
|
|
197
|
+
if ( options.json ) {
|
|
198
|
+
const dataJ = JSON.parse( data );
|
|
199
|
+
key = dataJ.key;
|
|
200
|
+
message = dataJ.message;
|
|
201
|
+
} else {
|
|
202
|
+
key = FS.readFileSync( options.keyfile ).toString();
|
|
203
|
+
message = data.toString();
|
|
204
|
+
}
|
|
205
|
+
const cipher = await Coder.encode( key, message );
|
|
206
|
+
FS.writeFileSync( options.output, cipher );
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
program.command('decode')
|
|
211
|
+
.alias('d')
|
|
212
|
+
.description('decode coded message or medical data')
|
|
213
|
+
.argument('[input file]', 'Input cipher file (default: STDIN)')
|
|
214
|
+
.option('-o, --output <output file>', 'Output file (default: stdout)', '/dev/stdout')
|
|
215
|
+
.option('-k, --keyfile <keyfile>', 'name of private data encryption key file', 'rxome.private.key')
|
|
216
|
+
.option('-j, --json', 'treat inputfile as json {key: ..., cipher: ...}', false)
|
|
217
|
+
.option('-c, --complete', 'also unpack PhenoPacket', false )
|
|
218
|
+
.option('-d, --debug', 'Output some debug data', false )
|
|
219
|
+
.action( async (inputfile, options) => {
|
|
220
|
+
const input = FS.readFileSync( inputfile || '/dev/stdin' );
|
|
221
|
+
let key;
|
|
222
|
+
let cipher;
|
|
223
|
+
if ( options.json ) {
|
|
224
|
+
const inputJ = JSON.parse( input );
|
|
225
|
+
cipher = inputJ.cipher;
|
|
226
|
+
key = inputJ.key;
|
|
227
|
+
} else {
|
|
228
|
+
cipher = input;
|
|
229
|
+
key = FS.readFileSync( options.keyfile ).toString();
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const data = await Coder.decode( key, cipher.toString() );
|
|
233
|
+
|
|
234
|
+
let result;
|
|
235
|
+
if ( options.complete ){
|
|
236
|
+
const clearBufferB64 = await Coder.decode( key, cipher.toString() );
|
|
237
|
+
options.debug && console.error( "buffer:", clearBufferB64 )
|
|
238
|
+
const clearB64 = RxAPI.base64ToBuffer(data);
|
|
239
|
+
options.debug && console.error( "clear ", clearB64 )
|
|
240
|
+
const phenoPrimeB64 = Coder.decodePhenoPacket(clearB64);
|
|
241
|
+
result = JSON.stringify(phenoPrimeB64);
|
|
242
|
+
} else {
|
|
243
|
+
result = data;
|
|
244
|
+
}
|
|
245
|
+
FS.writeFileSync( options.output, result );
|
|
246
|
+
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
program.command('rxome-keys')
|
|
251
|
+
.description('generate key pair for data encryption (see -e, -d; just for testing)')
|
|
252
|
+
.argument('[file prefix]', 'Prefix for file names (default: rxome)')
|
|
253
|
+
.option('-d, --directory <dir>', 'output directory', '.')
|
|
254
|
+
.action( (prefix, options) => {
|
|
255
|
+
Coder.generateRxomeKeyFiles( prefix || 'rxome', options.directory )
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
program.command('pheno2proto')
|
|
260
|
+
.alias('E')
|
|
261
|
+
.description('encode PhenoPacket to protobuf (just for testing)')
|
|
262
|
+
.argument('[input file]', 'Input text file (default: STDIN)')
|
|
263
|
+
.option('-o, --output <output file>', 'Output file (default: stdout)', '/dev/stdout')
|
|
264
|
+
.option('-b, --base64', 'Write output base64 encoded')
|
|
265
|
+
.option('-W, --whitelist', 'Preprocess: whitelist', false )
|
|
266
|
+
.option('-S, --sanitize', 'Preprocess: sanitize', false )
|
|
267
|
+
.option('-C, --compress', 'Preprocess: compress', false )
|
|
268
|
+
.action( async (inputfile, options) => {
|
|
269
|
+
//const { metaData, credentials, ...medical } = JSON.parse( FS.readFileSync( inputfile || '/dev/stdin' ));
|
|
270
|
+
const medical = JSON.parse( FS.readFileSync( inputfile || '/dev/stdin' ));
|
|
271
|
+
const whiteListMedical = options.sanitize ? Coder.whiteListPhenoPacket( medical ) : medical;
|
|
272
|
+
const sanitizedMedical = options.sanitize ? Coder.sanitizePhenoPacket( whiteListMedical ) : whiteListMedical;
|
|
273
|
+
const compressedMedical = options.compress ? Coder.compressPhenoPacket( sanitizedMedical ) : sanitizedMedical;
|
|
274
|
+
const protobufMedical = Coder.encodePhenoPacket( compressedMedical );
|
|
275
|
+
const outData = (options.base64 ? RxAPI.bufferToBase64( protobufMedical ) : protobufMedical );
|
|
276
|
+
FS.writeFileSync( options.output, outData );
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
program.command('proto2pheno')
|
|
281
|
+
.alias('D')
|
|
282
|
+
.description('decode protobuf to PhenoPacket (just for testing)')
|
|
283
|
+
.argument('[input file]', 'Input cipher file (default: STDIN)')
|
|
284
|
+
.option('-o, --output <output file>', 'Output file (default: stdout)', '/dev/stdout')
|
|
285
|
+
.option('-b, --base64', 'Read input base64 encoded')
|
|
286
|
+
.option('-p, --pretty', 'Pretty print output}')
|
|
287
|
+
|
|
288
|
+
.action( async (inputfile, options) => {
|
|
289
|
+
const input = FS.readFileSync( inputfile || '/dev/stdin' );
|
|
290
|
+
const data = ( options.base64 ? Uint8Array.from([...atob(input) ].map( c => c.charCodeAt(0))): input)
|
|
291
|
+
const pheno = Coder.decodePhenoPacket(data);
|
|
292
|
+
FS.writeFileSync( options.output, JSON.stringify(pheno, ' ', options.pretty ? 2 : 0) );
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
program.command('statistics')
|
|
297
|
+
.alias('s')
|
|
298
|
+
.argument('[input file]', 'Input JSON file (default: ./demos/demo_data_full.json)')
|
|
299
|
+
.description('print memory consuption for several stages and alternatives')
|
|
300
|
+
.action( async (inputfile, options) =>{
|
|
301
|
+
const fileName = inputfile || './demos/demo_data_full.json';
|
|
302
|
+
const data = JSON.parse( FS.readFileSync( fileName ));
|
|
303
|
+
const { metaData, credentials, ...medical } = data;
|
|
304
|
+
|
|
305
|
+
console.log( "Full : ", JSON.stringify(data).length );
|
|
306
|
+
console.log( "Medical : ", JSON.stringify(medical).length );
|
|
307
|
+
const whiteListMedical = Coder.whiteListPhenoPacket( medical );
|
|
308
|
+
console.log( "Whitelist : ", JSON.stringify(whiteListMedical).length );
|
|
309
|
+
const sanitizedMedical = Coder.sanitizePhenoPacket( whiteListMedical );
|
|
310
|
+
console.log( "Sanitized : ", JSON.stringify(sanitizedMedical).length );
|
|
311
|
+
const compressedMedical = Coder.compressPhenoPacket( sanitizedMedical );
|
|
312
|
+
console.log( "Compressed: ", JSON.stringify(compressedMedical).length );
|
|
313
|
+
//console.log( JSON.stringify(compressedMedical));
|
|
314
|
+
const protobufMedical = Coder.encodePhenoPacket( compressedMedical );
|
|
315
|
+
console.log( "Protobuf : ", protobufMedical.length );
|
|
316
|
+
//console.log( "Protobuf : ", protobufMedical );
|
|
317
|
+
//console.log( "Protobuf : ", protobufMedical.constructor.name );
|
|
318
|
+
// console.log( "- Hex : ", protobufMedical.toString('hex').length );;
|
|
319
|
+
//console.log( "- Utf8 : ", protobufMedical.toString('utf8').length )
|
|
320
|
+
|
|
321
|
+
console.log("===================================================================");
|
|
322
|
+
console.log("ProtoBuf, Encrypted:")
|
|
323
|
+
const cipherBin = await Coder.encode( DEMO_PUBLIC_KEY , protobufMedical, true);
|
|
324
|
+
console.log( "Cipher : ", cipherBin.length );
|
|
325
|
+
console.log( " - toString : " , cipherBin.toString().length );
|
|
326
|
+
// const clearBufferBin = await Coder.decode( DEMO_PRIVATE_KEY, '', cipherBin, true );
|
|
327
|
+
// const clearBin = Buffer.from (clearBufferBin, 'Binary');
|
|
328
|
+
// console.log( "Decrypted PhenoPacket: " , clearBin.length );
|
|
329
|
+
// const phenoPrimeBin = Coder.decodePhenoPacket(clearBin);
|
|
330
|
+
// const phenoBin = JSON.parse(JSON.stringify(phenoPrimeBin));
|
|
331
|
+
// console.log( "Original Data: : ", JSON.stringify(phenoBin).length );
|
|
332
|
+
|
|
333
|
+
console.log("===================================================================");
|
|
334
|
+
console.log("ProtoBuf, BASE64 Encoded, Encrypted:")
|
|
335
|
+
const protobufMedicalBase64 = RxAPI.bufferToBase64( protobufMedical );
|
|
336
|
+
console.log( "Base64 : ", protobufMedicalBase64.length );
|
|
337
|
+
const cipherB64 = await Coder.encode( DEMO_PUBLIC_KEY, protobufMedicalBase64 );
|
|
338
|
+
console.log( "Cipher Base64: ", cipherB64.length );
|
|
339
|
+
console.log( " - toString : ", cipherB64.toString().length );
|
|
340
|
+
//console.log(" B64 ", cipherB64 )
|
|
341
|
+
const clearBufferB64 = await Coder.decode( DEMO_PRIVATE_KEY, cipherB64 );
|
|
342
|
+
//console.log( "buffer:", clearBufferB64 )
|
|
343
|
+
//const clearB64_2 = Buffer.from (clearBufferB64, 'base64');
|
|
344
|
+
const clearB64 = RxAPI.base64ToBuffer( clearBufferB64 );
|
|
345
|
+
console.log( "Decrypted PhenoPacket: " , clearB64.length );
|
|
346
|
+
const phenoPrimeB64 = Coder.decodePhenoPacket(clearB64);
|
|
347
|
+
const phenoB64 = JSON.parse(JSON.stringify(phenoPrimeB64));
|
|
348
|
+
console.log( "Original Data: ", JSON.stringify(phenoB64).length );
|
|
349
|
+
//console.log( JSON.stringify(phenoB64, ' ', 2) );
|
|
350
|
+
|
|
351
|
+
// qrData = {
|
|
352
|
+
// keyver: "key.version",
|
|
353
|
+
// apiver: "apiVer",
|
|
354
|
+
// pseudonym: "key.pseudonym",
|
|
355
|
+
// payload: cipherBin.toString()
|
|
356
|
+
// }
|
|
357
|
+
// console.log( "QR-Data: ", JSON.stringify( qrData ).length )
|
|
358
|
+
//const ps_lab = await Coder.writeQR( "stat.png", qrData, RxAPI.TESTAPI );
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
console.log("===================================================================");
|
|
362
|
+
console.log("Without ProtoBuf, Encrypted:")
|
|
363
|
+
const cryptCompressed = await Coder.encode( DEMO_PUBLIC_KEY , JSON.stringify( compressedMedical ) );
|
|
364
|
+
console.log( "Cipher: ", cryptCompressed.length );
|
|
365
|
+
console.log( " - toString : " , cryptCompressed.toString().length )
|
|
366
|
+
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
// program.command('run')
|
|
371
|
+
// .argument('[input file]', 'Input JSON file (default: ./demos/demo_data_full.json)')
|
|
372
|
+
// .action( async (inputfile, options) =>{
|
|
373
|
+
// // const fileName = options.input || './demos/demo_data_full.json';
|
|
374
|
+
// // //file = inputfile || '/dev/stdin'
|
|
375
|
+
// // const data = JSON.parse( FS.readFileSync( fileName ));
|
|
376
|
+
// // // const ps_lab = await Coder.writeQR( "ZZZtest.png", data, RxAPI.TESTAPI );
|
|
377
|
+
// // console.log( data );
|
|
378
|
+
// // console.log( Coder.whiteListPhenoPacket( data ) );
|
|
379
|
+
// // console.log( {
|
|
380
|
+
// // ...data.subject
|
|
381
|
+
// // })
|
|
382
|
+
// const resp = await Coder.fetchKey( DEMO_CREDENTIALS, 'foo', RxAPI.TESTAPI )
|
|
383
|
+
// console.log( resp );
|
|
384
|
+
|
|
385
|
+
// data = { name: 'foobar', number: 42, ping: 'fiedeldiedel'}
|
|
386
|
+
// const message = JSON.stringify(data)
|
|
387
|
+
// const { privateKey, publicKey } = await Coder.generateRxomeKeys( )
|
|
388
|
+
// Coder.encode(publicKey, message)
|
|
389
|
+
// .then(cipher => {
|
|
390
|
+
// console.log( cipher )
|
|
391
|
+
// return Coder.decode(privateKey, cipher)
|
|
392
|
+
// })
|
|
393
|
+
// .then(clear => {console.log( JSON.parse(clear) )})
|
|
394
|
+
|
|
395
|
+
// console.log( JSON.stringify( Coder.fetchKey( DEMO_CREDENTIALS, '', RxAPI.TESTAPI )));
|
|
396
|
+
|
|
397
|
+
// });
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
program.parse();
|
|
401
|
+
|
package/rxcode.test.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const { exec } = require("child_process");
|
|
2
|
+
const FS = require( 'fs' );
|
|
3
|
+
//const { default: test } = require("node:test");
|
|
4
|
+
const Coder = require( './lib/rxome-generator' );
|
|
5
|
+
|
|
6
|
+
DEMO_CIPHER = `
|
|
7
|
+
-----BEGIN PGP MESSAGE-----
|
|
8
|
+
|
|
9
|
+
wV4Dhx/ATfJT0nQSAQdAQB3UcIAE5hMbtWJLiaDIrIiuNBRYzYPPGe4Ry40A
|
|
10
|
+
oCkw9Tf0OlDdDEqrCfGWseuYgdbgpqUSYJMTgmnmj8S2KxqU30eW10fu+lzt
|
|
11
|
+
0a8vvetS0loB8ktDgqeRfFeusC8L5vBVD6r5PixaZYWjhcaL1ZrcEl211ArW
|
|
12
|
+
Qvk3mk17r9xwp26rVXk5NX/feTNXr19907RdPM1oT7zWetTpwx8ow6KZZrGB
|
|
13
|
+
ZcabBZ5ti/o=
|
|
14
|
+
=6tRv
|
|
15
|
+
-----END PGP MESSAGE-----
|
|
16
|
+
`
|
|
17
|
+
|
|
18
|
+
const PRIVATE_KEY = Coder.DEMO_PRIVATE_KEY;
|
|
19
|
+
const PUBLIC_KEY = Coder.DEMO_PUBLIC_KEY;
|
|
20
|
+
|
|
21
|
+
async function execCmd( cmd ) {
|
|
22
|
+
const exec = require('child_process').exec;
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
exec(cmd, (error, stdout, stderr) => {
|
|
25
|
+
const result = {
|
|
26
|
+
error: error,
|
|
27
|
+
stdout: stdout,
|
|
28
|
+
stderr: stderr
|
|
29
|
+
}
|
|
30
|
+
if (error) {
|
|
31
|
+
console.warn(error);
|
|
32
|
+
}
|
|
33
|
+
resolve( result );
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
describe('CmdLine generate', () => {
|
|
39
|
+
it.skip('generates a qr code from demo data', () => {
|
|
40
|
+
FS.rm( 'zzz.png' );
|
|
41
|
+
execCmd( 'rxcode g -t -o zzz.png demos/demo_data_full.json' )
|
|
42
|
+
.then( result => {
|
|
43
|
+
console.log( result.stdout )
|
|
44
|
+
console.log( result.stderr )
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
// describe('generate keys', () => {
|
|
51
|
+
// test.skip('creates two files', async () => {
|
|
52
|
+
// const dir = '.';
|
|
53
|
+
// const ex = await execCmd( 'node rxcode.js generate testsuite foo@bar.baz ' );
|
|
54
|
+
// const publicKeyFile = `${dir}/testsuite.public.key`;
|
|
55
|
+
// const privateKeyFile = `${dir}/testsuite.private.key`;
|
|
56
|
+
// expect( ex.error ).toBeNull();
|
|
57
|
+
// expect( ex.stdout ).toBe('');
|
|
58
|
+
// expect( ex.stderr ).toBe('');
|
|
59
|
+
// expect( FS.existsSync( publicKeyFile )).toBeTruthy();
|
|
60
|
+
// expect( FS.existsSync( privateKeyFile )).toBeTruthy();
|
|
61
|
+
// const privStats = FS.statSync( privateKeyFile );
|
|
62
|
+
// expect( privStats.size ).toBe( 850 );
|
|
63
|
+
// const pubStats = FS.statSync( publicKeyFile );
|
|
64
|
+
// expect( pubStats.size ).toBe( 624 );
|
|
65
|
+
// const privateKey = FS.readFileSync( privateKeyFile, { encoding: 'utf8' }, err => { console.log(err) } );
|
|
66
|
+
// expect( privateKey ).toContain( 'BEGIN PGP PRIVATE KEY BLOCK' );
|
|
67
|
+
// const publicKey = FS.readFileSync( publicKeyFile, { encoding: 'utf8' }, err => { console.log(err) } );
|
|
68
|
+
// expect( publicKey ).toContain( 'BEGIN PGP PUBLIC KEY BLOCK' );
|
|
69
|
+
// })
|
|
70
|
+
|
|
71
|
+
// });
|
|
72
|
+
|
|
73
|
+
// //describe('encode', () => {
|
|
74
|
+
|
|
75
|
+
// //});
|
|
76
|
+
// describe('CmdLine help', async () => {
|
|
77
|
+
// test.skip( 'show help', () => {
|
|
78
|
+
// const result = execCmd( 'rxcode --help');
|
|
79
|
+
|
|
80
|
+
// })
|
|
81
|
+
|
|
82
|
+
// });
|
|
83
|
+
|
|
84
|
+
// describe('CmdLine decode', async () => {
|
|
85
|
+
// test.skip( 'decodes file', () => {
|
|
86
|
+
// });
|
|
87
|
+
|
|
88
|
+
// });
|
|
89
|
+
/*
|
|
90
|
+
echo -n 'the answer to life the universe and everything' | rxcode e -k rxome.public.key > rxome.message
|
|
91
|
+
|
|
92
|
+
rxcode d rxome.message
|
|
93
|
+
rxcode d < rxome.message
|
|
94
|
+
rxcode d -j rxome.decrypt.json
|
|
95
|
+
rxcode d -j rxome.decrypt.json
|
|
96
|
+
rxcode d -j < rxome.decrypt
|
|
97
|
+
|
|
98
|
+
rxcode P test Cs67c7aXYhZQbjU2W/4q6sBu/oIQ8zONSBURUH8g2wQ=
|
|
99
|
+
OK
|
|
100
|
+
rxcode P mgz QhcoRruGBVP39XCh8BujCE+q42qCRy/tu2CQ4YmRBgg=
|
|
101
|
+
OK
|
|
102
|
+
rxcode P rxome NamaTB+xwDFxtkQyBBkjRr5GEaXNtCw/G4qydnhQk5Y=
|
|
103
|
+
OK
|
|
104
|
+
*/
|