rxome-generator 1.0.2 → 1.0.3

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/README.md CHANGED
@@ -1,7 +1,9 @@
1
- # FindMe2Care (RxOME) QR-code generator
2
- Generates QR codes containing medical information for use with the FindMe2Care database
1
+ # TODO:
2
+ * how to connect to docker container (shell)
3
+
4
+ # FindMe2care (RxOME) QR-code generator
5
+ Generates QR codes containing medical information for use with the FindMe2care platform
3
6
  (formerly called RxOME).
4
- **Right now, it works only with the test API (-t, Coder.TESTAPI)**
5
7
 
6
8
  ## LICENSE
7
9
 
@@ -10,9 +12,13 @@ Copyright (c) 2023 RxOME GmbH
10
12
  All rights reserved, unauthorized use prohibited.
11
13
 
12
14
  ## Purpose
15
+ The *rxome* packages generate QR codes from medical data for use with the FindMe2care platform.
16
+
17
+ The package *rxome-generator* offers a JavaScript library as well as
18
+ a command line tool as front end to this library. Additonally, the packages *rxome-server* and *rxome-server-win*
19
+ provide a web service based on the rxome library.
13
20
 
14
- This package offers a JavaScript library for generating QR codes from medical data as well as
15
- a command line tool as front end to this library. Both expect the medical data in JSON format
21
+ The packages expect the medical data in JSON format
16
22
  according to a subset of the PhenoPacket standard (with some additions), see below.
17
23
  The medical data will be encrypted before generating the QR code. This encrypted data can be decrypted
18
24
  by the database backend only. The meta data is transmitted unencrypted.
@@ -24,7 +30,7 @@ a public key is uploaded to the server and used to verify the signature,
24
30
  see generating user credentials.
25
31
 
26
32
  When generating a QR code and, thus, downloading a pseudonym, the user needs to specify the
27
- corresponding credentials (keyID and key) for accessing the RxOME server.
33
+ corresponding credentials (keyID and key) for accessing the FindMe2care server.
28
34
  The command line tool offers command line options for the API access credentials. Further, they
29
35
  can be specified in the input JSON file (see 'MetaData and credentials' below),
30
36
  where the command line options precede the data in the JSON file.
@@ -33,19 +39,20 @@ In case the patient already has a pseudonym that will be used for the QR code,
33
39
  the known pseudonym can be specified in the MetaData section of the input JSON data.
34
40
  Additionally, the command line tool
35
41
  offers a command line argument, `-p`, for specifying a known pseudonym.
36
- Note that this pseudonym must be a valid RxOME pseudonym, that is, it has to be generated by
37
- RxOME for a previous medical statement. Using an arbitrary pseudonym will render the
38
- generated QR-Code useless, as it cannot be processed by RxOME.
42
+ Note that this pseudonym must be a valid FindMe2care pseudonym, that is, it has to be generated by
43
+ FindMe2care for a previous medical statement. Using an arbitrary pseudonym will render the
44
+ generated QR-Code useless, as it cannot be processed by FindMe2care.
39
45
 
40
46
  By default, the keywords in the JSON file are expected to be noted in camelCase. However, the tool
41
- can convert snake_case to camelCase (command line: -s, library: function convertToCamelCase).
47
+ can convert snake_case to camelCase (command line: -s, library function: convertToCamelCase).
42
48
 
43
- ## Installation
49
+ ## 1. Library and Command-Line Tool
50
+ ### 1.1 Installation
44
51
  > `npm install rxome-generator`
45
52
 
46
- ## Basic Usage
53
+ ### 1.2 Basic Usage
47
54
 
48
- ### Command Line Tool
55
+ #### Command Line Tool
49
56
 
50
57
  Generate a QR code *inputfile*.png from a JSON file *inputfile*.json containing all medical data in PhenoPacket format, meta data and credentials (using camelCase for keywords):
51
58
 
@@ -54,7 +61,7 @@ Generate a QR code *inputfile*.png from a JSON file *inputfile*.json containing
54
61
  For detailed descriptions see
55
62
  > `rxcode g --help`
56
63
 
57
- ### Library Functions
64
+ #### Library Functions
58
65
  Import the library with
59
66
  > `const Coder = require( 'rxome-generator' );`
60
67
 
@@ -95,8 +102,329 @@ Additionally, the data can be verified with
95
102
 
96
103
  Note that the credential information perhaps stored in the data package is *not* part of the PhenoPacket standard.
97
104
 
