rxome-generator 1.0.3 → 1.0.4-beta.1

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.
@@ -0,0 +1,26 @@
1
+ const CRYPT_PRIVATE_KEY = '-----BEGIN PGP PRIVATE KEY BLOCK-----\n\nxYYEY0gdfxYJKwYBBAHaRw8BAQdAYqNejQxT4gE+w2nwBvP+pe19P152F6LV\n8sqM/Qhut2D+CQMIlk6wdgn1LOXgt14o00FVGL49l+pQB8umf27PPnWrJ9IS\nIElQjaCsRYA3ZD/rnDUZiBGVS9++PaegYL339QT2bDp8l6VVtvcxG77svZ2n\na80Xcnh0ZXN0IDxpbmZvQHJ4b21lLm5ldD7CjAQQFgoAHQUCY0gdfwQLCQcI\nAxUICgQWAAIBAhkBAhsDAh4BACEJEGvtGF4xeK/wFiEEP1IE7WS9w5iQJRD8\na+0YXjF4r/CW7AD7BlIn1BHx8kOdyrt6E0L1EKIUi88Q3jQghmvlQomsIzIB\nAKW3e7gYkQJufFTlTWmD5dYmP4v3DfAGvkmFljOvHfwGx4sEY0gdfxIKKwYB\nBAGXVQEFAQEHQNBoBiWwb9t6WCMulp6/opgVJ88iKOY9MpAoZ5dyEbJwAwEI\nB/4JAwhZhPonkWKqteBKH35kf07JpJVMX8LWmZCqdFqXw8tmsU81LtCxVRl8\nexJ0vJor/6LmBUnzMrVSG3S0PCVLw0hAfCH4nN9HxT5gEc1mFFfSwngEGBYI\nAAkFAmNIHX8CGwwAIQkQa+0YXjF4r/AWIQQ/UgTtZL3DmJAlEPxr7RheMXiv\n8FlgAP9S+Oc82N6iSA4gj9hOt6dz7E4YE/3XGf+7uVQb3xVYSQD6A4X+cisS\nfqCVd5bPCMqAQQHjHgGBQawPK/PXyk9JxQQ=\n=idJc\n-----END PGP PRIVATE KEY BLOCK-----\n';
2
+
3
+ const CRYPT_PUBLIC_KEY = '-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxjMEY0gdfxYJKwYBBAHaRw8BAQdAYqNejQxT4gE+w2nwBvP+pe19P152F6LV\n8sqM/Qhut2DNF3J4dGVzdCA8aW5mb0ByeG9tZS5uZXQ+wowEEBYKAB0FAmNI\nHX8ECwkHCAMVCAoEFgACAQIZAQIbAwIeAQAhCRBr7RheMXiv8BYhBD9SBO1k\nvcOYkCUQ/GvtGF4xeK/wluwA+wZSJ9QR8fJDncq7ehNC9RCiFIvPEN40IIZr\n5UKJrCMyAQClt3u4GJECbnxU5U1pg+XWJj+L9w3wBr5JhZYzrx38Bs44BGNI\nHX8SCisGAQQBl1UBBQEBB0DQaAYlsG/belgjLpaev6KYFSfPIijmPTKQKGeX\nchGycAMBCAfCeAQYFggACQUCY0gdfwIbDAAhCRBr7RheMXiv8BYhBD9SBO1k\nvcOYkCUQ/GvtGF4xeK/wWWAA/1L45zzY3qJIDiCP2E63p3PsThgT/dcZ/7u5\nVBvfFVhJAPoDhf5yKxJ+oJV3ls8IyoBBAeMeAYFBrA8r89fKT0nFBA==\n=odkw\n-----END PGP PUBLIC KEY BLOCK-----\n';
4
+
5
+ const R_ID = 'rxome';
6
+ const R_PUBLIC_KEY = '4OShAt7RQ/RJA0qAvoaOQ2jx7SFBYef70XPIz7r9924=';
7
+ const R_PRIVATE_KEY = 'Rf7VbeUBQmjvAagwsWx6riaZYc7h4OBD4CuxYyZ5bgA=';
8
+ // const R_PUBLIC_KEY = '60uReCXTn7KTEIExM4KveKstBGI3TaSrQss4biaesNs=';
9
+ // const R_PRIVATE_KEY = 'lBSkSxe/+UBWOeF5OJdQgf9qZhiI85hYE6yJCuWjCNk=';
10
+ // const R_PRIVATE_KEY = 'NamaTB+xwDFxtkQyBBkjRr5GEaXNtCw/G4qydnhQk5Y=';
11
+ // const R_PUBLIC_KEY = 'XvbhLWKbA1wfKsx3B7FKQuDQsZTZ/dMXWiD1MehBxZg=';
12
+
13
+ const J_ID = 'rxomej';
14
+ const J_PRIVATE_KEY = 'QhcoRruGBVP39XCh8BujCE+q42qCRy/tu2CQ4YmRBgg=';
15
+ const J_PUBLIC_KEY = 'XL/i8jrJC55AdOV3zYHIIa095De5eYbDqWDPDW2r8tk=';
16
+
17
+ const DEMO_CREDENTIALS = {
18
+ id: R_ID,
19
+ user: 'test@rxome.net',
20
+ key: R_PRIVATE_KEY
21
+ };
22
+
23
+ export { CRYPT_PRIVATE_KEY, CRYPT_PUBLIC_KEY, DEMO_CREDENTIALS };
24
+ export const DEMO_API_PRIVATE_KEY = R_PRIVATE_KEY;
25
+ export const DEMO_API_PUBLIC_KEY = R_PUBLIC_KEY;
26
+ export const DEMO_API_ID = R_ID;
@@ -0,0 +1,247 @@
1
+ // Using native fetch API instead of axios for better webpack compatibility
2
+ import * as ED from 'noble-ed25519';
3
+ import Protobuf from 'protobufjs';
4
+ import { stringify } from 'querystring';
5
+
6
+ const API = 'https://app.findme2care.de';
7
+ const TESTAPI = 'https://stage.findme2care.de';
8
+ const APIENTRY = 'api/v1';
9
+ const VSTR = 'API1.0'
10
+ const IS_DEMO = '_DEMO_PSEUDONYM_';
11
+
12
+ export { API, TESTAPI, APIENTRY, VSTR, IS_DEMO };
13
+
14
+ /************************************************************************************
15
+ * Helper functions
16
+ ************************************************************************************/
17
+
18
+ // have issues:
19
+ const base64ToBufferVintage = data => atob(data.toString());
20
+ //const bufferToBase64 = data => Buffer.from(data).toString('base64');
21
+
22
+ const unpack = (arr) => Uint8Array.from( arr.map( c => c.charCodeAt(0) ));
23
+
24
+ let readSigKey = name => { console.log("Error: not supported") }
25
+
26
+ const base64ToBuffer = enc => {
27
+ const len = Protobuf.util.base64.length(enc);
28
+ let buf = new Protobuf.util.Array( len );
29
+ Protobuf.util.base64.decode(enc, buf, 0);
30
+ return buf;
31
+ }
32
+
33
+ const bufferToBase64 = buf => {
34
+ return Protobuf.util.base64.encode(buf, 0, buf.length);
35
+ }
36
+
37
+ export { base64ToBuffer, bufferToBase64, unpack };
38
+
39
+ /************************************************************************************
40
+ * Functions for node.js only
41
+ ************************************************************************************/
42
+
43
+ // Node.js specific functions that require fs module
44
+ readSigKey = async name => {
45
+ try {
46
+ const FS = await import('fs');
47
+ if (!FS.existsSync( name )) {
48
+ throw 'Key file not found!';
49
+ }
50
+ return FS.readFileSync( name ).slice(0,44);
51
+ } catch (e) {
52
+ if (e instanceof Error && e.code !== "MODULE_NOT_FOUND") {
53
+ throw e;
54
+ }
55
+ throw new Error('fs module not available - cannot read key file');
56
+ }
57
+ }
58
+
59
+ export const generateApiKeys = async () => {
60
+ const privateKey = ED.utils.randomPrivateKey();
61
+ const publicKey = await ED.getPublicKey(privateKey);
62
+ return {
63
+ privateKey: privateKey,
64
+ publicKey: publicKey
65
+ }
66
+ }
67
+
68
+ export const writeApiKeys = async (name = 'rxome', dir = '.') => {
69
+ try {
70
+ const FS = await import('fs');
71
+ const key = await generateApiKeys();
72
+ await Promise.all([
73
+ FS.writeFile( `${dir}/${name}.private.apikey`, bufferToBase64( key.privateKey ), { mode: 0o600 }, err => { if (err) throw err; } ),
74
+ FS.writeFile( `${dir}/${name}.public.apikey`, bufferToBase64( key.publicKey ), { mode: 0o600 }, err => { if (err) throw err; } )
75
+ ]);
76
+ } catch (e) {
77
+ if (e instanceof Error && e.code !== "MODULE_NOT_FOUND") {
78
+ throw e;
79
+ }
80
+ throw new Error('fs module not available - cannot write API keys');
81
+ }
82
+ }
83
+
84
+ export { readSigKey };
85
+
86
+ /************************************************************************************/
87
+
88
+ export const signData = async( keyId, user, keyB64, created, debug = false ) => {
89
+ const message = `x-date: ${created}\nx-rxome-user: ${user}`
90
+ const messageUi8 = unpack( Array.from(message) );
91
+
92
+ const key = unpack( [...base64ToBufferVintage(keyB64)] );
93
+ debug && console.log('Base 64 key: ', keyB64);
94
+ debug && console.log('Binary key: ', key, " Key length: ", key.length);
95
+
96
+ const signature = await ED.sign( messageUi8, key);
97
+ const sigB64 = bufferToBase64( signature );
98
+ const auth=`Signature keyId="${keyId}",algorithm="ed25519",headers="x-date x-rxome-user",signature="${sigB64}",created="${created}"`
99
+ debug && console.log('Auth string: ', auth);
100
+
101
+ return auth;
102
+ }
103
+
104
+ export const fetchData = async ( url, credentials, pseudonym = '', debug = false ) => {
105
+ debug && console.log( 'Fetching from', url )
106
+
107
+ const created = Date.now();
108
+ const keyId = credentials.keyId || "rxome";
109
+ const user = credentials.user || `${keyId}@rxome.net`;
110
+ const keyB64 = credentials.key || await readSigKey( process.cwd()+'/'+credentials.keyFile );
111
+
112
+ const auth = await signData( keyId, user, keyB64, created, debug );
113
+
114
+ // Build URL with query parameters
115
+ const urlParams = new URLSearchParams({
116
+ pslab: !!pseudonym.trim(),
117
+ demo: pseudonym === IS_DEMO
118
+ });
119
+ const fullUrl = `${url}?${urlParams}`;
120
+
121
+ // Create AbortController for timeout
122
+ const controller = new AbortController();
123
+ const timeoutId = setTimeout(() => controller.abort(), 5000);
124
+
125
+ return fetch(fullUrl, {
126
+ method: 'GET',
127
+ headers: {
128
+ Authorization: auth,
129
+ 'x-date': created,
130
+ 'x-rxome-user': user
131
+ },
132
+ signal: controller.signal
133
+ })
134
+ .then(async response => {
135
+ clearTimeout(timeoutId);
136
+ if (!response.ok) {
137
+ let errorData = null;
138
+ try {
139
+ errorData = await response.json();
140
+ } catch (e) {
141
+ // If response can't be parsed as JSON, use default error
142
+ }
143
+
144
+ const error = new Error(`HTTP error! status: ${response.status}`);
145
+ error.response = {
146
+ status: response.status,
147
+ statusText: response.statusText,
148
+ headers: response.headers,
149
+ data: errorData
150
+ };
151
+ throw error;
152
+ }
153
+ return response.json();
154
+ })
155
+ .then(data => {
156
+ debug && console.log( "Result Data= ", data );
157
+ return data;
158
+ })
159
+ .catch(error => {
160
+ clearTimeout(timeoutId);
161
+ if (error.name === 'AbortError') {
162
+ const timeoutError = new Error('Request timeout');
163
+ timeoutError.response = {
164
+ status: 408,
165
+ statusText: 'Request Timeout',
166
+ data: { message: 'Request timeout' }
167
+ };
168
+ throw timeoutError;
169
+ }
170
+ throw error;
171
+ })
172
+ }
173
+
174
+ export const pushData = async ( url, credentials, msg, debug = false ) => {
175
+ debug && console.log( 'Pushing to ', url )
176
+ console.log( 'Pushing to ', url )
177
+
178
+ const created = Date.now();
179
+ const keyId = credentials.keyId || "rxome";
180
+ const user = credentials.user || `${keyId}@rxome.net`;
181
+ const keyB64 = credentials.key || await readSigKey( process.cwd()+'/'+credentials.keyFile );
182
+
183
+ const auth = await signData( keyId, user, keyB64, created, debug );
184
+
185
+ // Create AbortController for timeout
186
+ const controller = new AbortController();
187
+ const timeoutId = setTimeout(() => controller.abort(), 5000);
188
+
189
+ return fetch(url, {
190
+ method: 'POST',
191
+ headers: {
192
+ 'Content-Type': 'application/json',
193
+ Authorization: auth,
194
+ 'x-date': created,
195
+ 'x-rxome-user': user
196
+ },
197
+ body: JSON.stringify(msg),
198
+ signal: controller.signal
199
+ })
200
+ .then(response => {
201
+ clearTimeout(timeoutId);
202
+ if (!response.ok) {
203
+ // Create error object similar to axios
204
+ const error = new Error(`HTTP error! status: ${response.status}`);
205
+ error.response = {
206
+ status: response.status,
207
+ statusText: response.statusText,
208
+ headers: response.headers,
209
+ data: null
210
+ };
211
+ throw error;
212
+ }
213
+ return response.json();
214
+ })
215
+ .then(data => {
216
+ debug && console.log( "Result Data= ", data );
217
+ return data;
218
+ })
219
+ .catch( (error) => {
220
+ clearTimeout(timeoutId);
221
+ let msg = null;
222
+ if (error.response) {
223
+ // Request made and server responded
224
+ if (error.response && error.response.data && error.response.data.message){
225
+ console.log( '[SendData Response Error] ', error.response.data.message );
226
+ msg = `Response Error: ${error.response.data.message}`;
227
+ console.log(error.response.data);
228
+ } else {
229
+ console.log( '[SendData Response Error] no message' );
230
+ msg = 'Unknown response error';
231
+ }
232
+ console.log(error.response.status);
233
+ console.log(error.response.headers);
234
+ } else if (error.name === 'AbortError') {
235
+ // Request was aborted (timeout)
236
+ console.log('[SendData Timeout Error]');
237
+ msg = 'Request timeout';
238
+ } else {
239
+ // Something happened in setting up the request that triggered an Error
240
+ console.log('[SendData Request Error] ', error.message);
241
+ msg = `Request Error: ${error.message}`;
242
+ }
243
+ const err = new Error( `Error sending data: ${msg}` );
244
+ console.log(err.name + ': ' + err.message);
245
+ throw err;
246
+ })
247
+ }
@@ -1,19 +1,19 @@
1
- const RxAPI = require('./rxome-api');
2
- const FS = require('fs');
3
- const ED = require( 'noble-ed25519' );
1
+ import * as RxAPI from './rxome-api.js';
2
+ import { readFileSync, existsSync, statSync } from 'fs';
3
+ import * as ED from 'noble-ed25519';
4
4
 
