rxome-generator 0.1.0 → 0.1.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.
package/- ADDED
@@ -0,0 +1 @@
1
+ answer to life the universe and everything
package/README.md CHANGED
@@ -1,8 +1,15 @@
1
1
  # rxome-qrcode-generator
2
2
  Generates QR codes containing medical information for use with the RxOME database.
3
-
4
3
  **Right now, it works only with the test API**
5
4
 
5
+ ## LICENSE
6
+
7
+ Copyright (c) 2022 MGZ-Tech GmbH, GeneTalk GmbH
8
+
9
+ All rights reserved, unauthorized use prohibited.
10
+
11
+ ## Purpose
12
+
6
13
  This package offers a JavaScript library for generating QR codes from medical data as well as
7
14
  a command line tool as front end to this library. Both expect the medical data in JSON format
8
15
  according to a subset of the PhenoPacket standard (with some additions), see below.
@@ -195,7 +202,7 @@ The type of genetic test performed to obtain a variant can be specified in an ex
195
202
 
196
203
  ### Additional Remarks
197
204
 
198
- Additional remarks can be specified in a *comment* field in the top level:
205
+ Additional remarks can be specified in a *comment* field on the top level:
199
206
 
200
207
  ```
201
208
  {
@@ -0,0 +1,17 @@
1
+ -----BEGIN PGP PRIVATE KEY BLOCK-----
2
+
3
+ xYYEY8BGEhYJKwYBBAHaRw8BAQdAegfXQCYheo+FJXoIY0qPYAeP+67inq0u
4
+ 0AZE8yrEOJ3+CQMIQ3S9CuD3PUTgKF/q8xafzIvLlEuLTCAInll8oSg9zb+2
5
+ MTFp3EEOZifKIA9YY1ujro17MzR3p/Bfdt2ayo+Pcxq0g9JNgrHfzUeIuTxG
6
+ xM0VZGVtbyA8aW5mb0ByeG9tZS5uZXQ+wowEEBYKAB0FAmPARhIECwkHCAMV
7
+ CAoEFgACAQIZAQIbAwIeAQAhCRABSM3I8Z0TohYhBGfCy2DdehZ+Frs2fgFI
8
+ zcjxnROi9ukA/RmZoF4VKDJouTjxPxCEzIqbM+9ZfHFyLmkr9EtMR0D+AP9o
9
+ 5Rauo9ium/t88qxfeCpcPTULZ4qu5GBkBHg9XCYrAceLBGPARhISCisGAQQB
10
+ l1UBBQEBB0A82B97nnZ60gGWR2v8mn319Yb8AdKGD85ier7hwSe/OgMBCAf+
11
+ CQMIUzDpTTSoyZrg8AVwyRZVmrXQbE9mzRtcy2sM3fbNyZCW44Rz0rgxwC+z
12
+ 1EfRC442wQSDs6pat0eeBX1Eh6vqENIRsCQNK426BD8XWWLor8J4BBgWCAAJ
13
+ BQJjwEYSAhsMACEJEAFIzcjxnROiFiEEZ8LLYN16Fn4WuzZ+AUjNyPGdE6In
14
+ sAD9GNlDrmnRIz+IP0XGheue6IhMLgzss2TsvRv2K8HQGqsBAIC3k3/T/sCN
15
+ MnR+TVPz/zYEEAbxEEurgfWdn1c8B0AM
16
+ =Sgm6
17
+ -----END PGP PRIVATE KEY BLOCK-----
@@ -0,0 +1,13 @@
1
+ -----BEGIN PGP PUBLIC KEY BLOCK-----
2
+
3
+ xjMEY8BGEhYJKwYBBAHaRw8BAQdAegfXQCYheo+FJXoIY0qPYAeP+67inq0u
4
+ 0AZE8yrEOJ3NFWRlbW8gPGluZm9AcnhvbWUubmV0PsKMBBAWCgAdBQJjwEYS
5
+ BAsJBwgDFQgKBBYAAgECGQECGwMCHgEAIQkQAUjNyPGdE6IWIQRnwstg3XoW
6
+ fha7Nn4BSM3I8Z0TovbpAP0ZmaBeFSgyaLk48T8QhMyKmzPvWXxxci5pK/RL
7
+ TEdA/gD/aOUWrqPYrpv7fPKsX3gqXD01C2eKruRgZAR4PVwmKwHOOARjwEYS
8
+ EgorBgEEAZdVAQUBAQdAPNgfe552etIBlkdr/Jp99fWG/AHShg/OYnq+4cEn
9
+ vzoDAQgHwngEGBYIAAkFAmPARhICGwwAIQkQAUjNyPGdE6IWIQRnwstg3XoW
10
+ fha7Nn4BSM3I8Z0ToiewAP0Y2UOuadEjP4g/RcaF657oiEwuDOyzZOy9G/Yr
11
+ wdAaqwEAgLeTf9P+wI0ydH5NU/P/NgQQBvEQS6uB9Z2fVzwHQAw=
12
+ =w+2C
13
+ -----END PGP PUBLIC KEY BLOCK-----
@@ -139,11 +139,12 @@
139
139
  "created": "2021-05-14T10:35:00Z",
140
140
  "createdBy": "mgz",
141
141
  "submittedBy": "a_clinician@mgz-muenchen.de",
142
- "phenopacketSchemaVersion": "2.0"
142
+ "phenopacketSchemaVersion": "2.0",
143
+ "pseudonym": "_DEMO_PSEUDONYM_"
143
144
  },
144
145
  "credentials": {
145
- "key": "QhcoRruGBVP39XCh8BujCE+q42qCRy/tu2CQ4YmRBgg=",
146
- "keyId": "mgz",
146
+ "key": "lBSkSxe/+UBWOeF5OJdQgf9qZhiI85hYE6yJCuWjCNk=",
147
+ "keyId": "rxome",
147
148
  "user": "a_clinician@mgz-muenchen.de"
148
149
  }
149
150
  }
@@ -51,7 +51,8 @@
51
51
  "created": "2021-05-14T10:35:00Z",
52
52
  "createdBy": "mgz",
53
53
  "submittedBy": "a_clinician@mgz-muenchen.de",
54
- "phenopacketSchemaVersion": "2.0"
54
+ "phenopacketSchemaVersion": "2.0",
55
+ "pseudonym": "_DEMO_PSEUDONYM_"
55
56
  },
56
57
  "compressedFeatures": {
57
58
  "includes": [
@@ -69,8 +70,8 @@
69
70
  "excludes": ["HP:0031360", "HP:0001234"]
70
71
  },
71
72
  "credentials": {
72
- "key": "QhcoRruGBVP39XCh8BujCE+q42qCRy/tu2CQ4YmRBgg=",
73
- "keyId": "mgz",
73
+ "key": "lBSkSxe/+UBWOeF5OJdQgf9qZhiI85hYE6yJCuWjCNk=",
74
+ "keyId": "rxome",
74
75
  "user": "a_clinician@mgz-muenchen.de"
75
76
  }
76
77
  }
@@ -0,0 +1 @@
1
+ {"key":"\n-----BEGIN PGP PRIVATE KEY BLOCK-----\n\nxYYEY8BGEhYJKwYBBAHaRw8BAQdAegfXQCYheo+FJXoIY0qPYAeP+67inq0u\n0AZE8yrEOJ3+CQMIQ3S9CuD3PUTgKF/q8xafzIvLlEuLTCAInll8oSg9zb+2\nMTFp3EEOZifKIA9YY1ujro17MzR3p/Bfdt2ayo+Pcxq0g9JNgrHfzUeIuTxG\nxM0VZGVtbyA8aW5mb0ByeG9tZS5uZXQ+wowEEBYKAB0FAmPARhIECwkHCAMV\nCAoEFgACAQIZAQIbAwIeAQAhCRABSM3I8Z0TohYhBGfCy2DdehZ+Frs2fgFI\nzcjxnROi9ukA/RmZoF4VKDJouTjxPxCEzIqbM+9ZfHFyLmkr9EtMR0D+AP9o\n5Rauo9ium/t88qxfeCpcPTULZ4qu5GBkBHg9XCYrAceLBGPARhISCisGAQQB\nl1UBBQEBB0A82B97nnZ60gGWR2v8mn319Yb8AdKGD85ier7hwSe/OgMBCAf+\nCQMIUzDpTTSoyZrg8AVwyRZVmrXQbE9mzRtcy2sM3fbNyZCW44Rz0rgxwC+z\n1EfRC442wQSDs6pat0eeBX1Eh6vqENIRsCQNK426BD8XWWLor8J4BBgWCAAJ\nBQJjwEYSAhsMACEJEAFIzcjxnROiFiEEZ8LLYN16Fn4WuzZ+AUjNyPGdE6In\nsAD9GNlDrmnRIz+IP0XGheue6IhMLgzss2TsvRv2K8HQGqsBAIC3k3/T/sCN\nMnR+TVPz/zYEEAbxEEurgfWdn1c8B0AM\n=Sgm6\n-----END PGP PRIVATE KEY BLOCK-----\n","cipher":"\n-----BEGIN PGP MESSAGE-----\n\nwV4DwTe9/0b1zzgSAQdAxe4Phva3n19MInlPhQS4OxG78y+3mTsNHVfsk5OF\nnGAwld5yaBCzLoudwGLQ17qIkABl9rhONf8VJMNoTOZOf8nPoouCKdXxktv7\ndG1wvV2s0lsBvUBUmaOzix1hEF6YeUr7mfc+MBBt/2gfoyT4Kujgrg25YoZ6\nqUgqga2eSZ6O+OhyjuFo3rZVXl1MFY6lfu+X+i4cCE2VWiAQOwVNnqFdY9FF\nuOPuzhz7UstK\n=KKxC\n-----END PGP MESSAGE-----\n"}
@@ -0,0 +1 @@
1
+ {"key":"\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxjMEY8BGEhYJKwYBBAHaRw8BAQdAegfXQCYheo+FJXoIY0qPYAeP+67inq0u\n0AZE8yrEOJ3NFWRlbW8gPGluZm9AcnhvbWUubmV0PsKMBBAWCgAdBQJjwEYS\nBAsJBwgDFQgKBBYAAgECGQECGwMCHgEAIQkQAUjNyPGdE6IWIQRnwstg3XoW\nfha7Nn4BSM3I8Z0TovbpAP0ZmaBeFSgyaLk48T8QhMyKmzPvWXxxci5pK/RL\nTEdA/gD/aOUWrqPYrpv7fPKsX3gqXD01C2eKruRgZAR4PVwmKwHOOARjwEYS\nEgorBgEEAZdVAQUBAQdAPNgfe552etIBlkdr/Jp99fWG/AHShg/OYnq+4cEn\nvzoDAQgHwngEGBYIAAkFAmPARhICGwwAIQkQAUjNyPGdE6IWIQRnwstg3XoW\nfha7Nn4BSM3I8Z0ToiewAP0Y2UOuadEjP4g/RcaF657oiEwuDOyzZOy9G/Yr\nwdAaqwEAgLeTf9P+wI0ydH5NU/P/NgQQBvEQS6uB9Z2fVzwHQAw=\n=w+2C\n-----END PGP PUBLIC KEY BLOCK-----\n","message":"answer to life the universe and everything"}
@@ -35,8 +35,10 @@ VBvfFVhJAPoDhf5yKxJ+oJV3ls8IyoBBAeMeAYFBrA8r89fKT0nFBA==
35
35
  `