98
- ## Modifications to the PhenoPacket Standard
99
- ### Meta Data and Credentials
105
+ ### 1.3 Command-Line Tool
106
+
107
+ #### Overview
108
+
109
+ ```
110
+ FindMe2care QR Code generation tool
111
+
112
+ Usage: rxcode [options] [command]
113
+
114
+ Basic usage: rxcode g <input json file>: generates QR Code with the basefilename of the inputfile.
115
+ Before first use, please generate an API access key (rxcode -k) and deposit the public key on the
116
+ FindMe2care server.
117
+
118
+
119
+ Options:
120
+ -V, --version output the version number
121
+ -h, --help display help for command
122
+
123
+ Commands:
124
+ generate|g [options] [input file] generate QR Code from PhenoPacket JSON
125
+ upload|U [input file] [key ID] [key] For debug purposes: Upload and decode QR Code PNG to server (only
126
+ for test server)
127
+ convert|c [options] [input file] convert case style of keys in JSON files from snake_case to
128
+ camelCase (and vice versa)
129
+ preprocess|p [options] [input file] perform preprocessing steps
130
+ verify|v [input file] verify input file against phenopacket schema
131
+ apikeys|k [options] [file prefix] generate key pair for API access
132
+ ping|P [options] <id> <key> Ping API/check API credentials
133
+ encrypt|e [options] [input file] encrypt message (just for testing)
134
+ decrypt|d [options] [input file] decrypt coded message or medical data
135
+ data-keys|K [options] [file prefix] generate data encryption key pair (see -e, -d; just for testing)
136
+ pheno2proto|E [options] [input file] encode PhenoPacket to protobuf (just for testing)
137
+ proto2pheno|D [options] [input file] decode protobuf to PhenoPacket (just for testing)
138
+ settings|S [options] Print current settings
139
+ statistics|s [input file] print memory consuption for several stages and alternatives
140
+ help [command] display help for command
141
+
142
+ Author: Tom Kamphans, GeneTalk GmbH, 2022, (c) 2023 RxOME GmbH
143
+ ```
144
+
145
+ #### Generating QR codes
146
+
147
+ Use the 'g' command for actually generating a QR code:
148
+
149
+ ```
150
+ FindMe2care QR Code generation tool
151
+
152
+ Usage: rxcode generate|g [options] [input file]
153
+
154
+ Generate QR Code from PhenoPacket JSON. The credential information keyId and either key or keyFile
155
+ are mandatory and can be specified either in the input JSON file or by command line arguments.
156
+ The command line arguments precede the data from the JSON input file.
157
+ Output: prints the given or new pseudonym.
158
+
159
+ Arguments:
160
+ input file Input JSON file (default: STDIN)
161
+
162
+ Options:
163
+ -o, --output <filename> Filename for the QR code (default: <inputfile>.png)
164
+ -p, --pseudonym <pseudonym> For re-evaluations: pseudonym for patient. Otherwise a new is generated
165
+ (default: "")
166
+ -i, --keyId <id> API access ID (default: input file, credentials.keyId or metaData.createdBy)
167
+ -k, --keyFile <filename> Filename with API access key (default: use -s)
168
+ -s, --key <key string> API access key (default: input file, credentials.key)
169
+ -u, --user <user string> API access user (default: credentials.user or metaData.submittedBy or
170
+ info@rxome.net)
171
+ -c, --created <date> Date (default: input file, metaData.created)
172
+ -l, --lab <lab> Laboratory name (default: input file, metaData.createdBy or lab name stored
173
+ in the user account)
174
+ -e, --email <email> Laboratory email (default: input file, metaData.submittedBy)
175
+ -S, --snake Read payload formatted in snake_case (default: camelCase)
176
+ -t, --test Use test API instead of production API
177
+ -L, --localhost Connect to localhost API
178
+ -D, --debug Some output for debugging
179
+ -h, --help display help for command
180
+
181
+ Author: Tom Kamphans, GeneTalk GmbH, 2022, (c) 2023 RxOME GmbH
182
+ ```
183
+
184
+ Writes the pseudonym used to generate the QR code to STDOUT. With -D given, this further writes the
185
+ (unencrypted) content of the QR code to STDOUT.
186
+
187
+ #### Generating API Access Keys
188
+ To communicate with the server API you need access credentials, that is, an id for your lab (the keyId) and a pair of corresponding keys. First, generate a pair of keys with
189
+
190
+ ```
191
+ rxcode k myLabId
192
+ ```
193
+
194
+ This yields two files: `myLabId.private.apikey` and `myLabId.public.apikey`. Store the
195
+ private key safely.
196
+ Create a lab account on `app.findme2care.de/generate` and upload the public key to your profile.
197
+ Afterwards, you should be able to access the API (see 'debugging' below).
198
+
199
+ #### Demo
200
+
201
+ ```
202
+ rxcode g -t -o qrcode.png demos/demo_data_full.json
203
+ ```
204
+
205
+ <img src="qrcode.png" width="400">
206
+
207
+ #### Testing your installation
208
+ To check the connection to the API on RxOME server API use
209
+
210
+ > `rxcode P -d ` *your_id* *your_key*
211
+
212
+ If you want to make sure that all data from your input is transmitted correctly, you can
213
+ use the `pheno2proto` and the corresponding `proto2pheno` commands to encode and decode your
214
+ file. Compare the output of `proto2pheno` with your original file:
215
+
216
+ ```
217
+ rxcode E -b my_file.json > my_file.pbuf
218
+ rxcode D -bp my_file.pbuf > my_new_file.json
219
+ diff my_new_file.json my_file.json
220
+ ```
221
+
222
+ Further, you can check a QR Code that was generated on the test server (using the `-t` option in `rxcode g `) by uploading and decoding it to the test server with the `upload` command:
223
+
224
+ ```
225
+ rxcode U my_qr_code.png my_key_id my_private_key
226
+ ```
227
+
228
+ ## 2. QR-code generator service
229
+ The packages *rxome-server* generates QR codes containing medical information for use with the FindMe2Care database
230
+ (formerly called RxOME). The command line tool `rxsrv` starts the QR generator as local service listening on localhost:*port* (default: port 1607).
231
+ A client can send POST requests to this port and retrieves the generated QR code by HTTP protocol.
232
+
233
+ A second package, *rxome-server-win*, build up on rxome-server installs the server as windows service.
234
+
235
+
236
+ ### 2.1 Prerequisites
237
+ Running the QR-Code server requires either `node.js` or `docker`.
238
+
239
+ ### 2.2 Using Node.js
240
+
241
+ #### Installation
242
+ Either install the QR-Code Server or the Windows service installer using
243
+
244
+ ```
245
+ npm install -q rxome-server
246
+ ```
247
+
248
+ or
249
+
250
+ ```
251
+ npm install -q rxome-server-win
252
+ ```
253
+
254
+
255
+ #### Starting the QR-Code Server
256
+
257
+ For detailed descriptions see
258
+ ```
259
+ rxsrv --help
260
+ ```
261
+
262
+ #### Generating API access keys
263
+ You can generate new API access keys using the command line:
264
+ ```
265
+ rxsrv --newkey
266
+ ```
267
+
268
+ or in the Windows version:
269
+ ```
270
+ rxsrv_win.cmd command
271
+ ```
272
+
273
+ or start the server with dummy FindMe2Care credentials and access the '/key' entrypoint of the server.
274
+
275
+ #### Configuring using Environment Variables
276
+
277
+ The following command starts the server and reads the configuration from environment variables.
278
+ Note that the env variables can be set in the
279
+ environment's config file, e.g. when using Docker or NGINX. Setting the port is optional.
280
+
281
+ ```
282
+ export RXID=rxome
283
+ export RXKEY=private_key_for_rxome
284
+ export RXPORT=4242
285
+
286
+ rxsrv -e
287
+ ```
288
+
289
+ Where `RXID` is the username of the laboratory on the FindMe2Care platform, `RXKEY` is the
290
+ private API access key matching the public key stored on the lab's profile on the
291
+ FindMe2Care platform. See the README of the rxome-qrcode-generator for generating the
292
+ API keys.
293
+
294
+ Note that storing secret information in environment variables may pose a security risk; therefore, this option is not recommended and should only be used if the software runs in an isolated environment.
295
+
296
+ #### Configuring using Config File
297
+
298
+ Example config file (setting the port is optional.)
299
+
300
+ ```
301
+ cat demo.cfg
302
+ {
303
+ "id": "rxome",
304
+ "key": "private_key_for_rxome",
305
+ "port": "4242"
306
+ }
307
+ ```
308
+
309
+ Start the server and read settings from config file:
310
+
311
+ ```
312
+ rxsrv -c demo.cfg
313
+ ```
314
+
315
+
316
+ #### Registering and Unregistering the Windows Service
317
+ The npm package `rxome-server-win` provides a Windows executable that you can start with:
318
+
319
+ ```
320
+ rxsrv_win.cmd command
321
+ ```
322
+
323
+ where command is one of
324
+
325
+ - install
326
+ - uninstall
327
+ - ping
328
+ - newkey
329
+ - help
330
+
331
+ Note that the Windows service is configured with a config file given by `%RXCFG%` or, if none specified,
332
+ the default file `%APPDATA\npm\node_modules\rxome-server-win\demo.cfg` is used.
333
+
334
+ ### 2.3 Using Docker
335
+ Instead of installing node.js and starting the server manually, you can use a docker image to run the server, e.g. by
336
+
337
+ ```
338
+ docker run -d -p 1607:1607 -e RXID="rxome" -e RXKEY="...private_key..." tomkamphans/rxsrv
339
+ ```
340
+
341
+ Where `RXID` is the lab's user name and `RXKEY` the private API key as described above.
342
+
343
+ Note that the first port number in `-p 1607:1607` denotes the port on *localhost* to which the docker internal port (denoted the second port number, in this case 1607 also) is mapped. So if you need to run the service on another port, say 8081, use
344
+ `docker run -p 8081:1607 ...`.
345
+
346
+ Hint for Docker on Windows: set the start type of *Docker Desktop Service* to *automatic* using the Windows Services App (services.msc).
347
+
348
+
349
+ ### 2.4 API Endpoints
350
+
351
+ The server provides the following endpoints, see descriptions below:
352
+
353
+ * `GET /`
354
+ * `GET /demo`
355
+ * `POST /`
356
+ * `POST /img`
357
+ * `GET /key`
358
+
359
+ #### Testing connection
360
+
361
+ Querying the url `localhost:<port>/` should yield a line such as
362
+
363
+ ```This is the RxOME QRcode generator API Version 0.0.1 for lab id rxome running on port 1607 with PID 26584```
364
+
365
+ #### Getting Demo Data
366
+ For convenient testing, the server provides a demo JSON file by sending a GET request to `/data`.
367
+
368
+ #### Getting a QR-Code in PNG
369
+ Send a JSON file with the data for the RxOME code generator by POST request to `/img`, e.g.
370
+
371
+ ```
372
+ curl -X POST -H "Content-Type: application/json" -d @demo_data_full.json --output qrcode.png localhost:1607/img
373
+ ```
374
+
375
+ #### Getting QR-Code and Pseudonym in JSON Format
376
+ In addition to the QR-Code itself, the code generator yields the pseudonym given to this patient
377
+ and the full unencrypted content of the QR code. The laboratory may
378
+ use this pseudonym if the patient is re-evaluated and gets a new QR-Code. Thus, the former medical data can be
379
+ overwritten in the FindMe2Care Database. To get the QR-code and the pseudonyme in JSON format, send the input JSON file to `/`:
380
+
381
+ ```
382
+ curl -X POST -H "Content-Type: application/json" -d @demo_data_full.json --output qrcode.json localhost:1607/
383
+ ```
384
+
385
+ This yields a JSON response containing
386
+
387
+ ```
388
+ {
389
+ qr_code: (QR code),
390
+ pseudonym: (pseudonym used to generate the QR code),
391
+ qr_content: content of the QR code but with unencrypted medical data for documentation purposes
392
+ }
393
+ ```
394
+
395
+ ### 2.5 Server Command-Line Tool
396
+
397
+ ```
398
+ RxOME QR Code generation server
399
+
400
+ Usage: rxsrv usage: rxsrv -i <id> (-e | -c <cfg_file> | -k <key_file> | -s <key>) [-p <port>]
401
+
402
+ Start the QR-code tool as service listening on localhost:<port>.
403
+ Before first use, please generate an API access key with rxcode and deposit the public key on the
404
+ RxOME server.
405
+
406
+ The command-line parameters -k, -s, -p precede the environment variables (if -e specified), which, in
407
+ turn, precede the config file (if -c is also specified). A key string (-s) has precedence over a key
408
+ from a key file (-k).
409
+
410
+ Options:
411
+ -c, --config <filename> JSON file with config, entries id, key, [port]; -c-- to read from stdin
412
+ -e, --environment use environment variables RXID, RXKEY, RXPORT to configure rxsrv (useful
413
+ for working with docker)
414
+ -i, --keyId <id> API access ID
415
+ -k, --keyFile <filename> Filename with API access key (default: use -s)
416
+ -s, --key <key string> API access key
417
+ -p, --port <port> Set port for server, default: 1607
418
+ -V, --version output the version number
419
+ -h, --help display help
420
+ ```
421
+
422
+
423
+
424
+
425
+ ## 3. Data Format
426
+ ### 3.1 Modifications to the PhenoPacket Standard
427
+ #### Meta Data and Credentials
100
428
  For convenience, all data needed to generate a QR code can be specified in one JSON file
