rxome-generator 1.0.3 → 1.0.4-beta.2

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.
@@ -1,16 +1,17 @@
1
1
  // https://openpgpjs.org/
2
- const PGP = require( 'openpgp' );
2
+ import * as PGP from 'openpgp';
3
3
 
4
4
  // https://github.com/soldair/node-qrcode
5
- const QRCode = require( 'qrcode' );
5
+ import QRCode from 'qrcode';
6
6
 
7
- const jsonKeyConverter = require('json-key-converter');
8
- const Protobuf = require('protobufjs');
9
- const PhenoPacketDescriptor = require("./phenopackets.json");
7
+ import jsonKeyConverter from 'json-key-converter';
8
+ import Protobuf from 'protobufjs';
9
+ import PhenoPacketDescriptor from "./phenopackets.js";
10
+ import { version } from './package-info.js';
10
11
 
11
12
  //const { constants } = require('buffer');
12
13
 
13
- const RxAPI= require('./rxome-api.cjs');
14
+ import * as RxAPI from './rxome-api.js';
14
15
 
15
16
  const apiVer = '1.0';
16
17
  const RXAPI = RxAPI.API;
@@ -24,35 +25,42 @@ const ProtoBufRoot = Protobuf.Root.fromJSON( PhenoPacketDescriptor );
24
25
  const PhenoPacket = ProtoBufRoot.lookupType('org.phenopackets.schema.v2.Phenopacket')
25
26
 
26
27
  const ENUM_SEX = ['UNKNOWN', 'FEMALE', 'MALE', 'OTHER']
27
- exports.ENUM_SEX = ENUM_SEX;
28
+ export { ENUM_SEX };
28
29
 
29
30
  const ENUM_PROG_STATE = ['UNKNOWN_PROGRESS', 'IN_PROGRESS', 'COMPLETED', 'SOLVED', 'UNSOLVED']
30
- exports.ENUM_PROG_STATE = ENUM_PROG_STATE;
31
+ export { ENUM_PROG_STATE };
31
32
 
32
- const ENUM_ACMG =
33
+ const ENUM_ACMG =
33
34
  ['NOT_PROVIDED', 'BENIGN', 'LIKELY_BENIGN', 'UNCERTAIN_SIGNIFICANCE', 'LIKELY_PATHOGENIC', 'PATHOGENIC'];
34
35
 
35
- exports.ENUM_ACMG = ENUM_ACMG;
36
+ export { ENUM_ACMG };
36
37
 
37
38
 
38
39
  /************************************************************************************
39
40
  * Functions for node.js only
40
41
  ************************************************************************************/
41
42
 