36
36
 
37
37
  const R_ID = 'rxome';
38
- const R_PRIVATE_KEY = 'NamaTB+xwDFxtkQyBBkjRr5GEaXNtCw/G4qydnhQk5Y=';
39
- const R_PUBLIC_KEY = 'XvbhLWKbA1wfKsx3B7FKQuDQsZTZ/dMXWiD1MehBxZg=';
38
+ const R_PUBLIC_KEY = '60uReCXTn7KTEIExM4KveKstBGI3TaSrQss4biaesNs=';
39
+ const R_PRIVATE_KEY = 'lBSkSxe/+UBWOeF5OJdQgf9qZhiI85hYE6yJCuWjCNk=';
40
+ // const R_PRIVATE_KEY = 'NamaTB+xwDFxtkQyBBkjRr5GEaXNtCw/G4qydnhQk5Y=';
41
+ // const R_PUBLIC_KEY = 'XvbhLWKbA1wfKsx3B7FKQuDQsZTZ/dMXWiD1MehBxZg=';
40
42
 
41
43
  const J_ID = 'rxomej'
42
44
  const J_PRIVATE_KEY = 'QhcoRruGBVP39XCh8BujCE+q42qCRy/tu2CQ4YmRBgg=';
package/lib/rxome-api.js CHANGED
@@ -1,16 +1,20 @@
1
1
  const Axios = require( 'axios' );
2
2
  const ED = require( 'noble-ed25519' );
3
3
  const Protobuf = require('protobufjs');
4
+ const { stringify } = require('querystring');
4
5
  //const BASE64 = require('@protobufjs/base64')
5
6
 
6
7
  const API = 'https://www.rxome.net';
7
- const TESTAPI = 'https://testapi.gene-talk.de';
8
+ const TESTAPI = 'http://stage.rxome.net';
8
9
  const APIENTRY = 'api/v1';
9
10
  const VSTR = 'API1.0'
11
+ const IS_DEMO = '_DEMO_PSEUDONYM_';
12
+
10
13
  exports.API = API;
11
14
  exports.TESTAPI = TESTAPI;
12
15
  exports.APIENTRY = APIENTRY;
13
16
  exports.VSTR = VSTR;