101
429
  (or, when using the library functions, one JavaScript object).
102
430
  In addition to the medical data, the JSON files or objects accepted by rxcode and the
@@ -132,7 +460,7 @@ pseudonym used will be part of the output for futher processing or storing.
132
460
  }
133
461
  ```
134
462
 
135
- ### Phenotypic Features
463
+ #### Phenotypic Features
136
464
 
137
465
  The rxome library extends the PhenoPacket schema for storing phenotypicFeatures (HPO terms). In addition the notation suggested by PhenoPackets:
138
466
 
@@ -176,10 +504,46 @@ the terms can be stored in a shorter and more convenient form:
176
504
  ]
177
505
  }
178
506
  ```
507
+
508
+ #### Additional Data
509
+
510
+ The RxOME data format allows to store informations that are not provided by the phenopacket format by using
511
+ the phenopacket extension fields in the form
512
+
513
+ ```
514
+ "extensions": [
515
+ {
516
+ "name": "...",
517
+ "value": "..."
518
+ },
519
+ {
520
+ "name": "...",
521
+ "value": "..."
522
+ }
523
+ ]
524
+
525
+ ```
526
+
527
+ * The type of genetic test performed to obtain a variant (extension field name *test-type*)
528
+ * CNV information (field name *cnv*). Possible values:
529
+ * 0 = Not provided (default)
530
+ * 1 = Deletion
531
+ * 2 = Duplication
532
+
533
+ * Methylation (field name *meth*). Possible values:
534
+ * 0 = Not provided
535
+ * 1 = Hypermethylation
536
+ * 2 = Hypomethylation
537
+ * 3 = Intermediate
538
+
539
+ * Allele Frequency (field name *af*)
540
+ * Repeat length (field name *rl*)
541
+ * Chromosomal Region (field name *chr*)
542
+ * Methylation site (field name *site*)
179
543
 