42
- try {
43
- const FS = require( 'fs/promises' );
44
- const { version } = require('os');
45
-
46
- exports.generateRxomeKeyFiles = async (name = 'rxome', dir = '.') => {
47
- const { privateKey, publicKey } = await exports.generateRxomeKeys( name );
43
+ export const generateRxomeKeyFiles = async (name = 'rxome', dir = '.') => {
44
+ try {
45
+ const FS = await import('fs/promises');
46
+ const { privateKey, publicKey } = await generateRxomeKeys( name );
48
47
  await Promise.all([
49
48
  FS.writeFile(`${dir}/${name}.private.key`, privateKey, { mode: 0o600 }, err => { console.log(err); }),
50
49
  FS.writeFile(`${dir}/${name}.public.key`, publicKey, { mode: 0o600 }, function (err) { console.log(err); })
51
50
  ]);
52
51
  }
53
-
54
- exports.writeQR = async ( filename, data, api = RXAPI, apiEntry = APIENTRY ) => {
55
- const {qrData, pseudonym, content} = await exports.prepareQR( data, api, apiEntry );
52
+ catch (e) {
53
+ if (e instanceof Error && e.code !== "MODULE_NOT_FOUND") {
54
+ throw e;
55
+ } else {
56
+ throw new Error('fs module not available - cannot write key files');
57
+ }
58
+ }
59
+ }
60
+
61
+ export const writeQR = async ( filename, data, api = RXAPI, apiEntry = APIENTRY ) => {
62
+ try {
63
+ const {qrData, pseudonym, content} = await prepareQR( data, api, apiEntry );
56
64
  //const base64Data = qr_code.replace(/^data:image\/png;base64,/, "");
57
65
  //FS.writeFile(filename, base64Data, 'base64', (err) => {console.log(err)} );
58
66
  QRCode.toFile( filename, JSON.stringify( qrData ), { type: 'png'} )
@@ -61,19 +69,20 @@ try {
61
69
  qr_content: content
62
70
  }
63
71
  }
64
- }
65
-
66
- catch (e) {
67
- if (e instanceof Error && e.code !== "MODULE_NOT_FOUND") {
68
- throw e;
72
+ catch (e) {
73
+ if (e instanceof Error && e.code !== "MODULE_NOT_FOUND") {
74
+ throw e;
75
+ } else {
76
+ throw new Error('fs module not available - cannot write QR file');
77
+ }
69
78
  }
70
79
  }
71
80
 
72
81
  /************************************************************************************/
73
82
 
74
83
 
75
- exports.generateRxomeKeys = async (name = 'rxome') => {
76
- return { privateKey, publicKey, revocationCertificate } = await PGP.generateKey({
84
+ export const generateRxomeKeys = async (name = 'rxome') => {
85
+ const { privateKey, publicKey, revocationCertificate } = await PGP.generateKey({
77
86
  type: 'ecc',
78
87
  curve: 'curve25519',
79
88
  //type: 'rsa',
@@ -82,41 +91,42 @@ exports.generateRxomeKeys = async (name = 'rxome') => {
82
91
  passphrase: PASSPHRASE,
83
92
  format: 'armored'
84
93
  });
94
+ return { privateKey, publicKey, revocationCertificate };
85
95
  }
86
96
 
87
97
 
88
- exports.fetchKey = async ( credentials, pseudonym = '', api = RXAPI, debug = false, apiEntry = APIENTRY ) => {
98
+ export const fetchKey = async ( credentials, pseudonym = '', api = RXAPI, debug = false, apiEntry = APIENTRY ) => {
89
99
  const result = await RxAPI.fetchData( `${api}/${apiEntry}/getpseudonym`, credentials, pseudonym, debug )
90
100
  if ( result.pseudonym === '' )
91
101
  result.pseudonym = pseudonym;
92
102
  return result;
93
103
  }
94
- /*
104
+ /*
95
105
  yields: { key: PGP_key, version: ..., pseudonym: ... }
96
106
  */
97
-
98
-
99
- exports.fetchDemoPrivateKey = async ( credentials, api=RXTESTAPI, debug = false, apiEntry = APIENTRY ) =>
107
+
108
+
109
+ export const fetchDemoPrivateKey = async ( credentials, api=RXTESTAPI, debug = false, apiEntry = APIENTRY ) =>
100
110
  await RxAPI.fetchData( `${api}/${apiEntry}/getprivatedemokey`, credentials, '', debug )
101
111
 
102
- /*
103
- yields: { private_key: PGP_key }
112
+ /*
113
+ yields: { private_key: PGP_key }
104
114
  */
105
115
 
106
- exports.fetchRxomeKey = async ( credentials, api = RXAPI, debug = false, apiEntry = APIENTRY ) =>
116
+ export const fetchRxomeKey = async ( credentials, api = RXAPI, debug = false, apiEntry = APIENTRY ) =>
107
117
  await RxAPI.fetchData( `${api}/${apiEntry}/getrxomekey`, credentials, '', debug )
108
118
 
109
- /*
110
- yields: { key: PGP_key, version: ... }
119
+ /*
120
+ yields: { key: PGP_key, version: ... }
111
121
  */
112
- exports.convert_to_snake_case = data => jsonKeyConverter.convert( data, { camel: false } );
122
+ export const convert_to_snake_case = data => jsonKeyConverter.convert( data, { camel: false } );
113
123
 
114
- exports.convertToCamelCase = data => jsonKeyConverter.convert( data, { camel: true } );
124
+ export const convertToCamelCase = data => jsonKeyConverter.convert( data, { camel: true } );
115
125
 
116
- exports.compressPhenoPacket = ( data ) => {
126
+ export const compressPhenoPacket = ( data ) => {
117
127
  const compressedData = {
118
128
  ...data,
119
- };
129
+ };
120
130
  if ( data.phenotypicFeatures ) {
121
131
  compressedData.compressedFeatures = {
122
132
  includes: data.phenotypicFeatures.filter( feat => feat.excluded === undefined || feat.excluded === false || feat.excluded === 'false' ).map( feat => feat.type.id ),
@@ -128,26 +138,30 @@ exports.compressPhenoPacket = ( data ) => {
128
138
  }
129
139
 
130
140
 
131
- exports.sanitizeSex = ( str ) =>
141
+ export const sanitizeSex = ( str ) =>
132
142
  isNaN(+(str.toString()))
133
143
  ? Math.max(0, ENUM_SEX.indexOf(str.toUpperCase().replace('_SEX', '')))
134
144
  : +str;
135
145
 
136
146
 
137
- exports.sanitizeProgState = ( str ) =>
147
+ export const sanitizeProgState = ( str ) =>
138
148
  isNaN(+(str.toString()))
139
149
  ? Math.max(0, ENUM_PROG_STATE.indexOf(str.toUpperCase()))
140
150
  : +str;
141
151
 
142
152
 
143
- exports.sanitizeACMG = ( str ) =>
153
+ export const sanitizeACMG = ( str ) => {
154
+ // special case for 'RISK_ALLELE'
155
+ if ( str == 'RISK_ALLELE' ) {
156
+ return 999;
157
+ }
144
158
  isNaN(+(str.toString()))
145
159
  ? Math.max(0, ENUM_ACMG.indexOf(str.toUpperCase()))
146
160
  : +str
161
+ }
147
162
 
148
-
149
- exports.whiteListPhenoPacket = ( data ) => {
150
- res = {};
163
+ export const whiteListPhenoPacket = ( data ) => {
164
+ let res = {};
151
165
  data.id && (res.id = data.id);
152
166
  data.comment && (res.comment = data.comment);
153
167
  data.subject && (res.subject = data.subject);
@@ -161,48 +175,48 @@ exports.whiteListPhenoPacket = ( data ) => {
161
175
  }
162
176
 
163
177
 
164
- exports.sanitizePhenoPacket = ( data, key = '' ) => {
178
+ export const sanitizePhenoPacket = ( data, key = '' ) => {
165
179
  if ( data instanceof Object ) {
166
180
  if (Array.isArray( data )) {
167
- return data.map( x => exports.sanitizePhenoPacket(x));
181
+ return data.map( x => sanitizePhenoPacket(x));
168
182
  } else {
169
183
  let obj={};
170
- for ( let k in data ) {
171
- obj[k] = exports.sanitizePhenoPacket( data[k], k );
184
+ for ( let k in data ) {
185
+ obj[k] = sanitizePhenoPacket( data[k], k );
172
186
  }
173
187
  return obj;
174
188
  }
175
189
  } else {
176
190
  switch( key ){
177
191
  case 'sex':
178
- return exports.sanitizeSex( data );
192
+ return sanitizeSex( data );
179
193
  case 'progressStatus':
180
- return exports.sanitizeProgState( data );
194
+ return sanitizeProgState( data );
181
195
  case 'acmgPathogenicityClassification':
182
- return exports.sanitizeACMG( data );
183
- default:
196
+ return sanitizeACMG( data );
197
+ default:
184
198
  return data;
185
199
  }
186
200
  }
187
201
  }
188
202
 
189
203
 
190
- exports.verifyPhenoPacket = (data) => (
204
+ export const verifyPhenoPacket = (data) => (
191
205
  PhenoPacket.verify( data )
192
206
  )
193
207
 
194
208
 
195
- exports.encodePhenoPacket = (data) => (
209
+ export const encodePhenoPacket = (data) => (
196
210
  PhenoPacket.encode( data ).finish()
197
211
  )
198
212
 
199
213
 
200
- exports.decodePhenoPacket = (data) => (
214
+ export const decodePhenoPacket = (data) => (
201
215
  PhenoPacket.decode( data )
202
216
  )
203
217
 
204
218
 
205
- exports.encode_serial = async (publicKeyStr, message) => {
219
+ export const encode_serial = async (publicKeyStr, message) => {
206
220
  const publicKey = await PGP.readKey({ armoredKey: publicKeyStr });
207
221
  const encrypted = await PGP.encrypt({
208
222
  message: await PGP.createMessage({ text: message }),
@@ -214,10 +228,10 @@ exports.encode_serial = async (publicKeyStr, message) => {
214
228
  }
215
229
 
216
230
 
217
- exports.encode = async (publicKeyStr, message, binary = false) => {
231
+ export const encode = async (publicKeyStr, message, binary = false) => {
218
232
  return await Promise.all([
219
233
  PGP.readKey({ armoredKey: publicKeyStr }),
220
- PGP.createMessage( (binary
234
+ PGP.createMessage( (binary
221
235
  ? { binary: message, format: 'binary' }
222
236
  : { text: message }) )
223
237
  ]).then( async ([publicKey, message]) => {
@@ -233,7 +247,7 @@ exports.encode = async (publicKeyStr, message, binary = false) => {
233
247
  }
234
248
 
235
249
 
236
- exports.decode_serial = async (privateKeyStr, encrypted) => {
250
+ export const decode_serial = async (privateKeyStr, encrypted) => {
237
251
  const privateKey = await PGP.readPrivateKey( { armoredKey: privateKeyStr } );
238
252
  const privateKeyDecr = await PGP.decryptKey({
239
253
  privateKey: privateKey,
@@ -250,16 +264,16 @@ exports.decode_serial = async (privateKeyStr, encrypted) => {
250
264
  }
251
265
 
252
266
 
253
- exports.decode = async (privateKeyStr, encrypted, binary = false) => {
267
+ export const decode = async (privateKeyStr, encrypted, binary = false) => {
254
268
  return await Promise.all([
255
269
  PGP.readPrivateKey({ armoredKey: privateKeyStr })
256
270
  .then( (privateKey) => {
257
271
  return PGP.decryptKey({
258
272
  privateKey: privateKey,
259
- passphrase: PASSPHRASE
273
+ passphrase: PASSPHRASE
260
274
  })
261
275
  }),
262
- PGP.readMessage( (binary
276
+ PGP.readMessage( (binary
263
277
  ? {binaryMessage: encrypted}
264
278
  : {armoredMessage: encrypted} )
265
279
  )
@@ -282,27 +296,28 @@ exports.decode = async (privateKeyStr, encrypted, binary = false) => {
282
296
  }
283
297
 
284
298
 
285
- exports.prepareQR = async ( data, api = RXAPI, apiEntry = APIENTRY ) => {
299
+ export const prepareQR = async ( data, api = RXAPI, apiEntry = APIENTRY ) => {
300
+ console.log(`RxOME QR Generator version: ${version}`);
286
301
  const { metaData, credentials, ...medical } = data;
287
302
 
288
- const whiteListMedical = exports.whiteListPhenoPacket( medical );
289
- const sanitizedMedical = exports.sanitizePhenoPacket( whiteListMedical );
290
- const compressedMedical = exports.compressPhenoPacket( sanitizedMedical );
291
- const protobufMedical = exports.encodePhenoPacket( compressedMedical );
303
+ const whiteListMedical = whiteListPhenoPacket( medical );
304
+ const sanitizedMedical = sanitizePhenoPacket( whiteListMedical );
305
+ const compressedMedical = compressPhenoPacket( sanitizedMedical );
306
+ const protobufMedical = encodePhenoPacket( compressedMedical );
292
307
  const base64Medical = RxAPI.bufferToBase64(protobufMedical);
293
308
 
294
- const key = await this.fetchKey( credentials, metaData?.pseudonym || '', api, false, apiEntry );
309
+ const key = await fetchKey( credentials, (metaData && metaData.pseudonym) || '', api, false, apiEntry );
295
310
 
296
311
  // check:
297
312
  const buff = RxAPI.base64ToBuffer( base64Medical );
298
- const pheno = exports.decodePhenoPacket( buff );
313
+ const pheno = decodePhenoPacket( buff );
299
314
  const medicalDeciphered = JSON.parse( JSON.stringify( pheno ));
300
315
  // console.log( JSON.stringify(medicalDeciphered,' ', 2 ))
301
316
 
302
- const cipher = await exports.encode( key.key, base64Medical );
317
+ const cipher = await encode( key.key, base64Medical );
303
318
 
304
319
  //delete metaData.pseudonym;
305
- const newMetaData = Object.fromEntries(
320
+ const newMetaData = Object.fromEntries(
306
321
  Object.entries( metaData ).filter( ([key, val]) => key !== 'pseudonym')
307
322
  )
308
323
 
@@ -312,7 +327,7 @@ exports.prepareQR = async ( data, api = RXAPI, apiEntry = APIENTRY ) => {
312
327
  labid: key.lab_id,
313
328
  keyver: key.version,
314
329
  apiver: apiVer,
315
- pseudonym: key.pseudonym,
330
+ pseudonym: key.pseudonym,
316
331
  payload: cipher.toString()
317
332
  }
318
333
 
@@ -331,8 +346,8 @@ exports.prepareQR = async ( data, api = RXAPI, apiEntry = APIENTRY ) => {
331
346
  }
332
347
 
333
348
 
334
- exports.makeQR = async ( data, api = RXAPI, apiEntry = APIENTRY ) => {
335
- const {qrData, pseudonym, content} = await exports.prepareQR( data, api, apiEntry );
349
+ export const makeQR = async ( data, api = RXAPI, apiEntry = APIENTRY ) => {
350
+ const {qrData, pseudonym, content} = await prepareQR( data, api, apiEntry );
336
351
  return {
337
352
  qr_code: await QRCode.toDataURL( JSON.stringify( qrData )),
338
353
  pseudonym: pseudonym,
@@ -341,8 +356,8 @@ exports.makeQR = async ( data, api = RXAPI, apiEntry = APIENTRY ) => {
341
356
  }
342
357
  }
343
358
 
344
- exports.versionStr = () => {
345
- return 'RxOME QR Generator 1.0.0, 2022 Tom Kamphans, GeneTalk GmbH'
359
+ export const versionStr = () => {
360
+ return `RxOME QR Generator ${version}, 2025 Tom Kamphans, GeneTalk GmbH/RxOme GmbH`
346
361
  }
347
362
 
348
363
 
@@ -356,5 +371,4 @@ exports.versionStr = () => {
356
371
  // const clearBin = Buffer.from (clearBufferBin, 'Binary');
357
372
  // const phenoPrimeBin = Coder.decodePhenoPacket(clearBin);
358
373
  // const phenoBin = JSON.parse(JSON.stringify(phenoPrimeBin));
359
- // ////
360
-
374
+ // ////
@@ -1,9 +1,10 @@
1
- const Coder = require('./rxome-generator');
2
- const RxAPI = require( './rxome-api' );
3
- const ApiDemo = require( './rxome-api-demo');
1
+ import * as Coder from './rxome-generator.js';
2
+ import * as RxAPI from './rxome-api.js';
3
+ import * as ApiDemo from './rxome-api-demo.js';
4
+ import { getFetch } from './rxome-api.js';
4
5
 
5
- const FS = require('fs');
6
- const Axios = require( 'axios' );
6
+ import { readFileSync } from 'fs';
7
+ // Using native fetch API instead of axios
7
8
 
8
9
  const RXAPI = RxAPI.API;
9
10
  const RXTESTAPI = RxAPI.TESTAPI;
@@ -16,9 +17,9 @@ const CREDENTIALS = {
16
17
  key: ApiDemo.DEMO_API_PRIVATE_KEY
17
18
  }
18
19
 
19
- const DEMO_DATA = JSON.parse(FS.readFileSync('./demos/demo_data_full.json'));
20
+ const DEMO_DATA = JSON.parse(readFileSync('./demos/demo_data_full.json'));
20
21
 
21
- const DEMO_DATA_COMPRESSED = JSON.parse(FS.readFileSync('./demos/demo_data_full_compressed.json'));
22
+ const DEMO_DATA_COMPRESSED = JSON.parse(readFileSync('./demos/demo_data_full_compressed.json'));
22
23
  // compressed: without credentials due to whitelist/phenopacket filtering
23
24
 
24
25
  const DEMO_PSEUDONYM = 'HANSMOTKAMP';
@@ -98,7 +99,7 @@ describe('API access', () => {
98
99
  Coder.fetchKey(wrong_credentials, 'lab_ps', RXTESTAPI)
99
100
  .then(data => { })
100
101
  .catch(err => {
101
- expect(err.response?.status.toString().toMatch('403'));
102
+ expect(err.response && err.response.status.toString().toMatch('403'));
102
103
  });
103
104
  });
104
105
  });
@@ -277,8 +278,8 @@ describe('Coder', () => {
277
278
  test('should encode and decode with key files', async () => {
278
279
  const message = 'Be Sure To Drink Your Ovaltine';
279
280
  await Coder.generateRxomeKeyFiles( 'testsuite' );
280
- const privateKey = FS.readFileSync('./testsuite.private.key').toString();
281
- const publicKey = FS.readFileSync('./testsuite.public.key').toString();
281
+ const privateKey = readFileSync('./testsuite.private.key').toString();
282
+ const publicKey = readFileSync('./testsuite.public.key').toString();
282
283
  const cipher = await Coder.encode(publicKey, message);
283
284
  const clear = await Coder.decode(privateKey, cipher);
284
285
  expect(clear).toBe(message);
@@ -291,14 +292,22 @@ describe('Rails', () => {
291
292
  const message = 'A-well-a bird bird bird, bird is the word';
292
293
  const cipher = await Coder.encode(PUBLIC_KEY, message);
293
294
 
294
- const res = await Axios({
295
- method$: 'GET',
296
- url: `${RXTESTAPI}/api/v1/decryptTest`,
297
- data: {
298
- cipher: cipher
295
+ const params = new URLSearchParams({
296
+ cipher: cipher
297
+ });
298
+ const fetch = await getFetch();
299
+ const res = await fetch(`${RXTESTAPI}/api/v1/decryptTest?${params}`, {
300
+ method: 'GET',
301
+ headers: {
302
+ 'Content-Type': 'application/json'
299
303
  }
300
- })
301
- expect( res.data?.clearText ).toEqual( message )
304
+ }).then(response => {
305
+ if (!response.ok) {
306
+ throw new Error(`HTTP error! status: ${response.status}`);
307
+ }
308
+ return response.json();
309
+ }).then(data => ({ data }))
310
+ expect( res.data && res.data.clearText ).toEqual( message )
302
311
  });
303
312
  });
304
313
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rxome-generator",
3
- "version": "1.0.3",
3
+ "version": "1.0.4-beta.2",
4
4
  "description": "Generates QR codes containing medical information for use with the FindMe2Care platform.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -32,10 +32,10 @@
32
32
  "homepage": "https://github.com/GeneTalkTK/rxome-qrcode-generator#readme",
33
33
  "dependencies": {
34
34
  "@noble/ed25519": "^2.2.3",
35
- "axios": "^1.7.9",
36
35
  "commander": "^13.1.0",
37
36
  "json-key-converter": "^1.0.0",
38
37
  "noble-ed25519": "^1.2.6",
38
+ "node-fetch": "^3.3.2",
39
39
  "openpgp": "^6.1.0",
40
40
  "protobufjs": "^7.4.0",
41
41
  "protobufjs-cli": "^1.1.3",
@@ -48,5 +48,14 @@
48
48
  },
49
49
  "bin": {
50
50
  "rxcode": "rxcode.js"
51
+ },
52
+ "jest": {
53
+ "globals": {
54
+ "NODE_OPTIONS": "--experimental-vm-modules"
55
+ },
56
+ "moduleNameMapper": {
57
+ "^(\\.{1,2}/.*)\\.js$": "$1"
58
+ },
59
+ "transform": {}
51
60
  }
52
61
  }
package/rxcode.js CHANGED
@@ -4,9 +4,9 @@ import * as FS from 'fs';
4
4
  import sharp from 'sharp';
5
5
 
6
6
  // const Coder = require( './lib/rxome-generator' );
7
- import * as Coder from './lib/rxome-generator.cjs';
8
- import * as ApiDemo from './lib/rxome-api-demo.cjs' ;
9
- import * as RxAPI from './lib/rxome-api.cjs';
7
+ import * as Coder from './lib/rxome-generator.js';
8
+ import * as ApiDemo from './lib/rxome-api-demo.js' ;
9
+ import * as RxAPI from './lib/rxome-api.js';
10
10
 
11
11
  import { program } from 'commander';
12
12
  import * as Path from 'path';
@@ -186,6 +186,10 @@ program.command('preprocess')
186
186
  .option('-c, --compress', 'Compact HPO term list')
187
187
  .action( async (inputfile, options) => {
188
188
  let data = JSON.parse(FS.readFileSync( inputfile || '/dev/stdin' ));
189
+ if (! (options.case || options.whitelist || options.sanitize || options.compress)) {
190
+ process.stderr.write( 'Error: at least one preprocessing option must be selected (-C, -w, -s, -c).');
191
+ return 1;
192
+ }
189
193
  options.case && (data = Coder.convertToCamelCase( data ));
190
194
  options.whitelist && (data = Coder.whiteListPhenoPacket( data ));
191
195
  options.sanitize && (data = Coder.sanitizePhenoPacket( data ));
@@ -306,12 +310,15 @@ program.command('decrypt')
306
310
  key = FS.readFileSync( options.keyfile ).toString();
307
311
  }
308
312
 
313
+ //@TODO: Guard against missing key or cipher
309
314
  const data = await Coder.decode( key, cipher.toString() );
310
315
 
311
316
  let result;
312
317
  if ( options.complete ){
313
- const clearBufferB64 = await Coder.decode( key, cipher.toString() );
314
- options.debug && console.error( "buffer:", clearBufferB64 )
318
+ if ( options.debug ) {
319
+ const clearBufferB64 = await Coder.decode( key, cipher.toString() );
320
+ console.error( "buffer:", clearBufferB64 )
321
+ }
315
322
  const clearB64 = RxAPI.base64ToBuffer(data);
316
323
  options.debug && console.error( "clear ", clearB64 )
317
324
  const phenoPrimeB64 = Coder.decodePhenoPacket(clearB64);