rxome-generator 1.0.3 → 1.0.4-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,257 @@
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
+ // Environment-aware fetch function
7
+ export async function getFetch() {
8
+ if (typeof window !== 'undefined') {
9
+ return window.fetch;
10
+ }
11
+ return (await import('node-fetch')).default;
12
+ }
13
+
14
+ const API = 'https://app.findme2care.de';
15
+ const TESTAPI = 'https://stage.findme2care.de';
16
+ const APIENTRY = 'api/v1';
17
+ const VSTR = 'API1.0'
18
+ const IS_DEMO = '_DEMO_PSEUDONYM_';
19
+
20
+ export { API, TESTAPI, APIENTRY, VSTR, IS_DEMO };
21
+
22
+ /************************************************************************************
23
+ * Helper functions
24
+ ************************************************************************************/
25
+
26
+ // have issues:
27
+ const base64ToBufferVintage = data => atob(data.toString());
28
+ //const bufferToBase64 = data => Buffer.from(data).toString('base64');
29
+
30
+ const unpack = (arr) => Uint8Array.from( arr.map( c => c.charCodeAt(0) ));
31
+
32
+ let readSigKey = name => { console.log("Error: not supported") }
33
+
34
+ const base64ToBuffer = enc => {
35
+ const len = Protobuf.util.base64.length(enc);
36
+ let buf = new Protobuf.util.Array( len );
37
+ Protobuf.util.base64.decode(enc, buf, 0);
38
+ return buf;
39
+ }
40
+
41
+ const bufferToBase64 = buf => {
42
+ return Protobuf.util.base64.encode(buf, 0, buf.length);
43
+ }
44
+
45
+ export { base64ToBuffer, bufferToBase64, unpack };
46
+
47
+ /************************************************************************************
48
+ * Functions for node.js only
49
+ ************************************************************************************/
50
+
51
+ // Node.js specific functions that require fs module
52
+ readSigKey = async name => {
53
+ try {
54
+ const FS = await import('fs');
55
+ if (!FS.existsSync( name )) {
56
+ throw 'Key file not found!';
57
+ }
58
+ return FS.readFileSync( name ).slice(0,44);
59
+ } catch (e) {
60
+ if (e instanceof Error && e.code !== "MODULE_NOT_FOUND") {
61
+ throw e;
62
+ }
63
+ throw new Error('fs module not available - cannot read key file');
64
+ }
65
+ }
66
+
67
+ export const generateApiKeys = async () => {
68
+ const privateKey = ED.utils.randomPrivateKey();
69
+ const publicKey = await ED.getPublicKey(privateKey);
70
+ return {
71
+ privateKey: privateKey,
72
+ publicKey: publicKey
73
+ }
74
+ }
75
+
76
+ export const writeApiKeys = async (name = 'rxome', dir = '.') => {
77
+ try {
78
+ const FS = await import('fs');
79
+ const key = await generateApiKeys();
80
+ await Promise.all([
81
+ FS.writeFile( `${dir}/${name}.private.apikey`, bufferToBase64( key.privateKey ), { mode: 0o600 }, err => { if (err) throw err; } ),
82
+ FS.writeFile( `${dir}/${name}.public.apikey`, bufferToBase64( key.publicKey ), { mode: 0o600 }, err => { if (err) throw err; } )
83
+ ]);
84
+ } catch (e) {
85
+ if (e instanceof Error && e.code !== "MODULE_NOT_FOUND") {
86
+ throw e;
87
+ }
88
+ throw new Error('fs module not available - cannot write API keys');
89
+ }
90
+ }
91
+
92
+ export { readSigKey };
93
+
94
+ /************************************************************************************/
95
+
96
+ export const signData = async( keyId, user, keyB64, created, debug = false ) => {
97
+ const message = `x-date: ${created}\nx-rxome-user: ${user}`
98
+ const messageUi8 = unpack( Array.from(message) );
99
+
100
+ const key = unpack( [...base64ToBufferVintage(keyB64)] );
101
+ debug && console.log('Base 64 key: ', keyB64);
102
+ debug && console.log('Binary key: ', key, " Key length: ", key.length);
103
+
104
+ const signature = await ED.sign( messageUi8, key);
105
+ const sigB64 = bufferToBase64( signature );
106
+ const auth=`Signature keyId="${keyId}",algorithm="ed25519",headers="x-date x-rxome-user",signature="${sigB64}",created="${created}"`
107
+ debug && console.log('Auth string: ', auth);
108
+
109
+ return auth;
110
+ }
111
+
112
+ export const fetchData = async ( url, credentials, pseudonym = '', debug = false ) => {
113
+ debug && console.log( 'Fetching from', url )
114
+
115
+ const created = Date.now();
116
+ const keyId = credentials.keyId || "rxome";
117
+ const user = credentials.user || `${keyId}@rxome.net`;
118
+ const keyB64 = credentials.key || await readSigKey( process.cwd()+'/'+credentials.keyFile );
119
+
120
+ const auth = await signData( keyId, user, keyB64, created, debug );
121
+
122
+ // Build URL with query parameters
123
+ const urlParams = new URLSearchParams({
124
+ pslab: !!pseudonym.trim(),
125
+ demo: pseudonym === IS_DEMO
126
+ });
127
+ const fullUrl = `${url}?${urlParams}`;
128
+
129
+ // Create AbortController for timeout
130
+ const controller = new AbortController();
131
+ const timeoutId = setTimeout(() => controller.abort(), 5000);
132
+
133
+ const fetch = await getFetch();
134
+ return fetch(fullUrl, {
135
+ method: 'GET',
136
+ headers: {
137
+ Authorization: auth,
138
+ 'x-date': created,
139
+ 'x-rxome-user': user
140
+ },
141
+ signal: controller.signal
142
+ })
143
+ .then(async response => {
144
+ clearTimeout(timeoutId);
145
+ if (!response.ok) {
146
+ let errorData = null;
147
+ try {
148
+ errorData = await response.json();
149
+ } catch (e) {
150
+ // If response can't be parsed as JSON, use default error
151
+ }
152
+
153
+ const error = new Error(`HTTP error! status: ${response.status}`);
154
+ error.response = {
155
+ status: response.status,
156
+ statusText: response.statusText,
157
+ headers: response.headers,
158
+ data: errorData
159
+ };
160
+ throw error;
161
+ }
162
+ return response.json();
163
+ })
164
+ .then(data => {
165
+ debug && console.log( "Result Data= ", data );
166
+ return data;
167
+ })
168
+ .catch(error => {
169
+ clearTimeout(timeoutId);
170
+ if (error.name === 'AbortError') {
171
+ const timeoutError = new Error('Request timeout');
172
+ timeoutError.response = {
173
+ status: 408,
174
+ statusText: 'Request Timeout',
175
+ data: { message: 'Request timeout' }
176
+ };
177
+ throw timeoutError;
178
+ }
179
+ throw error;
180
+ })
181
+ }
182
+
183
+ export const pushData = async ( url, credentials, msg, debug = false ) => {
184
+ debug && console.log( 'Pushing to ', url )
185
+ console.log( 'Pushing to ', url )
186
+
187
+ const created = Date.now();
188
+ const keyId = credentials.keyId || "rxome";
189
+ const user = credentials.user || `${keyId}@rxome.net`;
190
+ const keyB64 = credentials.key || await readSigKey( process.cwd()+'/'+credentials.keyFile );
191
+
192
+ const auth = await signData( keyId, user, keyB64, created, debug );
193
+
194
+ // Create AbortController for timeout
195
+ const controller = new AbortController();
196
+ const timeoutId = setTimeout(() => controller.abort(), 5000);
197
+
198
+ const fetch = await getFetch();
199
+ return fetch(url, {
200
+ method: 'POST',
201
+ headers: {
202
+ 'Content-Type': 'application/json',
203
+ Authorization: auth,
204
+ 'x-date': created,
205
+ 'x-rxome-user': user
206
+ },
207
+ body: JSON.stringify(msg),
208
+ signal: controller.signal
209
+ })
210
+ .then(response => {
211
+ clearTimeout(timeoutId);
212
+ if (!response.ok) {
213
+ // Create error object similar to axios
214
+ const error = new Error(`HTTP error! status: ${response.status}`);
215
+ error.response = {
216
+ status: response.status,
217
+ statusText: response.statusText,
218
+ headers: response.headers,
219
+ data: null
220
+ };
221
+ throw error;
222
+ }
223
+ return response.json();
224
+ })
225
+ .then(data => {
226
+ debug && console.log( "Result Data= ", data );
227
+ return data;
228
+ })
229
+ .catch( (error) => {
230
+ clearTimeout(timeoutId);
231
+ let msg = null;
232
+ if (error.response) {
233
+ // Request made and server responded
234
+ if (error.response && error.response.data && error.response.data.message){
235
+ console.log( '[SendData Response Error] ', error.response.data.message );
236
+ msg = `Response Error: ${error.response.data.message}`;
237
+ console.log(error.response.data);
238
+ } else {
239
+ console.log( '[SendData Response Error] no message' );
240
+ msg = 'Unknown response error';
241
+ }
242
+ console.log(error.response.status);
243
+ console.log(error.response.headers);
244
+ } else if (error.name === 'AbortError') {
245
+ // Request was aborted (timeout)
246
+ console.log('[SendData Timeout Error]');
247
+ msg = 'Request timeout';
248
+ } else {
249
+ // Something happened in setting up the request that triggered an Error
250
+ console.log('[SendData Request Error] ', error.message);
251
+ msg = `Request Error: ${error.message}`;
252
+ }
253
+ const err = new Error( `Error sending data: ${msg}` );
254
+ console.log(err.name + ': ' + err.message);
255
+ throw err;
256
+ })
257
+ }
@@ -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;