180
- ### Data Source
544
+ ###### Example: test type
181
545
 
182
- The type of genetic test performed to obtain a variant can be specified in an extension field to the genomic interpretation:
546
+ The type of genetic test performed to obtain a variant can be specified in an extension field to the genomic interpretation in the *variationDescriptor* section:
183
547
 
184
548
  ```
185
549
  "genomicInterpretations": [
@@ -200,7 +564,8 @@ The type of genetic test performed to obtain a variant can be specified in an ex
200
564
  },
201
565
  "extensions": [
202
566
  {
203
- "name": "Single gene sequencing"
567
+ "name": "test-type",
568
+ "value": "Single gene sequencing"
204
569
  }
205
570
  ]
206
571
  }
@@ -211,7 +576,7 @@ The type of genetic test performed to obtain a variant can be specified in an ex
211
576
  ]
212
577
  ```
213
578
 
214
- ### Additional Remarks
579
+ #### Additional Remarks
215
580
 
216
581
  Additional remarks can be specified in a *comment* field on the top level:
217
582
 
@@ -223,7 +588,7 @@ Additional remarks can be specified in a *comment* field on the top level:
223
588
  ...
224
589
  ```
225
590
 
226
- ### Whitelist Filter
591
+ #### Whitelist Filter
227
592
 
228
593
  Before packing the data, needless sections (that is, sections that are not evaluted by RxOME)
229
594
  are removed. On top level, the following section will be passed over to the QR code:
@@ -237,253 +602,177 @@ are removed. On top level, the following section will be passed over to the QR c
237
602
  * metaData
238
603
  * credentials (not passed to QR code, but also not removed by whitelist filtering)
239
604
 
240
- ## Command-Line Tool
241
-
242
- ### Overview
243
-
244
- ```
245
- FindMe2care QR Code generation tool
246
-
247
- Usage: rxcode [options] [command]
248
-
249
- Basic usage: rxcode g <input json file>: generates QR Code with the basefilename of the inputfile.
250
- Before first use, please generate an API access key (rxcode -k) and deposit the public key on the FindMe2care server.
251
-
252
-
253
- Options:
254
- -V, --version output the version number
255
- -h, --help display help for command
256
-
257
- Commands:
258
- generate|g [options] [input file] generate QR Code from PhenoPacket JSON
259
- convert|c [options] [input file] convert case style of keys in JSON files from snake_case to camelCase
260
- (and vice versa)
261
- preprocess|p [options] [input file] perform preprocessing steps
262
- verify|v [input file] verify input file against phenopacket schema
263
- apikeys|k [options] [file prefix] generate key pair for API access
264
- ping|P [options] <id> <key> Ping API/check API credentials
265
- encrypt|e [options] [input file] encrypt message (just for testing)
266
- decrypt|d [options] [input file] decrypt coded message or medical data
267
- data-keys|K [options] [file prefix] generate key pair for data encryption (see -e, -d; just for testing)
268
- pheno2proto|E [options] [input file] encode PhenoPacket to protobuf (just for testing)
269
- proto2pheno|D [options] [input file] decode protobuf to PhenoPacket (just for testing)
270
- settings|S [options] Print current settings
271
- statistics|s [input file] print memory consuption for several stages and alternatives
272
- help [command] display help for command
273
-
274
- Author: Tom Kamphans, GeneTalk GmbH, 2022, (c) 2023 RxOME GmbH
275
- ```
276
-
277
- ### Generating QR codes
278
-
279
- Use the 'g' command for actually generating a QR code:
280
-
281
- ```
282
- FindMe2care QR Code generation tool
283
-
284
- Usage: rxcode generate|g [options] [input file]
285
-
286
- Generate QR Code from PhenoPacket JSON. The credential information keyId and either key or keyFile
287
- are mandatory and can be specified either in the input JSON file or by command line arguments.
288
- The command line arguments precede the data from the JSON input file.
289
- Output: prints the given or new pseudonym.
290
-
291
- Arguments:
292
- input file Input JSON file (default: STDIN)
293
-
294
- Options:
295
- -o, --output <filename> Filename for the QR code (default: <inputfile>.png)
296
- -p, --pseudonym <pseudonym> For re-evaluations: pseudonym for patient. Otherwise a new is generated
297
- (default: "")
298
- -i, --keyId <id> API access ID (default: input file, credentials.keyId or metaData.createdBy)
299
- -k, --keyFile <filename> Filename with API access key (default: use -s)
300
- -s, --key <key string> API access key (default: input file, credentials.key)
301
- -u, --user <user string> API access user (default: credentials.user or metaData.submittedBy or
302
- info@rxome.net)
303
- -c, --created <date> Date (default: input file, metaData.created)
304
- -l, --lab <lab> Laboratory name (default: input file, metaData.createdBy or lab name stored in
305
- the user account)
306
- -e, --email <email> Laboratory email (default: input file, metaData.submittedBy)
307
- -S, --snake Read payload formatted in snake_case (default: camelCase)
308
- -t, --test Use test API instead of production API
309
- -L, --localhost Connect to localhost API
310
- -D, --debug Some output for debugging
311
- -h, --help display help for command
312
-
313
- Author: Tom Kamphans, GeneTalk GmbH, 2022, (c) 2023 RxOME GmbH
314
- ```
315
-
316
- Writes the pseudonym used to generate the QR code to STDOUT. With -D given, this further writes the
317
- (unencrypted) content of the QR code to STDOUT.
318
-
319
- ### Generating API Access Keys
320
- To communicate with the server API you need access credentials, that is, an id for your lab (the keyId) and a pair of corresponding keys. First, generate a pair of keys with
321
-
322
- ```
323
- rxcode k myLabId
324
- ```
325
-
326
- This yields two files: `myLabId.private.apikey` and `myLabId.public.apikey`. Store the
327
- private key safely.
328
- Create a lab account on `app.findme2care.de/generate` and upload the public key to your profile.
329
- Afterwards, you should be able to access the API (see 'debugging' below).
330
-
331
- ## Demo
332
-
333
- ```
334
- rxcode g -t -o qrcode.png demos/demo_data_full.json
335
- ```
336
-
337
- <img src="qrcode.png" width="400">
338
-
339
- ## Debugging
340
- To check the connection to the API on RxOME server API use
341
-
342
- > `rxcode P -d ` *your_id* *your_key*
343
-
344
- If you want to make sure that all data from your input is transmitted correctly, you can
345
- use the `pheno2proto` and the corresponding `proto2pheno` commands to encode and decode your
346
- file. Compare the output of `proto2pheno` with your original file:
347
-
348
- ```
349
- rxcode E -b my_file.json > my_file.pbuf
350
- rxcode D -bp my_file.pbuf > my_new_file.json
351
- diff my_new_file.json my_file.json
352
- ```
353
-
354
- ## Payload Example File
605
+ ### 3.2 Special phenopacket entries
606
+ In this section, we give some additional explanations to some of the fields in the phenopacket schema.
607
+
608
+ #### Diagnosis/Disease
609
+ The diagnosis can be specified in the *disease* field.
610
+ IMPORTANT: Note that the
611
+
612
+ #### Zygosity
613
+ The zygosity is specified in the field *allelicState* in the *variationDescriptor* section. According to the
614
+ phenopacket standard, possible values are
615
+
616
+ * GENO\_0000137 for 'unspecified\_zygosity'
617
+ * GENO\_0000136 for 'homozygous'
618
+ * GENO\_0000135 for 'heterozygous'
619
+ * GENO\_0000402 for 'compound_heterozygous'
620
+ * GENO\_0000134 for 'hemizygous'
621
+ * GENO\_0000604 for 'hemizygous\_X\_linked'
622
+ * GENO\_0000605 for 'hemizygous\_Y\_linked'
623
+ * GENO\_0000606 for 'hemizygous\_insertion\_linked'
624
+ * GENO\_0000392 for 'aneusomic\_zygosity'
625
+ * GENO\_0000393 for 'trisomic\_homozygous'
626
+ * GENO\_0000394 for 'trisomic\_heterozygous'
627
+ * GENO\_0000602 for 'homoplasmic'
628
+ * GENO\_0000603 for 'heteroplasmic'
629
+ * GENO\_0000964 for 'mosaic'
630
+
631
+ ### 3.3 Payload Example File
355
632
 
356
633
  ```