17
+ exports.IS_DEMO = IS_DEMO;
14
18
 
15
19
  /************************************************************************************
16
20
  * Helper functions
@@ -97,13 +101,15 @@ exports.fetchData = async ( url, credentials, pseudonym = '', debug = false ) =>
97
101
  const user = credentials.user || `${keyId}@rxome.net`;
98
102
  const keyB64 = credentials.key || readSigKey( process.cwd()+'/'+credentials.keyFile );
99
103
 
100
- auth = await exports.signData( keyId, user, keyB64, created, debug );
104
+ const auth = await exports.signData( keyId, user, keyB64, created, debug );
101
105
 
106
+ FS = require( 'fs' );
102
107
  return Axios({
103
108
  url: url,
104
109
  method: 'GET',
105
110
  params: {
106
- pslab: !!pseudonym.trim()
111
+ pslab: !!pseudonym.trim(),
112
+ demo: pseudonym === IS_DEMO
107
113
  },
108
114
  headers: {
109
115
  Authorization: auth,
@@ -4,16 +4,16 @@ const ED = require( 'noble-ed25519' );
4
4
 
5
5
  describe('API access', () => {
6
6
  test.skip('generates valid API access keys', async () => {
7
- await RxAPI.generateApiKeys( 'jesttest' );
8
- expect( FS.existsSync('jesttest.private.apikey') ).toBe( true );
9
- expect( FS.existsSync('jesttest.public.apikey') ).toBe( true );
10
- expect( FS.statSync('jesttest.private.apikey').size - 44 ).toBeLessThan( 2 );
11
- expect( FS.statSync('jesttest.public.apikey').size - 44 ).toBeLessThan( 2 );
7
+ await RxAPI.generateApiKeys( '__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 );
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('jesttest.private.apikey'))])
16
- const pubKey = RxAPI.unpack([...RxAPI.base64ToBuffer( FS.readFileSync('jesttest.public.apikey'))])
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'))])
17
17
  const signature = await ED.sign(messageUi8, privKey);
18
18
  const isValid = await ED.verify(signature, messageUi8, pubKey);
19
19
  expect( isValid ).toBeTruthy;
@@ -7,7 +7,8 @@ const Axios = require( 'axios' );
7
7
 
8
8
  const RXAPI = RxAPI.API;
9
9
  const RXTESTAPI = RxAPI.TESTAPI;
10
- const RXLOCALAPI = 'http:localhost:3000';
10
+ // const RXTESTAPI = 'http://localhost:3000';
11
+ const RXLOCALAPI = 'http://localhost:3000';
11
12
 
12
13
  const CREDENTIALS = {
13
14
  id: ApiDemo.DEMO_API_ID,
@@ -28,13 +29,15 @@ const PUBLIC_KEY = ApiDemo.CRYPT_PUBLIC_KEY;
28
29
  const DEMO_API_PRIVATE_KEY = ApiDemo.DEMO_API_PRIVATE_KEY;
29
30
  const DEMO_API_PUBLIC_KEY = ApiDemo.API_PUBLIC_KEY;
30
31
 
32
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
33
+
31
34
  describe('API access', () => {
32
35
 
33
36
  test('is able to connect to API', async () => {
34
- await expect( Coder.fetchKey(CREDENTIALS, '', RXTESTAPI) ).resolves.not.toThrowError();
37
+ await expect( Coder.fetchKey(CREDENTIALS, RxAPI.IS_DEMO, RXTESTAPI) ).resolves.not.toThrowError();
35
38
  });
36
39
 
37
- // test('should fetch key and pseudonyms', async () => {
40
+ // test.skip('should fetch key and pseudonyms', async () => {
38
41
  // Coder.fetchKey(CREDENTIALS, '', RXTESTAPI)
39
42
  // .then( result => {
40
43
  // //console.log( PUBLIC_KEY )
@@ -46,7 +49,7 @@ describe('API access', () => {
46
49
  // });
47
50
 
48
51
  test('should fetch key and pseudonyms', () => {
49
- Coder.fetchKey(CREDENTIALS, '', RXTESTAPI)
52
+ Coder.fetchKey(CREDENTIALS, RxAPI.IS_DEMO, RXTESTAPI)
50
53
  .then(result => {
51
54
  expect(result.pseudonym).toBe(DEMO_PSEUDONYM);
52
55
  expect(result.key.trim()).toBe(PUBLIC_KEY.trim());
@@ -63,7 +66,7 @@ describe('API access', () => {
63
66
 
64
67
  // error handling:
65
68
  test('should raise an error when url is wrong', () => {
66
- Coder.fetchKey(CREDENTIALS, '', 'https://testapi.gene-talk.de/api/v1/schnitzel/', false, 'fehler')
69
+ Coder.fetchKey(CREDENTIALS, '', RXTESTAPI, false, '/api/v1/errortest')
67
70
  .then(data => { })
68
71
  .catch(err => {
69
72
  expect(err.message).toMatch('404');
@@ -106,7 +109,8 @@ describe('fetchDemoKey', () => {
106
109
  Coder.fetchDemoPrivateKey(CREDENTIALS, RXTESTAPI )
107
110
  .then(result => {
108
111
  expect(result.private_key.trim()).toBe(PRIVATE_KEY.trim())
109
- });
112
+ })
113
+ .catch( err => { process.stderr.write( JSON.stringify( err ))});
110
114
  });
111
115
  });
112
116
 
@@ -115,7 +119,7 @@ describe('Phenopackets preprocessor', () => {
115
119
  test('converts camelCase to snake_case', () => {
116
120
  const snake = Coder.convert_to_snake_case(DEMO_DATA);
117
121
  const camel = Coder.convertToCamelCase(snake);
118
- expect(JSON.stringify(snake).match(/_/g).length).toBe( 30 );
122
+ expect(JSON.stringify(snake).match(/_/g).length).toBe( 33 );
119
123
  expect(camel).toEqual(DEMO_DATA);
120
124
  });
121
125
 
@@ -263,7 +267,7 @@ describe('Coder', () => {
263
267
 
264
268
  test('should encode and decode with key from server', async () => {
265
269
  const message = 'A-well-a bird bird bird, bird is the word';
266
- const keypkg = await Coder.fetchKey(CREDENTIALS, '', RXTESTAPI);
270
+ const keypkg = await Coder.fetchKey(CREDENTIALS, RxAPI.IS_DEMO, RXTESTAPI);
267
271
  expect(keypkg.pseudonym).toBe(DEMO_PSEUDONYM);
268
272
  const cipher = await Coder.encode(keypkg.key, message);
269
273
  const clear = await Coder.decode(PRIVATE_KEY, cipher);
@@ -283,20 +287,18 @@ describe('Coder', () => {
283
287
 
284
288
 
285
289
  describe('Rails', () => {
286
- test.skip('should be able to decode cipher', async() => {
290
+ test('should be able to decode cipher', async() => {
287
291
  const message = 'A-well-a bird bird bird, bird is the word';
288
292
  const cipher = await Coder.encode(PUBLIC_KEY, message);
289
293
 
290
294
  const res = await Axios({
291
- method: 'GET',
292
- url: 'http://localhost:3000/api/v1/decryptTest',
295
+ method$: 'GET',
296
+ url: `${RXTESTAPI}/api/v1/decryptTest`,
293
297
  data: {
294
298
  cipher: cipher
295
299
  }
296
300
  })
297
- // @TODO: do not send to localhorst
298
301
  expect( res.data?.clearText ).toEqual( message )
299
-
300
302
  });
301
303
  });
302
304
 
@@ -312,8 +314,10 @@ describe('Serial version of coder', () => {
312
314
 
313
315
  test('should encode and decode with key from server', async () => {
314
316
  const message = 'A-well-a bird bird bird, bird is the word';
315
- const keypkg = await Coder.fetchKey(CREDENTIALS, '', RXTESTAPI, false);
316
- const { private_key } = await Coder.fetchDemoPrivateKey(CREDENTIALS);
317
+ const keypkg = await Coder.fetchKey(CREDENTIALS, RxAPI.IS_DEMO, RXTESTAPI, false);
318
+ const { private_key } = await Coder.fetchDemoPrivateKey(CREDENTIALS, RXTESTAPI)
319
+ //.then( data => {console.log( data )})
320
+ //.catch( err => { process.stderr.write( JSON.stringify( err ))})
317
321
  expect(keypkg.pseudonym).toBe(DEMO_PSEUDONYM);
318
322
  const cipher = await Coder.encode(keypkg.key, message);
319
323
  const clear = await Coder.decode(private_key, cipher);
@@ -326,14 +330,17 @@ describe('QR Code generator', () => {
326
330
  test('should make QR code', async () => {
327
331
  const newData = { ...DEMO_DATA, metaData: { ...DEMO_DATA.metaData } };
328
332
  delete newData.metaData.pseudonym;
329
- const { qr_code, pseudonym } = await Coder.makeQR(
333
+ //const { qr_code, pseudonym } = await
334
+ Coder.makeQR(
330
335
  newData,
331
336
  RXTESTAPI
332
- );
333
- //console.log( qr_code.length );
334
- //expect( qr_code.length ).toBe( 25750 );
335
- expect(qr_code.startsWith(' data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAiQAAAIkCAYAAAAu8zBwAAA2qElEQVR4AezBQQ4by5LAQFLw/a/MectcF')).toBeTruthy;
336
- expect(pseudonym).toBe(DEMO_PSEUDONYM);
337
+ )
338
+ .then( data => {
339
+ expect( data.qr_code.startsWith(' data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAiQAAAIkCAYAAAAu8zBwAAA2qElEQVR4AezBQQ4by5LAQFLw/a/MectcF')).toBeTruthy;
340
+ expect( data.pseudonym ).toBe(DEMO_PSEUDONYM);
341
+ expect( data.qr_data ).toBe( newData );
342
+ })
343
+ .catch( err => { process.stderr.write( JSON.stringify( err ))})
337
344
  })
338
345
 
339
346
  test('should make QR code when given lab ps', async () => {
@@ -350,8 +357,6 @@ describe('QR Code generator', () => {
350
357
  newData,
351
358
  RXTESTAPI
352
359
  );
353
-
354
- //expect( qr_code.length ).toBe( 25750 );
355
360
  expect(qr_code.startsWith(' data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAiQAAAIkCAYAAAAu8zBwAAA2qElEQVR4AezBQQ4by5LAQFLw/a/MectcF')).toBeTruthy;
356
361
  //console.log(qr_code.length);
357
362
  expect(pseudonym).toBe( lab_ps );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rxome-generator",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Generates QR codes containing medical information for use with RxOME database.",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
@@ -25,6 +25,7 @@
25
25
  ],
26
26
  "author": "Tom Kamphans",
27
27
  "license": "MIT",
28
+ "license" : "SEE LICENSE IN README.md",
28
29
  "bugs": {
29
30
  "url": "https://github.com/GeneTalkTK/rxome-qrcode-generator/issues"
30
31
  },
package/rxcode CHANGED
@@ -46,6 +46,7 @@ Output: prints the given or new pseudonym.`)
46
46
  .option('-e, --email <email>', 'Laboratory email (default: input file, metaData.submittedBy)')
47
47
  .option('-S, --snake', 'Read payload formatted in snake_case (default: camelCase)')
48
48
  .option('-t, --test', 'Use test API instead of production API')
49
+ .option('-L, --localhost', 'Connect to localhost API')
49
50
  .option('-D, --debug', 'Some output for debugging')
50
51
  .action( async (inputfile, options) => {
51
52
  const rawdata = FS.readFileSync( inputfile || '/dev/stdin' );
@@ -57,7 +58,9 @@ Output: prints the given or new pseudonym.`)
57
58
  options.created && (qrData.metaData.created = options.created);
58
59
  options.email && (qrData.metaData.submittedBy = options.email);
59
60
  options.pseudonym && (qrData.metaData.pseudonym = options.pseudonym);
60
- const qrApi = options.test ? RxAPI.TESTAPI : RxAPI.API;
61
+ let qrApi = RxAPI.API;
62
+ options.test && (qrApi = RxAPI.TESTAPI);
63
+ options.localhost && (qrApi = 'http://localhost:3000/');
61
64
 
62
65
  ('credentials' in qrData) || (qrData.credentials = {});
63
66
  if ( options.key ) {
@@ -91,7 +94,7 @@ program.command('convert')
91
94
  .alias('c')
92
95
  .description('convert case style of keys in JSON files from snake_case to camelCase (and vice versa)')
93
96
  .argument('[input file]', 'Input JSON file (default: STDIN)')
94
- .option('-o, --output <output file>', 'Output JSON file (default: stdout)', '/dev/stdout')
97
+ .option('-o, --output <output file>', 'Output JSON file (default: stdout)')
95
98
  .option('-s, --snake', 'Convert to snake_case (default: convert to camelCase')
96
99
  .action( async (inputfile, options) => {
97
100
  const data = JSON.parse(FS.readFileSync( inputfile || '/dev/stdin' ));
@@ -101,7 +104,11 @@ program.command('convert')
101
104
  } else {
102
105
  newData = Coder.convertToCamelCase( data );
103
106
  }
104
- FS.writeFileSync( options.output, JSON.stringify( newData ))
107
+ if ( options.output ) {
108
+ const stream = FS.createWriteStream( options.output );
109
+ process.stdout.write = stream.write.bind( stream );
110
+ }
111
+ process.stdout.write( JSON.stringify( newData ) );
105
112
  });
106
113
 
107
114
 
@@ -109,7 +116,7 @@ program.command('preprocess')
109
116
  .alias('p')
110
117
  .description('perform preprocessing steps')
111
118
  .argument('[input file]', 'Input JSON file (default: STDIN)')
112
- .option('-o, --output <output file>', 'Output JSON file (default: stdout)', '/dev/stdout')
119
+ .option('-o, --output <output file>', 'Output JSON file (default: stdout)')
113
120
  .option('-C, --case', 'Apply case style converter from snake_case to camelCase')
114
121
  .option('-w, --whitelist', 'Apply whitelist filtering (remove unnecessary sections)')
115
122
  .option('-s, --sanitize', 'A pply sanitizing step (remove common mistakes)')
@@ -120,7 +127,11 @@ program.command('preprocess')
120
127
  options.whitelist && (data = Coder.whiteListPhenoPacket( data ));
121
128
  options.sanitize && (data = Coder.sanitizePhenoPacket( data ));
122
129
  options.compress && (data = Coder.compressPhenoPacket( data ));
123
- FS.writeFileSync( options.output, JSON.stringify( data ))
130
+ if ( options.output ) {
131
+ const stream = FS.createWriteStream( options.output );
132
+ process.stdout.write = stream.write.bind( stream );
133
+ }
134
+ process.stdout.write( JSON.stringify( data ) );
124
135
  })
125
136
 
126
137
 
@@ -149,10 +160,10 @@ program.command('apikeys')
149
160
  program.command('ping')
150
161
  .summary('Ping API/check API credentials')
151
162
  .alias('P')
152
- .argument('id', 'API access key ID (default: rxome)')
163
+ .argument('[id]', 'API access key ID (default: rxome)')
153
164
  .argument('key', 'API access key')
154
165
  .option('-t, --test', 'Connect to test API')
155
- .option('-l, --localhost', 'Connect to localhost API')
166
+ .option('-L, --localhost', 'Connect to localhost API')
156
167
  .option('-D, --debug', 'Some output for debugging')
157
168
  .action( async (id, key, options) => {
158
169
  let qrApi = RxAPI.API;
@@ -163,15 +174,14 @@ program.command('ping')
163
174
  key: key,
164
175
  user: 'info@rxome.net'
165
176
  }
166
-
167
177
  options.debug && console.log( "Sending " , credentials , " to ", qrApi );
168
178
 
169
179
  Coder.fetchKey( credentials, 'HANSMOTKAMP', qrApi, options.debug )
170
- .then( result => {console.log( (result?.key && result?.pseudonym === '') ? 'OK' : 'An error occured')} )
180
+ .then( result => { console.log('[RESULT] ', result);console.log( (result?.key && result?.pseudonym === 'HANSMOTKAMP') ? 'OK' : 'An error occured')} )
171
181
  .catch( error => {
172
- console.log( error.code );
182
+ console.log( '[Error] ', error.code );
173
183
  if (error.response) { // status !== 2xx
174
- options.debug && console.log('\nResp. Data:\n', error.response.data);
184
+ // options.debug && console.log('\nResp. Data:\n', error.response.data);
175
185
  options.debug && console.log('\nResp. Headers:\n', error.response.headers);
176
186
  console.log('\nError ', error.response.status);
177
187
  } else if (error.request) { // request send, but no response
@@ -183,11 +193,11 @@ program.command('ping')
183
193
  });
184
194
 
185
195
 
186
- program.command('encode')
196
+ program.command('encrypt')
187
197
  .alias('e')
188
198
  .description('encrypt message (just for testing)')
189
199
  .argument('[input file]', 'Input text file (default: STDIN)')
190
- .option('-o, --output <output file>', 'Output file (default: stdout)', '/dev/stdout')
200
+ .option('-o, --output <output file>', 'Output file (default: stdout)')
191
201
  .option('-k, --keyfile <keyfile>', 'name of public data encryption key file (not to be confused with the API access key!)', 'rxome.public.key')
192
202
  .option('-j, --json', 'treat inputfile as json {key: ..., message: ...}', false)
193
203
  .action( async (inputfile, options) => {
@@ -203,15 +213,19 @@ program.command('encode')
203
213
  message = data.toString();
204
214
  }
205
215
  const cipher = await Coder.encode( key, message );
206
- FS.writeFileSync( options.output, cipher );
216
+ if ( options.output ) {
217
+ const stream = FS.createWriteStream( options.output );
218
+ process.stdout.write = stream.write.bind( stream );
219
+ }
220
+ process.stdout.write( cipher );
207
221
  });
208
222
 
209
223
 
210
- program.command('decode')
224
+ program.command('decrypt')
211
225
  .alias('d')
212
- .description('decode coded message or medical data')
226
+ .description('decrypt coded message or medical data')
213
227
  .argument('[input file]', 'Input cipher file (default: STDIN)')
214
- .option('-o, --output <output file>', 'Output file (default: stdout)', '/dev/stdout')
228
+ .option('-o, --output <output file>', 'Output file (default: stdout)')
215
229
  .option('-k, --keyfile <keyfile>', 'name of private data encryption key file', 'rxome.private.key')
216
230
  .option('-j, --json', 'treat inputfile as json {key: ..., cipher: ...}', false)
217
231
  .option('-c, --complete', 'also unpack PhenoPacket', false )
@@ -242,12 +256,16 @@ program.command('decode')
242
256
  } else {
243
257
  result = data;
244
258
  }
245
- FS.writeFileSync( options.output, result );
246
-
259
+ if ( options.output ) {
260
+ const stream = FS.createWriteStream( options.output );
261
+ process.stdout.write = stream.write.bind( stream );
262
+ }
263
+ process.stdout.write( result );
247
264
  });
248
265
 
249
266
 
250
- program.command('rxome-keys')
267
+ program.command('data-keys')
268
+ .alias('K')
251
269
  .description('generate key pair for data encryption (see -e, -d; just for testing)')
252
270
  .argument('[file prefix]', 'Prefix for file names (default: rxome)')
253
271
  .option('-d, --directory <dir>', 'output directory', '.')
@@ -260,7 +278,7 @@ program.command('pheno2proto')
260
278
  .alias('E')
261
279
  .description('encode PhenoPacket to protobuf (just for testing)')
262
280
  .argument('[input file]', 'Input text file (default: STDIN)')
263
- .option('-o, --output <output file>', 'Output file (default: stdout)', '/dev/stdout')
281
+ .option('-o, --output <output file>', 'Output file (default: stdout)')
264
282
  .option('-b, --base64', 'Write output base64 encoded')
265
283
  .option('-W, --whitelist', 'Preprocess: whitelist', false )
266
284
  .option('-S, --sanitize', 'Preprocess: sanitize', false )
@@ -273,7 +291,11 @@ program.command('pheno2proto')
273
291
  const compressedMedical = options.compress ? Coder.compressPhenoPacket( sanitizedMedical ) : sanitizedMedical;
274
292
  const protobufMedical = Coder.encodePhenoPacket( compressedMedical );
275
293
  const outData = (options.base64 ? RxAPI.bufferToBase64( protobufMedical ) : protobufMedical );
276
- FS.writeFileSync( options.output, outData );
294
+ if ( options.output ) {
295
+ const stream = FS.createWriteStream( options.output );
296
+ process.stdout.write = stream.write.bind( stream );
297
+ }
298
+ process.stdout.write( outData );
277
299
  });
278
300
 
279
301
 
@@ -281,7 +303,7 @@ program.command('proto2pheno')
281
303
  .alias('D')
282
304
  .description('decode protobuf to PhenoPacket (just for testing)')
283
305
  .argument('[input file]', 'Input cipher file (default: STDIN)')
284
- .option('-o, --output <output file>', 'Output file (default: stdout)', '/dev/stdout')
306
+ .option('-o, --output <output file>', 'Output file (default: stdout)')
285
307
  .option('-b, --base64', 'Read input base64 encoded')
286
308
  .option('-p, --pretty', 'Pretty print output}')
287
309
 
@@ -289,7 +311,11 @@ program.command('proto2pheno')
289
311
  const input = FS.readFileSync( inputfile || '/dev/stdin' );
290
312
  const data = ( options.base64 ? Uint8Array.from([...atob(input) ].map( c => c.charCodeAt(0))): input)
291
313
  const pheno = Coder.decodePhenoPacket(data);
292
- FS.writeFileSync( options.output, JSON.stringify(pheno, ' ', options.pretty ? 2 : 0) );
314
+ if ( options.output ) {
315
+ const stream = FS.createWriteStream( options.output );
316
+ process.stdout.write = stream.write.bind( stream );
317
+ }
318
+ process.stdout.write( JSON.stringify(pheno, ' ', options.pretty ? 2 : 0) );
293
319
  });
294
320
 
295
321
 
@@ -391,8 +417,8 @@ program.command('statistics')
391
417
  // return Coder.decode(privateKey, cipher)
392
418
  // })
393
419
  // .then(clear => {console.log( JSON.parse(clear) )})
394
-
395
- // console.log( JSON.stringify( Coder.fetchKey( DEMO_CREDENTIALS, '', RxAPI.TESTAPI )));
420
+ // .action( async() => {
421
+ // console.log( JSON.stringify( await Coder.fetchDemoPrivateKey( DEMO_CREDENTIALS, '', RxAPI.TESTAPI, true )));
396
422
 
397
423
  // });
398
424
 
package/rxcode.test.js CHANGED
@@ -3,22 +3,27 @@ const FS = require( 'fs' );
3
3
  //const { default: test } = require("node:test");
4
4
  const Coder = require( './lib/rxome-generator' );
5
5
 
6
+ DEMO_TEXT = 'answer to life the universe and everything'
7
+
6
8
  DEMO_CIPHER = `
7
9
  -----BEGIN PGP MESSAGE-----
8
10
 
9
- wV4Dhx/ATfJT0nQSAQdAQB3UcIAE5hMbtWJLiaDIrIiuNBRYzYPPGe4Ry40A
10
- oCkw9Tf0OlDdDEqrCfGWseuYgdbgpqUSYJMTgmnmj8S2KxqU30eW10fu+lzt
11
- 0a8vvetS0loB8ktDgqeRfFeusC8L5vBVD6r5PixaZYWjhcaL1ZrcEl211ArW
12
- Qvk3mk17r9xwp26rVXk5NX/feTNXr19907RdPM1oT7zWetTpwx8ow6KZZrGB
13
- ZcabBZ5ti/o=
14
- =6tRv
11
+ wV4DwTe9/0b1zzgSAQdAxe4Phva3n19MInlPhQS4OxG78y+3mTsNHVfsk5OF
12
+ nGAwld5yaBCzLoudwGLQ17qIkABl9rhONf8VJMNoTOZOf8nPoouCKdXxktv7
13
+ dG1wvV2s0lsBvUBUmaOzix1hEF6YeUr7mfc+MBBt/2gfoyT4Kujgrg25YoZ6
14
+ qUgqga2eSZ6O+OhyjuFo3rZVXl1MFY6lfu+X+i4cCE2VWiAQOwVNnqFdY9FF
15
+ uOPuzhz7UstK
16
+ =KKxC
15
17
  -----END PGP MESSAGE-----
16
18
  `
17
19
 
18
20
  const PRIVATE_KEY = Coder.DEMO_PRIVATE_KEY;
19
21
  const PUBLIC_KEY = Coder.DEMO_PUBLIC_KEY;
20
22
 
23
+ jest.setTimeout(70000)
24
+
21
25
  async function execCmd( cmd ) {
26
+ // process.stderr.write( `Executing ${cmd}` )
22
27
  const exec = require('child_process').exec;
23
28
  return new Promise((resolve, reject) => {
24
29
  exec(cmd, (error, stdout, stderr) => {
@@ -36,41 +41,130 @@ async function execCmd( cmd ) {
36
41
  }
37
42
 
38
43
  describe('CmdLine generate', () => {
39
- it.skip('generates a qr code from demo data', () => {
40
- FS.rm( 'zzz.png' );
41
- execCmd( 'rxcode g -t -o zzz.png demos/demo_data_full.json' )
42
- .then( result => {
43
- console.log( result.stdout )
44
- console.log( result.stderr )
45
- });
44
+ test('generates a qr code from demo data', () => {
45
+ FS.rmSync( '__TESTSUITE_IMG.png' );
46
+ execCmd( 'rxcode g -t -o __TESTSUITE_IMG.png demos/demo_data_full.json' )
47
+ // execCmd( 'rxcode g -L -o __TESTSUITE_IMG.png demos/demo_data_full.json' )
48
+ .then( res => {
49
+ expect( res.error ).toBeNull();
50
+ expect( res.stdout ).toBe('HANSMOTKAMP\n');
51
+ expect( res.stderr ).toBe('');
52
+ expect( FS.existsSync( '__TESTSUITE_IMG.png' )).toBeTruthy();
53
+ const fileStats = FS.statSync( '__TESTSUITE_IMG.png' );
54
+ expect( Math.floor( fileStats.size / 100 )-215).toBeLessThan( 4 );
55
+ })
56
+ .catch( err => { process.stderr.write( JSON.stringify( err ))})
46
57
  });
47
58
  });
48
59
 
49
60
 
50
- // describe('generate keys', () => {
51
- // test.skip('creates two files', async () => {
52
- // const dir = '.';
53
- // const ex = await execCmd( 'node rxcode.js generate testsuite foo@bar.baz ' );
54
- // const publicKeyFile = `${dir}/testsuite.public.key`;
55
- // const privateKeyFile = `${dir}/testsuite.private.key`;
56
- // expect( ex.error ).toBeNull();
57
- // expect( ex.stdout ).toBe('');
58
- // expect( ex.stderr ).toBe('');
59
- // expect( FS.existsSync( publicKeyFile )).toBeTruthy();
60
- // expect( FS.existsSync( privateKeyFile )).toBeTruthy();
61
- // const privStats = FS.statSync( privateKeyFile );
62
- // expect( privStats.size ).toBe( 850 );
63
- // const pubStats = FS.statSync( publicKeyFile );
64
- // expect( pubStats.size ).toBe( 624 );
65
- // const privateKey = FS.readFileSync( privateKeyFile, { encoding: 'utf8' }, err => { console.log(err) } );
66
- // expect( privateKey ).toContain( 'BEGIN PGP PRIVATE KEY BLOCK' );
67
- // const publicKey = FS.readFileSync( publicKeyFile, { encoding: 'utf8' }, err => { console.log(err) } );
68
- // expect( publicKey ).toContain( 'BEGIN PGP PUBLIC KEY BLOCK' );
69
- // })
61
+ describe('generate keys', () => {
62
+ test('creates two files', async () => {
63
+ const dir = '.';
64
+ const ex = await execCmd( 'rxcode K __TESTSUITE' );
65
+ const publicKeyFile = `${dir}/__TESTSUITE.public.key`;
66
+ const privateKeyFile = `${dir}/__TESTSUITE.private.key`;
67
+ expect( ex.error ).toBeNull();
68
+ expect( ex.stdout ).toBe('');
69
+ expect( ex.stderr ).toBe('');
70
+ expect( FS.existsSync( publicKeyFile )).toBeTruthy();
71
+ expect( FS.existsSync( privateKeyFile )).toBeTruthy();
72
+ const privStats = FS.statSync( privateKeyFile );
73
+ expect( Math.floor( privStats.size / 100 )).toBe( 8 );
74
+ const pubStats = FS.statSync( publicKeyFile );
75
+ expect( Math.floor( pubStats.size / 10 )).toBe( 62 );
76
+ const privateKey = FS.readFileSync( privateKeyFile, { encoding: 'utf8' }, err => { console.log(err) } );
77
+ expect( privateKey ).toContain( 'BEGIN PGP PRIVATE KEY BLOCK' );
78
+ const publicKey = FS.readFileSync( publicKeyFile, { encoding: 'utf8' }, err => { console.log(err) } );
79
+ expect( publicKey ).toContain( 'BEGIN PGP PUBLIC KEY BLOCK' );
80
+ })
70
81
 
71
- // });
82
+ });
72
83
 
73
- // //describe('encode', () => {
84
+ describe('Cmdline encode', () => {
85
+ test('encodes json input', async() => {
86
+ execCmd( './rxcode e -j ./demos/demo_encrypt.json > __TESTSUITE_FILE_1' )
87
+ .then( res => {
88
+ expect( res.error ).toBeNull();
89
+ expect( res.stdout ).toBe('');
90
+ expect( res.stderr ).toBe('');
91
+ expect( FS.existsSync( '__TESTSUITE_FILE_1' )).toBeTruthy();
92
+ const fileStats = FS.statSync( '__TESTSUITE_FILE_1' );
93
+ expect( Math.floor( fileStats.size / 100 )).toBe( 3 );
94
+ const fileContent = FS.readFileSync( '__TESTSUITE_FILE_1', { encoding: 'utf8' }, err => { process.stderr.write(err) } );
95
+ expect( fileContent ).toContain( '-----BEGIN PGP MESSAGE-----' );
96
+ //FS.rmSync( '__TESTSUITE_FILE_1')
97
+ })
98
+ .catch( err => { process.stderr.write( JSON.stringify( err ))})
99
+ })
100
+
101
+ test('decodes json input', async() => {
102
+ execCmd( './rxcode d -j ./demos/demo_decrypt.json > __TESTSUITE_FILE_2' )
103
+ .then( res => {
104
+ expect( res.error ).toBeNull();
105
+ expect( res.stdout ).toBe('');
106
+ expect( res.stderr ).toBe('');
107
+ expect( FS.existsSync( '__TESTSUITE_FILE_2' )).toBeTruthy();
108
+ const fileStats = FS.statSync( '__TESTSUITE_FILE_2' );
109
+ expect( fileStats.size ).toBe( 42 );
110
+ const fileContent = FS.readFileSync( '__TESTSUITE_FILE_2', { encoding: 'utf8' }, err => { process.stderr.write(err) } );
111
+ expect( fileContent ).toContain( DEMO_TEXT );
112
+ //FS.rmSync( '__TESTSUITE_FILE_1')
113
+ })
114
+ .catch( err => { process.stderr.write( JSON.stringify( err ))})
115
+ })
116
+
117
+ test('encodes and decodes a text file', async() => {
118
+ FS.writeFileSync( '__TESTSUITE_FILE_3', DEMO_TEXT );
119
+ execCmd( './rxcode e -k ./demos/demo.public.key -o __TESTSUITE_FILE_4 __TESTSUITE_FILE_3' )
120
+ .then( res => {
121
+ expect( res.error ).toBeNull();
122
+ expect( res.stdout ).toBe('');
123
+ expect( res.stderr ).toBe('');
124
+ expect( FS.existsSync( '__TESTSUITE_FILE_4' )).toBeTruthy();
125
+
126
+ execCmd( './rxcode d -k ./demos/demo.private.key -o __TESTSUITE_FILE_5 __TESTSUITE_FILE_4' )
127
+ .then( res => {
128
+ expect( res.error ).toBeNull();
129
+ expect( res.stdout ).toBe('');
130
+ expect( res.stderr ).toBe('');
131
+ expect( FS.existsSync( '__TESTSUITE_FILE_5' )).toBeTruthy();
132
+ const fileStats = FS.statSync( '__TESTSUITE_FILE_5' );
133
+ expect( fileStats.size ).toBe( 42 );
134
+ const fileContent = FS.readFileSync( '__TESTSUITE_FILE_5', { encoding: 'utf8' } );
135
+ expect( fileContent ).toContain( DEMO_TEXT );
136
+ //FS.rmSync( '__TESTSUITE_FILE_1')
137
+ })
138
+ //.catch( err => { process.stderr.write( JSON.stringify( err ))})
139
+ })
140
+ //.catch( err => { process.stderr.write( JSON.stringify( err ))})
141
+ }, 100000)
142
+
143
+ test('encodes and decodes from stdin to stdout file', async() => {
144
+ FS.writeFileSync( '__TESTSUITE_FILE_6', DEMO_TEXT );
145
+ execCmd( './rxcode e -k ./demos/demo.public.key < __TESTSUITE_FILE_6 > __TESTSUITE_FILE_7' )
146
+ .then( res => {
147
+ expect( res.error ).toBeNull();
148
+ expect( res.stdout ).toBe('');
149
+ expect( res.stderr ).toBe('');
150
+ expect( FS.existsSync( '__TESTSUITE_FILE_7' )).toBeTruthy();
151
+
152
+ execCmd( './rxcode d -k ./demos/demo.private.key < __TESTSUITE_FILE_7 > __TESTSUITE_FILE_8' )
153
+ .then( res => {
154
+ expect( res.error ).toBeNull();
155
+ expect( res.stdout ).toBe('');
156
+ expect( res.stderr ).toBe('');
157
+ expect( FS.existsSync( '__TESTSUITE_FILE_8' )).toBeTruthy();
158
+ const fileStats = FS.statSync( '__TESTSUITE_FILE_8' );
159
+ expect( fileStats.size ).toBe( 42 );
160
+ const fileContent = FS.readFileSync( '__TESTSUITE_FILE_8', { encoding: 'utf8' } );
161
+ expect( fileContent ).toContain( DEMO_TEXT );
162
+ //FS.rmSync( '__TESTSUITE_FILE_1')
163
+ })
164
+ //.catch( err => { process.stderr.write( JSON.stringify( err ))})
165
+ });
166
+ })
167
+ });
74
168
 
75
169
  // //});
76
170
  // describe('CmdLine help', async () => {
@@ -95,10 +189,4 @@ rxcode d -j rxome.decrypt.json
95
189
  rxcode d -j rxome.decrypt.json
96
190
  rxcode d -j < rxome.decrypt
97
191
 
98
- rxcode P test Cs67c7aXYhZQbjU2W/4q6sBu/oIQ8zONSBURUH8g2wQ=
99
- OK
100
- rxcode P mgz QhcoRruGBVP39XCh8BujCE+q42qCRy/tu2CQ4YmRBgg=
101
- OK
102
- rxcode P rxome NamaTB+xwDFxtkQyBBkjRr5GEaXNtCw/G4qydnhQk5Y=
103
- OK
104
192
  */
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2022 Tom Kamphans, GeneTalk GmbH
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -1 +0,0 @@
1
- {"key":"\n-----BEGIN PGP PRIVATE KEY BLOCK-----\n\nxYYEYmgyNxYJKwYBBAHaRw8BAQdA9l4CTUgpfKMpdhmIsu1+mFZh96Mch+5w\nZnd3+fvIoz7+CQMI2zrQtpZGqZvgA0VIaMqedg6MCtUWVZR7Eb6FOhizqvo/\ngNeBu4IvoHEqv8NECSfy10WFSMuDN2D4dm9E21VBcpdryNo5WOTE2qwUX7sp\ntc0UZm9vYmFyIDxmb29AYmFyLmJhej7CjAQQFgoAHQUCYmgyNwQLCQcIAxUI\nCgQWAAIBAhkBAhsDAh4BACEJELz7rrggWl5DFiEExPymzQI26MvyIw/1vPuu\nuCBaXkOMogEAhQlj7f+riRrlpFtmL13//BHZJdAy8hNO4AUOkNjxEzcBALqS\nrEoMvCeXPjju60hBzyb0rzmzWHyUKQE1R4mgJzwEx4sEYmgyNxIKKwYBBAGX\nVQEFAQEHQNVKEkYa4QPXrI5553FfN1Uio4fsorJoIya8EivEbLIyAwEIB/4J\nAwhP5xKSOD3XVODBWc+ZZVn9sJyvyQeyZWZ0em15ixtmxO3BF+1AzNj/1bcx\nx/BsSYyX6tnEh/AjMNCZV4Cmvp+pBie+x+BBN6zJRHM837PYwngEGBYIAAkF\nAmJoMjcCGwwAIQkQvPuuuCBaXkMWIQTE/KbNAjboy/IjD/W8+664IFpeQyUr\nAP0VhT+Xa4lt2EvapPlXeEsdTyI5gx/87pSw6Cs21GyUwwEApgU2q4qfjsFC\nyOcQrcylWRQ4NvdK9SqsEomwxTwHkQQ=\n=YCih\n-----END PGP PRIVATE KEY BLOCK-----\n","cipher":"\n-----BEGIN PGP MESSAGE-----\n\nwV4Dhx/ATfJT0nQSAQdAkPgYRHClE5eUyl58gXBQrmZoiTtkvrOZLjnaLvFq\ncicw/28IAdW/0wuYtbd0CQf6gFMMLVmF+4Qx6OeQHehI8t+5mi7Keve1eaJp\nj2WL1TiN0lsBBbYvVdInUt3VbiywTxa+sMvfT+0crmTtsfJ6FrbD7nR22L/v\n9RgUEaY6cDrNu+PzcKGVYQj/WCqhlFflcAn+/cfcu0mRkllmbghN2uYbymff\n4M44RC1yZ0j1\n=x+N1\n-----END PGP MESSAGE-----\n"}
@@ -1 +0,0 @@
1
- {"key":"\n-----BEGIN PGP PRIVATE KEY BLOCK-----\n\nxYYEYmgyNxYJKwYBBAHaRw8BAQdA9l4CTUgpfKMpdhmIsu1+mFZh96Mch+5w\nZnd3+fvIoz7+CQMI2zrQtpZGqZvgA0VIaMqedg6MCtUWVZR7Eb6FOhizqvo/\ngNeBu4IvoHEqv8NECSfy10WFSMuDN2D4dm9E21VBcpdryNo5WOTE2qwUX7sp\ntc0UZm9vYmFyIDxmb29AYmFyLmJhej7CjAQQFgoAHQUCYmgyNwQLCQcIAxUI\nCgQWAAIBAhkBAhsDAh4BACEJELz7rrggWl5DFiEExPymzQI26MvyIw/1vPuu\nuCBaXkOMogEAhQlj7f+riRrlpFtmL13//BHZJdAy8hNO4AUOkNjxEzcBALqS\nrEoMvCeXPjju60hBzyb0rzmzWHyUKQE1R4mgJzwEx4sEYmgyNxIKKwYBBAGX\nVQEFAQEHQNVKEkYa4QPXrI5553FfN1Uio4fsorJoIya8EivEbLIyAwEIB/4J\nAwhP5xKSOD3XVODBWc+ZZVn9sJyvyQeyZWZ0em15ixtmxO3BF+1AzNj/1bcx\nx/BsSYyX6tnEh/AjMNCZV4Cmvp+pBie+x+BBN6zJRHM837PYwngEGBYIAAkF\nAmJoMjcCGwwAIQkQvPuuuCBaXkMWIQTE/KbNAjboy/IjD/W8+664IFpeQyUr\nAP0VhT+Xa4lt2EvapPlXeEsdTyI5gx/87pSw6Cs21GyUwwEApgU2q4qfjsFC\nyOcQrcylWRQ4NvdK9SqsEomwxTwHkQQ=\n=YCih\n-----END PGP PRIVATE KEY BLOCK-----\n","message":"answer to life the universe and everything"}