5
5
  describe('API access', () => {
6
6
  test.skip('generates valid API access keys', async () => {
7
7
  await RxAPI.writeApiKeys( '__TESTSUITE_jesttest' );
8
- expect( FS.existsSync('__TESTSUITE_jesttest.private.apikey') ).toBe( true );
9
- expect( FS.existsSync('__TESTSUITE_jesttest.public.apikey') ).toBe( true );
10
- expect( FS.statSync('__TESTSUITE_jesttest.private.apikey').size - 44 ).toBeLessThan( 2 );
11
- expect( FS.statSync('__TESTSUITE_jesttest.public.apikey').size - 44 ).toBeLessThan( 2 );
8
+ expect( existsSync('__TESTSUITE_jesttest.private.apikey') ).toBe( true );
9
+ expect( existsSync('__TESTSUITE_jesttest.public.apikey') ).toBe( true );
10
+ expect( statSync('__TESTSUITE_jesttest.private.apikey').size - 44 ).toBeLessThan( 2 );
11
+ expect( statSync('__TESTSUITE_jesttest.public.apikey').size - 44 ).toBeLessThan( 2 );
12
12
 
13
13
  const message='Answer to life the universe and everything';
14
14
  const messageUi8 = RxAPI.unpack(Array.from(message));
15
- const privKey = RxAPI.unpack([...RxAPI.base64ToBuffer( FS.readFileSync('__TESTSUITE_jesttest.private.apikey'))])
16
- const pubKey = RxAPI.unpack([...RxAPI.base64ToBuffer( FS.readFileSync('__TESTSUITE_jesttest.public.apikey'))])
15
+ const privKey = RxAPI.unpack([...RxAPI.base64ToBuffer( readFileSync('__TESTSUITE_jesttest.private.apikey'))])
16
+ const pubKey = RxAPI.unpack([...RxAPI.base64ToBuffer( readFileSync('__TESTSUITE_jesttest.public.apikey'))])
17
17
  const signature = await ED.sign(messageUi8, privKey);
18
18
  const isValid = await ED.verify(signature, messageUi8, pubKey);
19
19
  expect( isValid ).toBeTruthy;
@@ -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,26 @@ 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 ) =>
144
154
  isNaN(+(str.toString()))
145
155
  ? Math.max(0, ENUM_ACMG.indexOf(str.toUpperCase()))
146
156
  : +str
147
157
 
148
158
 
149
- exports.whiteListPhenoPacket = ( data ) => {
150
- res = {};
159
+ export const whiteListPhenoPacket = ( data ) => {
160
+ let res = {};
151
161
  data.id && (res.id = data.id);
152
162
  data.comment && (res.comment = data.comment);
153
163
  data.subject && (res.subject = data.subject);
@@ -161,48 +171,48 @@ exports.whiteListPhenoPacket = ( data ) => {
161
171
  }
162
172
 
163
173
 
164
- exports.sanitizePhenoPacket = ( data, key = '' ) => {
174
+ export const sanitizePhenoPacket = ( data, key = '' ) => {
165
175
  if ( data instanceof Object ) {
166
176
  if (Array.isArray( data )) {
167
- return data.map( x => exports.sanitizePhenoPacket(x));
177
+ return data.map( x => sanitizePhenoPacket(x));
168
178
  } else {
169
179
  let obj={};
170
- for ( let k in data ) {
171
- obj[k] = exports.sanitizePhenoPacket( data[k], k );
180
+ for ( let k in data ) {
181
+ obj[k] = sanitizePhenoPacket( data[k], k );
172
182
  }
173
183
  return obj;
174
184
  }
175
185
  } else {
176
186
  switch( key ){
177
187
  case 'sex':
178
- return exports.sanitizeSex( data );
188
+ return sanitizeSex( data );
179
189
  case 'progressStatus':
180
- return exports.sanitizeProgState( data );
190
+ return sanitizeProgState( data );
181
191
  case 'acmgPathogenicityClassification':
182
- return exports.sanitizeACMG( data );
183
- default:
192
+ return sanitizeACMG( data );
193
+ default:
184
194
  return data;
185
195
  }
186
196
  }
187
197
  }
188
198
 
189
199
 
190
- exports.verifyPhenoPacket = (data) => (
200
+ export const verifyPhenoPacket = (data) => (
191
201
  PhenoPacket.verify( data )
192
202
  )
193
203
 
194
204
 
195
- exports.encodePhenoPacket = (data) => (
205
+ export const encodePhenoPacket = (data) => (
196
206
  PhenoPacket.encode( data ).finish()
197
207
  )
198
208
 
199
209
 
200
- exports.decodePhenoPacket = (data) => (
210
+ export const decodePhenoPacket = (data) => (
201
211
  PhenoPacket.decode( data )
202
212
  )
203
213
 
204
214
 
205
- exports.encode_serial = async (publicKeyStr, message) => {
215
+ export const encode_serial = async (publicKeyStr, message) => {
206
216
  const publicKey = await PGP.readKey({ armoredKey: publicKeyStr });
207
217
  const encrypted = await PGP.encrypt({
208
218
  message: await PGP.createMessage({ text: message }),
@@ -214,10 +224,10 @@ exports.encode_serial = async (publicKeyStr, message) => {
214
224
  }
215
225
 
216
226
 
217
- exports.encode = async (publicKeyStr, message, binary = false) => {
227
+ export const encode = async (publicKeyStr, message, binary = false) => {
218
228
  return await Promise.all([
219
229
  PGP.readKey({ armoredKey: publicKeyStr }),
220
- PGP.createMessage( (binary
230
+ PGP.createMessage( (binary
221
231
  ? { binary: message, format: 'binary' }
222
232
  : { text: message }) )
223
233
  ]).then( async ([publicKey, message]) => {
@@ -233,7 +243,7 @@ exports.encode = async (publicKeyStr, message, binary = false) => {
233
243
  }
234
244
 
235
245
 
236
- exports.decode_serial = async (privateKeyStr, encrypted) => {
246
+ export const decode_serial = async (privateKeyStr, encrypted) => {
237
247
  const privateKey = await PGP.readPrivateKey( { armoredKey: privateKeyStr } );
238
248
  const privateKeyDecr = await PGP.decryptKey({
239
249
  privateKey: privateKey,
@@ -250,16 +260,16 @@ exports.decode_serial = async (privateKeyStr, encrypted) => {
250
260
  }
251
261
 
252
262
 
253
- exports.decode = async (privateKeyStr, encrypted, binary = false) => {
263
+ export const decode = async (privateKeyStr, encrypted, binary = false) => {
254
264
  return await Promise.all([
255
265
  PGP.readPrivateKey({ armoredKey: privateKeyStr })
256
266
  .then( (privateKey) => {
257
267
  return PGP.decryptKey({
258
268
  privateKey: privateKey,
259
- passphrase: PASSPHRASE
269
+ passphrase: PASSPHRASE
260
270
  })
261
271
  }),
262
- PGP.readMessage( (binary
272
+ PGP.readMessage( (binary
263
273
  ? {binaryMessage: encrypted}
264
274
  : {armoredMessage: encrypted} )
265
275
  )
@@ -282,27 +292,28 @@ exports.decode = async (privateKeyStr, encrypted, binary = false) => {
282
292
  }
283
293
 
284
294
 
285
- exports.prepareQR = async ( data, api = RXAPI, apiEntry = APIENTRY ) => {
295
+ export const prepareQR = async ( data, api = RXAPI, apiEntry = APIENTRY ) => {
296
+ console.log(`RxOME QR Generator version: ${version}`);
286
297
  const { metaData, credentials, ...medical } = data;
287
298
 
288
- const whiteListMedical = exports.whiteListPhenoPacket( medical );
289
- const sanitizedMedical = exports.sanitizePhenoPacket( whiteListMedical );
290
- const compressedMedical = exports.compressPhenoPacket( sanitizedMedical );
291
- const protobufMedical = exports.encodePhenoPacket( compressedMedical );
299
+ const whiteListMedical = whiteListPhenoPacket( medical );
300
+ const sanitizedMedical = sanitizePhenoPacket( whiteListMedical );
301
+ const compressedMedical = compressPhenoPacket( sanitizedMedical );
302
+ const protobufMedical = encodePhenoPacket( compressedMedical );
292
303
  const base64Medical = RxAPI.bufferToBase64(protobufMedical);
293
304
 
294
- const key = await this.fetchKey( credentials, metaData?.pseudonym || '', api, false, apiEntry );
305
+ const key = await fetchKey( credentials, (metaData && metaData.pseudonym) || '', api, false, apiEntry );
295
306
 
296
307
  // check:
297
308
  const buff = RxAPI.base64ToBuffer( base64Medical );
298
- const pheno = exports.decodePhenoPacket( buff );
309
+ const pheno = decodePhenoPacket( buff );
299
310
  const medicalDeciphered = JSON.parse( JSON.stringify( pheno ));
300
311
  // console.log( JSON.stringify(medicalDeciphered,' ', 2 ))
301
312
 
302
- const cipher = await exports.encode( key.key, base64Medical );
313
+ const cipher = await encode( key.key, base64Medical );
303
314
 
304
315
  //delete metaData.pseudonym;
305
- const newMetaData = Object.fromEntries(
316
+ const newMetaData = Object.fromEntries(
306
317
  Object.entries( metaData ).filter( ([key, val]) => key !== 'pseudonym')
307
318
  )
308
319
 
@@ -312,7 +323,7 @@ exports.prepareQR = async ( data, api = RXAPI, apiEntry = APIENTRY ) => {
312
323
  labid: key.lab_id,
313
324
  keyver: key.version,
314
325
  apiver: apiVer,
315
- pseudonym: key.pseudonym,
326
+ pseudonym: key.pseudonym,
316
327
  payload: cipher.toString()
317
328
  }
318
329
 
@@ -331,8 +342,8 @@ exports.prepareQR = async ( data, api = RXAPI, apiEntry = APIENTRY ) => {
331
342
  }
332
343
 
333
344
 
334
- exports.makeQR = async ( data, api = RXAPI, apiEntry = APIENTRY ) => {
335
- const {qrData, pseudonym, content} = await exports.prepareQR( data, api, apiEntry );
345
+ export const makeQR = async ( data, api = RXAPI, apiEntry = APIENTRY ) => {
346
+ const {qrData, pseudonym, content} = await prepareQR( data, api, apiEntry );
336
347
  return {
337
348
  qr_code: await QRCode.toDataURL( JSON.stringify( qrData )),
338
349
  pseudonym: pseudonym,
@@ -341,8 +352,8 @@ exports.makeQR = async ( data, api = RXAPI, apiEntry = APIENTRY ) => {
341
352
  }
342
353
  }
343
354
 
344
- exports.versionStr = () => {
345
- return 'RxOME QR Generator 1.0.0, 2022 Tom Kamphans, GeneTalk GmbH'
355
+ export const versionStr = () => {
356
+ return `RxOME QR Generator ${version}, 2025 Tom Kamphans, GeneTalk GmbH/RxOme GmbH`
346
357
  }
347
358
 
348
359
 
@@ -356,5 +367,4 @@ exports.versionStr = () => {
356
367
  // const clearBin = Buffer.from (clearBufferBin, 'Binary');
357
368
  // const phenoPrimeBin = Coder.decodePhenoPacket(clearBin);
358
369
  // const phenoBin = JSON.parse(JSON.stringify(phenoPrimeBin));
359
- // ////
360
-
370
+ // ////