357
634
  {
358
- "id": "QR-Code ID",
359
- "comment": "useful remarks",
635
+ "id": "232DTCEZZCQX",
360
636
  "subject": {
361
- "id": "proband A",
362
- "dateOfBirth": "1994-01-01T00:00:00Z",
363
- "sex": "FEMALE"
637
+ "dateOfBirth": "2021-07-16",
638
+ "sex": 1
639
+ },
640
+ "comment": "Demo record",
641
+ "compressedFeatures": {
642
+ "includes": [
643
+ "HP:0003155",
644
+ "HP:0001250",
645
+ "HP:0001249"
646
+ ],
647
+ "excludes": [
648
+ "HP:0031360"
649
+ ]
364
650
  },
365
- "phenotypicFeatures": [
366
- {
367
- "type": {
368
- "id": "HP:0030084"
369
- }
370
- },
371
- {
372
- "type": {
373
- "id": "HP:0000555"
374
- }
375
- },
376
- {
377
- "type": {
378
- "id": "HP:0000486"
379
- }
380
- },
381
- {
382
- "type": {
383
- "id": "HP:0000541"
384
- }
385
- },
386
- {
387
- "type": {
388
- "id": "HP:0084369"
389
- }
390
- },
391
- {
392
- "type": {
393
- "id": "HP:0112358"
394
- }
395
- },
396
- {
397
- "type": {
398
- "id": "HP:0000145"
399
- }
400
- },
401
- {
402
- "type": {
403
- "id": "HP:1234567"
404
- }
405
- },
406
- {
407
- "type": {
408
- "id": "HP:9876543"
409
- }
410
- },
411
- {
412
- "type": {
413
- "id": "HP:5678912"
414
- }
415
- },
416
- {
417
- "type": {
418
- "id": "HP:0031360"
419
- },
420
- "excluded": true
421
- },
422
- {
423
- "type": {
424
- "id": "HP:0001234",
425
- },
426
- "excluded": true
427
- }
428
- ],
429
651
  "interpretations": [
430
652
  {
431
- "id": "interpretation.id",
432
- "progressStatus": "SOLVED",
653
+ "id": "first",
654
+ "progressStatus": 3,
433
655
  "diagnosis": {
434
656
  "disease": {
435
- "id": "OMIM:263750"
657
+ "id": "OMIM:614207"
436
658
  },
437
659
  "genomicInterpretations": [
438
660
  {
661
+ "subjectOrBiosampleId": "0vlqzsw094u.0",
662
+ "interpretationStatus": "3",
439
663
  "variantInterpretation": {
440
- "acmgPathogenicityClassification": "PATHOGENIC",
664
+ "acmgPathogenicityClassification": "5",
441
665
  "variationDescriptor": {
442
666
  "geneContext": {
443
- "valueId": "HGNC:9884",
444
- "symbol": "RB1"
667
+ "valueId": "26031",
668
+ "symbol": "PIGV",
669
+ "alternateIds": [
670
+ "55650"
671
+ ]
445
672
  },
446
673
  "expressions": [
447
674
  {
448
675
  "syntax": "hgvs.c",
449
- "value": "NM_000321.2:c.958C>T"
676
+ "value": "NM_017837.4(PIGV):c.1022C>A (p.Ala341Glu)"
450
677
  }
451
678
  ],
452
- "allelicState": {
453
- "id": "GENO:0000135"
454
- },
455
679
  "extensions": [
456
680
  {
457
681
  "name": "test-type",
458
- "value": "Exome, short read"
682
+ "value": "Single gene sequencing"
459
683
  }
460
- ]
684
+ ],
685
+ "allelicState": {
686
+ "id": "GENO_0000136"
687
+ }
461
688
  }
462
689
  }
463
690
  },
464
691
  {
692
+ "subjectOrBiosampleId": "qpsczs5l7y.907m2ybforb",
465
693
  "variantInterpretation": {
466
- "acmgPathogenicityClassification": "LIKELY_PATHOGENIC",
694
+ "acmgPathogenicityClassification": "1",
467
695
  "variationDescriptor": {
468
696
  "geneContext": {
469
- "valueId": "HGNC:9884",
470
- "symbol": "RB1"
697
+ "valueId": "31369",
698
+ "symbol": "TOMM5",
699
+ "alternateIds": [
700
+ "401505"
701
+ ]
471
702
  },
472
703
  "expressions": [
473
704
  {
474
705
  "syntax": "hgvs.c",
475
- "value": "NM_000321.2:c.1234A>G"
706
+ "value": "... hgvs code ..."
707
+ },
708
+ {
709
+ "syntax": "iscn",
710
+ "value": "... iscn data ..."
711
+ }
712
+ ],
713
+ "extensions": [
714
+ {
715
+ "name": "test-type",
716
+ "value": "Multigene panel"
717
+ },
718
+ {
719
+ "name": "cnv",
720
+ "value": "1"
721
+ },
722
+ {
723
+ "name": "meth",
724
+ "value": "1"
725
+ },
726
+ {
727
+ "name": "af",
728
+ "value": "...allele frequency..."
729
+ },
730
+ {
731
+ "name": "rl",
732
+ "value": "... repeat length ..."
733
+ },
734
+ {
735
+ "name": "chr",
736
+ "value": "... chromosomal region ..."
737
+ },
738
+ {
739
+ "name": "site",
740
+ "value": " ... methylation site ..."
476
741
  }
477
742
  ],
478
743
  "allelicState": {
479
- "label": "heterozygous"
744
+ "id": "GENO_0000136"
745
+ }
746
+ }
747
+ }
748
+ },
749
+ {
750
+ "subjectOrBiosampleId": "qpsczs5l7y.k0z7yqgy8gi",
751
+ "variantInterpretation": {
752
+ "acmgPathogenicityClassification": "Unknown",
753
+ "variationDescriptor": {
754
+ "geneContext": {
755
+ "valueId": "34528",
756
+ "symbol": "TOMM6",
757
+ "alternateIds": [
758
+ "100188893"
759
+ ]
480
760
  },
761
+ "expressions": [
762
+ {
763
+ "syntax": "hgvs.c",
764
+ "value": "HGVS2"
765
+ }
766
+ ],
481
767
  "extensions": [
482
768
  {
483
769
  "name": "test-type",
484
- "value": "Exome, short read"
770
+ "value": "Multigene panel"
485
771
  }
486
- ]
772
+ ],
773
+ "allelicState": {
774
+ "id": "None"
775
+ }
487
776
  }
488
777
  }
489
778
  }
@@ -492,10 +781,10 @@ diff my_new_file.json my_file.json
492
781
  }
493
782
  ],
494
783
  "metaData": {
495
- "created": "2021-05-14T10:35:00Z",
496
- "createdBy": "MGZ",
497
- "submittedBy": "abc@def.de",
498
- "phenopacketSchemaVersion": "2.0"
784
+ "created": "2024-08-13",
785
+ "createdBy": "ACME Genetics",
786
+ "submittedBy": "genetics@acme.org",
787
+ "pseudonym": "232DTCEZZCQX"
499
788
  }
500
789
  }
