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/- +1 -0
- package/README.md +9 -2
- package/demos/demo.private.key +17 -0
- package/demos/demo.public.key +13 -0
- package/demos/demo_data_full.json +4 -3
- package/demos/demo_data_full_compressed.json +4 -3
- package/demos/demo_decrypt.json +1 -0
- package/demos/demo_encrypt.json +1 -0
- package/lib/rxome-api-demo.js +4 -2
- package/lib/rxome-api.js +9 -3
- package/lib/rxome-api.test.js +7 -7
- package/lib/rxome-generator.test.js +28 -23
- package/package.json +2 -1
- package/rxcode +52 -26
- package/rxcode.test.js +129 -41
- package/LICENSE +0 -21
- package/demos/rxome.decrypt.json +0 -1
- package/demos/rxome.encrypt.json +0 -1
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
|
|
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": "
|
|
146
|
-
"keyId": "
|
|
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": "
|
|
73
|
-
"keyId": "
|
|
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"}
|
package/lib/rxome-api-demo.js
CHANGED
|
@@ -35,8 +35,10 @@ VBvfFVhJAPoDhf5yKxJ+oJV3ls8IyoBBAeMeAYFBrA8r89fKT0nFBA==
|
|
|
35
35
|
`
|
|
36
36
|
|
|
37
37
|
const R_ID = 'rxome';
|
|
38
|
-
const
|
|
39
|
-
const
|
|
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 = '
|
|
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,
|
package/lib/rxome-api.test.js
CHANGED
|
@@ -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( '
|
|
8
|
-
expect( FS.existsSync('
|
|
9
|
-
expect( FS.existsSync('
|
|
10
|
-
expect( FS.statSync('
|
|
11
|
-
expect( FS.statSync('
|
|
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('
|
|
16
|
-
const pubKey = RxAPI.unpack([...RxAPI.base64ToBuffer( FS.readFileSync('
|
|
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
|
|
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,
|
|
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,
|
|
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, '', '
|
|
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(
|
|
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,
|
|
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
|
|
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
|
|
292
|
-
url:
|
|
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,
|
|
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
|
|
333
|
+
//const { qr_code, pseudonym } = await
|
|
334
|
+
Coder.makeQR(
|
|
330
335
|
newData,
|
|
331
336
|
RXTESTAPI
|
|
332
|
-
)
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
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.
|
|
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
|
-
|
|
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)'
|
|
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
|
-
|
|
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)'
|
|
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
|
-
|
|
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('-
|
|
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('
|
|
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)'
|
|
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
|
-
|
|
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('
|
|
224
|
+
program.command('decrypt')
|
|
211
225
|
.alias('d')
|
|
212
|
-
.description('
|
|
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)'
|
|
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
|
-
|
|
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('
|
|
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)'
|
|
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
|
-
|
|
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)'
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
=
|
|
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
|
-
|
|
40
|
-
FS.
|
|
41
|
-
execCmd( 'rxcode g -t -o
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
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.
|
package/demos/rxome.decrypt.json
DELETED
|
@@ -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"}
|
package/demos/rxome.encrypt.json
DELETED
|
@@ -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"}
|