501
790
  ```
@@ -505,4 +794,4 @@ diff my_new_file.json my_file.json
505
794
  openpgp https://openpgpjs.org/
506
795
  node-qrcode https://github.com/soldair/node-qrcode
507
796
  noble-ed25519
508
- -->
797
+ -->
@@ -143,7 +143,7 @@
143
143
  "pseudonym": "_DEMO_PSEUDONYM_"
144
144
  },
145
145
  "credentials": {
146
- "key": "lBSkSxe/+UBWOeF5OJdQgf9qZhiI85hYE6yJCuWjCNk=",
146
+ "key": "Rf7VbeUBQmjvAagwsWx6riaZYc7h4OBD4CuxYyZ5bgA=",
147
147
  "keyId": "rxome",
148
148
  "user": "a_clinician@mgz-muenchen.de"
149
149
  }
@@ -70,7 +70,7 @@
70
70
  "excludes": ["HP:0031360", "HP:0001234"]
71
71
  },
72
72
  "credentials": {
73
- "key": "lBSkSxe/+UBWOeF5OJdQgf9qZhiI85hYE6yJCuWjCNk=",
73
+ "key": "Rf7VbeUBQmjvAagwsWx6riaZYc7h4OBD4CuxYyZ5bgA=",
74
74
  "keyId": "rxome",
75
75
  "user": "a_clinician@mgz-muenchen.de"
76
76
  }
@@ -139,7 +139,6 @@
139
139
  "created": "2021-05-14T10:35:00Z",
140
140
  "createdBy": "mgz",
141
141
  "submittedBy": "a_clinician@mgz-muenchen.de",
142
- "phenopacketSchemaVersion": "2.0",
143
- "pseudonym": "_DEMO_PSEUDONYM_"
142
+ "phenopacketSchemaVersion": "2.0"
144
143
  }
145
144
  }
@@ -0,0 +1 @@
1
+ {"status":422,"message":"Request failed with status code 403"}
@@ -35,8 +35,10 @@ VBvfFVhJAPoDhf5yKxJ+oJV3ls8IyoBBAeMeAYFBrA8r89fKT0nFBA==
35
35
  `
36
36
 
37
37
  const R_ID = 'rxome';
38
- const R_PUBLIC_KEY = '60uReCXTn7KTEIExM4KveKstBGI3TaSrQss4biaesNs=';
39
- const R_PRIVATE_KEY = 'lBSkSxe/+UBWOeF5OJdQgf9qZhiI85hYE6yJCuWjCNk=';
38
+ const R_PUBLIC_KEY = '4OShAt7RQ/RJA0qAvoaOQ2jx7SFBYef70XPIz7r9924=';
39
+ const R_PRIVATE_KEY = 'Rf7VbeUBQmjvAagwsWx6riaZYc7h4OBD4CuxYyZ5bgA=';
40
+ // const R_PUBLIC_KEY = '60uReCXTn7KTEIExM4KveKstBGI3TaSrQss4biaesNs=';
41
+ // const R_PRIVATE_KEY = 'lBSkSxe/+UBWOeF5OJdQgf9qZhiI85hYE6yJCuWjCNk=';
40
42
  // const R_PRIVATE_KEY = 'NamaTB+xwDFxtkQyBBkjRr5GEaXNtCw/G4qydnhQk5Y=';
41
43
  // const R_PUBLIC_KEY = 'XvbhLWKbA1wfKsx3B7FKQuDQsZTZ/dMXWiD1MehBxZg=';
42
44
 
package/lib/rxome-api.cjs CHANGED
@@ -133,3 +133,60 @@ exports.fetchData = async ( url, credentials, pseudonym = '', debug = false ) =>
133
133
  return res.data
134
134
  })
135
135
  }
136
+
137
+ exports.pushData = async ( url, credentials, msg, debug = false ) => {
138
+ debug && console.log( 'Pushing to ', url )
139
+ console.log( 'Pushing to ', url )
140
+
141
+ const created = Date.now();
142
+ const keyId = credentials.keyId || "rxome";
143
+ const user = credentials.user || `${keyId}@rxome.net`;
144
+ const keyB64 = credentials.key || readSigKey( process.cwd()+'/'+credentials.keyFile );
145
+
146
+ const auth = await exports.signData( keyId, user, keyB64, created, debug );
147
+
148
+ FS = require( 'fs' );
149
+ return Axios({
150
+ url: url,
151
+ method: 'POST',
152
+ data: msg,
153
+ headers: {
154
+ Authorization: auth,
155
+ 'x-date': created,
156
+ 'x-rxome-user': user
157
+ },
158
+ timeout: 5000
159
+ })
160
+ .then(res => {
161
+ debug && console.log( "Result Data= ", res.data )
162
+ return res.data
163
+ })
164
+ .catch( (error) => {
165
+ // setIsLoading(false);
166
+ let msg=null;
167
+ if (error.response) {
168
+ // Request made and server responded
169
+ if (error.response?.data?.message){
170
+ console.log( '[SendData Response Error] ', error.response.data.message );
171
+ msg=`Response Error: ${error.response.data.message}`;
172
+ console.log(error.response.data);
173
+ } else {
174
+ console.log( '[SendData Response Error] no message' );
175
+ msg='Unknown response error';
176
+ }
177
+ console.log(error.response.status);
178
+ console.log(error.response.headers);
179
+ } else if (error.request) {
180
+ // The request was made but no response was received
181
+ console.log('[SendData Request Error] ', error.request);
182
+ msg = 'No response from server';
183
+ } else {
184
+ // Something happened in setting up the request that triggered an Error
185
+ console.log('[SendData Request Error] ', error.message);
186
+ msg = `Request Error: ${error.message}`;
187
+ }
188
+ const err = new Error( `Error sending data: ${msg}` );
189
+ console.log(err.name + ': ' + err.message);
190
+ throw err;
191
+ })
192
+ }
@@ -87,7 +87,7 @@ exports.generateRxomeKeys = async (name = 'rxome') => {
87
87
 
88
88
  exports.fetchKey = async ( credentials, pseudonym = '', api = RXAPI, debug = false, apiEntry = APIENTRY ) => {
89
89
  const result = await RxAPI.fetchData( `${api}/${apiEntry}/getpseudonym`, credentials, pseudonym, debug )
90
- if ( !result.pseudonym )
90
+ if ( result.pseudonym === '' )
91
91
  result.pseudonym = pseudonym;
92
92
  return result;
93
93
  }
@@ -291,7 +291,7 @@ exports.prepareQR = async ( data, api = RXAPI, apiEntry = APIENTRY ) => {
291
291
  const protobufMedical = exports.encodePhenoPacket( compressedMedical );
292
292
  const base64Medical = RxAPI.bufferToBase64(protobufMedical);
293
293
 
294
- const key = await this.fetchKey( credentials, metaData.pseudonym || '', api, false, apiEntry );
294
+ const key = await this.fetchKey( credentials, metaData?.pseudonym || '', api, false, apiEntry );
295
295
 
296
296
  // check:
297
297
  const buff = RxAPI.base64ToBuffer( base64Medical );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rxome-generator",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Generates QR codes containing medical information for use with the FindMe2Care platform.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -25,27 +25,28 @@
25
25
  "phenopacket"
26
26
  ],
27
27
  "author": "Tom Kamphans",
28
- "license" : "SEE LICENSE IN README.md",
28
+ "license": "SEE LICENSE IN README.md",
29
29
  "bugs": {
30
30
  "url": "https://github.com/GeneTalkTK/rxome-qrcode-generator/issues"
31
31
  },
32
32
  "homepage": "https://github.com/GeneTalkTK/rxome-qrcode-generator#readme",
33
33
  "dependencies": {
34
- "@noble/ed25519": "^1.7.1",
35
- "axios": "^0.27.1",
36
- "commander": "^9.4.0",
34
+ "@noble/ed25519": "^2.2.3",
35
+ "axios": "^1.7.9",
36
+ "commander": "^13.1.0",
37
37
  "json-key-converter": "^1.0.0",
38
38
  "noble-ed25519": "^1.2.6",
39
- "openpgp": "^5.2.1",
40
- "protobufjs": "~7.1.0",
41
- "protobufjs-cli": "^1.0.1",
42
- "qrcode": "^1.5.0"
39
+ "openpgp": "^6.1.0",
40
+ "protobufjs": "^7.4.0",
41
+ "protobufjs-cli": "^1.1.3",
42
+ "qrcode": "^1.5.4",
43
+ "sharp": "^0.33.5"
43
44
  },
44
45
  "devDependencies": {
45
- "jest": "^28.0.1",
46
+ "jest": "^29.7.0",
46
47
  "json-loader": "^0.5.7"
47
48
  },
48
49
  "bin": {
49
- "rxcode": "./rxcode.js"
50
+ "rxcode": "rxcode.js"
50
51
  }
51
52
  }
package/rxcode.js CHANGED
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import * as FS from 'fs';
4
+ import sharp from 'sharp';
5
+
4
6
  // const Coder = require( './lib/rxome-generator' );
5
7
  import * as Coder from './lib/rxome-generator.cjs';
6
8
  import * as ApiDemo from './lib/rxome-api-demo.cjs' ;
@@ -25,7 +27,7 @@ const DEMO_CREDENTIALS = ApiDemo.DEMO_CREDENTIALS
25
27
  const DEMO_PRIVATE_KEY = ApiDemo.CRYPT_PRIVATE_KEY
26
28
  const DEMO_PUBLIC_KEY = ApiDemo.CRYPT_PUBLIC_KEY
27
29
 
28
- const VERSION = '1.0.2'
30
+ const VERSION = '1.0.3'
29
31
 
30
32
  program
31
33
  .name('rxcode')
@@ -100,10 +102,58 @@ Output: prints the given or new pseudonym.`)
100
102
  const data = await Coder.writeQR( outputfile, qrData, qrApi );
101
103
  console.log( data.pseudonym );
102
104
  options.debug && console.log( JSON.stringify( data.qr_content, 0, 2) );
105
+ //const fulldata = await Coder.makeQR( qrData, qrApi );
106
+ //console.log( JSON.stringify( fulldata, 0, 2) );
107
+ });
108
+
109
+
110
+ program.command('upload')
111
+ .alias('U')
112
+ .summary('For debug purposes: Upload and decode QR Code PNG to server (only for test server)')
113
+ .description(
114
+ `This uploads a QR Code in PNG format that was generated with either -t (test API)
115
+ to the corresponding server, decodes the QR Code and the medical information an returns it as JSON.
116
+ This should basically yield the original JSON data used to create the QR Code.
117
+ Note that this function can be used only with the test server: for data protection reasons, the medical data are stored
118
+ on a separate server and the production server has means to decode the medical data.
119
+ Output: QR Code content in JSON format.`)
120
+ .argument('[input file]', 'PNG containing a QR code')
121
+ .argument('[key ID]', 'API access ID ')
122
+ .argument('[key]', 'API access private key')
123
+ //.option('-o, --output <filename>', 'Filename for the JSON data (default: <inputfile>.json)')
124
+ //.option('-D, --debug', 'Some output for debugging')
125
+ .action( async (inputfile, keyId, key, options) => {
126
+ let theImage;
127
+ try {
128
+ const jpgBuffer = await sharp(inputfile).jpeg().toBuffer();
129
+ const base64String = jpgBuffer.toString('base64');
130
+ theImage = `data:image/jpeg;base64,${base64String}`;
131
+ } catch (error) {
132
+ console.log('Error converting: ', error);
133
+ }
134
+
135
+ const data = {
136
+ image: theImage
137
+ };
138
+ const credentials = {
139
+ keyId: keyId,
140
+ user: 'doesntmatter@rxome.net',
141
+ key: key
142
+ }
143
+
144
+ const publicKey = await Coder.fetchRxomeKey( credentials, RxAPI.TESTAPI );
145
+ const cryptData = await Coder.encode( publicKey.key, JSON.stringify(data) );
146
+ const msg = {
147
+ payload: cryptData,
148
+ keyver: publicKey.version
149
+ }
150
+
151
+ const result = await RxAPI.pushData( `${ RxAPI.TESTAPI}/${RxAPI.APIENTRY}/testupload`, credentials, msg );
152
+ process.stdout.write( JSON.stringify( result, 0, 2 ));
103
153
  });
104
154
 
105
155
 
106
- program.command('convert')
156
+ program.command('convert')
107
157
  .alias('c')
108
158
  .description('convert case style of keys in JSON files from snake_case to camelCase (and vice versa)')
109
159
  .argument('[input file]', 'Input JSON file (default: STDIN)')
@@ -339,6 +389,7 @@ program.command('settings')
339
389
  .action( (options) => {
340
390
 
341
391
  console.log('This RxOME/FindMe2care QR generator V', VERSION );
392
+ console.log(`Running under Node ${process.version} for ${process.arch}`);
342
393
  console.log('Connecting to', options.test ? RxAPI.TESTAPI : RxAPI.API );
343
394
  console.log('API', options.test ? RxAPI.APIENTRY : RxAPI.APIENTRY );
344
395
 
package/README.TODO DELETED
@@ -1,4 +0,0 @@
1
- ## Testing
2
- Codes generated by the test API (i.e., with the `-t` switch or `API=Coder.TESTAPI`) can be decoded online using the following tool:
3
-
4
- Todo: URL Code-Reader Demo
package/qrcode.png DELETED
Binary file