@openziti/ziti-sdk-nodejs 0.6.0
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/.github/workflows/build.yml +220 -0
- package/.github/workflows/codeql-analysis.yml +71 -0
- package/.github/workflows/mattermost-ziti-webhook.yml +26 -0
- package/.gitmodules +4 -0
- package/.travis.yml-obsolete +99 -0
- package/CODE_OF_CONDUCT.md +17 -0
- package/CONTRIBUTING.md +6 -0
- package/LICENSE +201 -0
- package/README.md +155 -0
- package/appveyor.yml-obsolete +32 -0
- package/binding.gyp +227 -0
- package/lib/index.js +17 -0
- package/lib/ziti.js +40 -0
- package/package.json +56 -0
- package/scripts/build-appveyor.bat +198 -0
- package/scripts/install_node.sh +99 -0
- package/scripts/validate_tag.sh +24 -0
- package/src/Ziti_https_request.c +960 -0
- package/src/Ziti_https_request_data.c +250 -0
- package/src/Ziti_https_request_end.c +79 -0
- package/src/stack_traces.c +334 -0
- package/src/utils.c +108 -0
- package/src/utils.h +85 -0
- package/src/ziti-add-on.c +88 -0
- package/src/ziti-nodejs.h +209 -0
- package/src/ziti_close.c +79 -0
- package/src/ziti_dial.c +375 -0
- package/src/ziti_enroll.c +245 -0
- package/src/ziti_hello.c +52 -0
- package/src/ziti_init.c +315 -0
- package/src/ziti_service_available.c +222 -0
- package/src/ziti_shutdown.c +47 -0
- package/src/ziti_websocket_connect.c +458 -0
- package/src/ziti_websocket_write.c +235 -0
- package/src/ziti_write.c +223 -0
- package/tests/enroll-test.js +38 -0
- package/tests/hello.js +12 -0
- package/tests/https-test.js +206 -0
- package/tests/mattermost-test.js +124 -0
- package/tests/websocket-test.js +119 -0
- package/ziti.js +1 -0
- package/ziti.png +0 -0
package/src/ziti_dial.c
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2019-2020 Netfoundry, Inc.
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
#include "ziti-nodejs.h"
|
|
18
|
+
#include <string.h>
|
|
19
|
+
|
|
20
|
+
// An item that will be generated here and passed into the JavaScript on_data callback
|
|
21
|
+
typedef struct OnDataItem {
|
|
22
|
+
|
|
23
|
+
uint8_t *buf;
|
|
24
|
+
int len;
|
|
25
|
+
|
|
26
|
+
} OnDataItem;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* This function is responsible for calling the JavaScript 'connect' callback function
|
|
30
|
+
* that was specified when the ziti_dial(...) was called from JavaScript.
|
|
31
|
+
*/
|
|
32
|
+
static void CallJs_on_connect(napi_env env, napi_value js_cb, void* context, void* data) {
|
|
33
|
+
napi_status status;
|
|
34
|
+
|
|
35
|
+
// This parameter is not used.
|
|
36
|
+
(void) context;
|
|
37
|
+
|
|
38
|
+
// env and js_cb may both be NULL if Node.js is in its cleanup phase, and
|
|
39
|
+
// items are left over from earlier thread-safe calls from the worker thread.
|
|
40
|
+
// When env is NULL, we simply skip over the call into Javascript
|
|
41
|
+
if (env != NULL) {
|
|
42
|
+
napi_value undefined, js_conn;
|
|
43
|
+
|
|
44
|
+
ZITI_NODEJS_LOG(INFO, "data: %p", data);
|
|
45
|
+
|
|
46
|
+
// Convert the ziti_connection to a napi_value.
|
|
47
|
+
if (NULL != data) {
|
|
48
|
+
// Retrieve the ziti_connection from the item created by the worker thread.
|
|
49
|
+
ziti_connection conn = *(ziti_connection*)data;
|
|
50
|
+
status = napi_create_int64(env, (int64_t)conn, &js_conn);
|
|
51
|
+
if (status != napi_ok) {
|
|
52
|
+
napi_throw_error(env, NULL, "Unable to napi_create_int64");
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
status = napi_get_undefined(env, &js_conn) == napi_ok;
|
|
56
|
+
if (status != napi_ok) {
|
|
57
|
+
napi_throw_error(env, NULL, "Unable to napi_get_undefined (1)");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Retrieve the JavaScript `undefined` value so we can use it as the `this`
|
|
62
|
+
// value of the JavaScript function call.
|
|
63
|
+
status = napi_get_undefined(env, &undefined);
|
|
64
|
+
if (status != napi_ok) {
|
|
65
|
+
napi_throw_error(env, NULL, "Unable to napi_get_undefined (2)");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
ZITI_NODEJS_LOG(INFO, "calling JS callback...");
|
|
69
|
+
|
|
70
|
+
// Call the JavaScript function and pass it the ziti_connection
|
|
71
|
+
status = napi_call_function(
|
|
72
|
+
env,
|
|
73
|
+
undefined,
|
|
74
|
+
js_cb,
|
|
75
|
+
1,
|
|
76
|
+
&js_conn,
|
|
77
|
+
NULL
|
|
78
|
+
);
|
|
79
|
+
ZITI_NODEJS_LOG(INFO, "returned from JS callback...");
|
|
80
|
+
if (status != napi_ok) {
|
|
81
|
+
napi_throw_error(env, NULL, "Unable to napi_call_function");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* This function is responsible for calling the JavaScript 'data' callback function
|
|
89
|
+
* that was specified when the ziti_dial(...) was called from JavaScript.
|
|
90
|
+
*/
|
|
91
|
+
static void CallJs_on_data(napi_env env, napi_value js_cb, void* context, void* data) {
|
|
92
|
+
napi_status status;
|
|
93
|
+
|
|
94
|
+
// This parameter is not used.
|
|
95
|
+
(void) context;
|
|
96
|
+
|
|
97
|
+
// Retrieve the OnDataItem created by the worker thread.
|
|
98
|
+
OnDataItem* item = (OnDataItem*)data;
|
|
99
|
+
|
|
100
|
+
// env and js_cb may both be NULL if Node.js is in its cleanup phase, and
|
|
101
|
+
// items are left over from earlier thread-safe calls from the worker thread.
|
|
102
|
+
// When env is NULL, we simply skip over the call into Javascript and free the
|
|
103
|
+
// items.
|
|
104
|
+
if (env != NULL) {
|
|
105
|
+
napi_value undefined, js_buffer;
|
|
106
|
+
void* result_data;
|
|
107
|
+
|
|
108
|
+
// Convert the buffer to a napi_value.
|
|
109
|
+
status = napi_create_buffer_copy(env,
|
|
110
|
+
item->len,
|
|
111
|
+
(const void*)item->buf,
|
|
112
|
+
(void**)&result_data,
|
|
113
|
+
&js_buffer);
|
|
114
|
+
if (status != napi_ok) {
|
|
115
|
+
napi_throw_error(env, NULL, "Unable to napi_create_buffer_copy");
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Retrieve the JavaScript `undefined` value so we can use it as the `this`
|
|
119
|
+
// value of the JavaScript function call.
|
|
120
|
+
status = napi_get_undefined(env, &undefined);
|
|
121
|
+
if (status != napi_ok) {
|
|
122
|
+
napi_throw_error(env, NULL, "Unable to napi_get_undefined (3)");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Call the JavaScript function and pass it the data
|
|
126
|
+
status = napi_call_function(
|
|
127
|
+
env,
|
|
128
|
+
undefined,
|
|
129
|
+
js_cb,
|
|
130
|
+
1,
|
|
131
|
+
&js_buffer,
|
|
132
|
+
NULL
|
|
133
|
+
);
|
|
134
|
+
if (status != napi_ok) {
|
|
135
|
+
napi_throw_error(env, NULL, "Unable to napi_call_function");
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* This function is the callback invoked by the C-SDK when data arrives on the connection.
|
|
145
|
+
*/
|
|
146
|
+
ssize_t on_data(ziti_connection conn, uint8_t *buf, ssize_t len) {
|
|
147
|
+
napi_status status;
|
|
148
|
+
|
|
149
|
+
ConnAddonData* addon_data = (ConnAddonData*) ziti_conn_data(conn);
|
|
150
|
+
|
|
151
|
+
ZITI_NODEJS_LOG(INFO, "len: %zd, conn: %p", len, conn);
|
|
152
|
+
|
|
153
|
+
if (len == ZITI_EOF) {
|
|
154
|
+
if (addon_data->isWebsocket) {
|
|
155
|
+
ZITI_NODEJS_LOG(DEBUG, "skipping ziti_close on ZITI_EOF due to isWebsocket=true");
|
|
156
|
+
return 0;
|
|
157
|
+
} else {
|
|
158
|
+
ziti_close(conn, NULL);
|
|
159
|
+
return 0;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
else if (len < 0) {
|
|
163
|
+
ziti_close(conn, NULL);
|
|
164
|
+
return 0;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
|
|
168
|
+
OnDataItem* item = memset(malloc(sizeof(*item)), 0, sizeof(*item));
|
|
169
|
+
item->buf = buf;
|
|
170
|
+
item->buf = calloc(1, len);
|
|
171
|
+
memcpy(item->buf, buf, len);
|
|
172
|
+
item->len = len;
|
|
173
|
+
|
|
174
|
+
// if (addon_data->isWebsocket) {
|
|
175
|
+
// hexDump("on_data", item->buf, item->len);
|
|
176
|
+
// }
|
|
177
|
+
|
|
178
|
+
// Initiate the call into the JavaScript callback.
|
|
179
|
+
// The call into JavaScript will not have happened
|
|
180
|
+
// when this function returns, but it will be queued.
|
|
181
|
+
status = napi_call_threadsafe_function(
|
|
182
|
+
addon_data->tsfn_on_data,
|
|
183
|
+
item, // Send the data we received from the service on over to the JS callback
|
|
184
|
+
napi_tsfn_blocking);
|
|
185
|
+
if (status != napi_ok) {
|
|
186
|
+
ZITI_NODEJS_LOG(ERROR, "Unable to napi_call_threadsafe_function");
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return len;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
*
|
|
196
|
+
*/
|
|
197
|
+
void on_connect(ziti_connection conn, int status) {
|
|
198
|
+
napi_status nstatus;
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
ConnAddonData* addon_data = (ConnAddonData*) ziti_conn_data(conn);
|
|
202
|
+
ziti_connection* the_conn = NULL;
|
|
203
|
+
|
|
204
|
+
ZITI_NODEJS_LOG(DEBUG, "conn: %p, status: %o, isWebsocket: %o", conn, status, addon_data->isWebsocket);
|
|
205
|
+
|
|
206
|
+
if (status == ZITI_OK) {
|
|
207
|
+
|
|
208
|
+
// Save the 'ziti_connection' to the heap. The JavaScript marshaller (CallJs)
|
|
209
|
+
// will free this item after having sent it to JavaScript.
|
|
210
|
+
the_conn = malloc(sizeof(ziti_connection));
|
|
211
|
+
*the_conn = conn;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
ZITI_NODEJS_LOG(DEBUG, "the_conn: %p", the_conn);
|
|
215
|
+
|
|
216
|
+
// Initiate the call into the JavaScript callback.
|
|
217
|
+
// The call into JavaScript will not have happened
|
|
218
|
+
// when this function returns, but it will be queued.
|
|
219
|
+
nstatus = napi_call_threadsafe_function(
|
|
220
|
+
addon_data->tsfn_on_connect,
|
|
221
|
+
the_conn, // Send the ziti_connection over to the JS callback
|
|
222
|
+
napi_tsfn_blocking);
|
|
223
|
+
if (nstatus != napi_ok) {
|
|
224
|
+
ZITI_NODEJS_LOG(ERROR, "Unable to napi_call_threadsafe_function");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
*
|
|
231
|
+
*/
|
|
232
|
+
napi_value _ziti_dial(napi_env env, const napi_callback_info info) {
|
|
233
|
+
|
|
234
|
+
napi_status status;
|
|
235
|
+
size_t argc = 4;
|
|
236
|
+
napi_value args[4];
|
|
237
|
+
status = napi_get_cb_info(env, info, &argc, args, NULL, NULL);
|
|
238
|
+
if (status != napi_ok) {
|
|
239
|
+
napi_throw_error(env, NULL, "Failed to parse arguments");
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (argc < 4) {
|
|
243
|
+
napi_throw_error(env, "EINVAL", "Too few arguments");
|
|
244
|
+
return NULL;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Obtain service name
|
|
248
|
+
size_t result;
|
|
249
|
+
char ServiceName[256]; //TODO: make this smarter
|
|
250
|
+
status = napi_get_value_string_utf8(env, args[0], ServiceName, 256, &result);
|
|
251
|
+
if (status != napi_ok) {
|
|
252
|
+
napi_throw_error(env, NULL, "Failed to get Service Name");
|
|
253
|
+
}
|
|
254
|
+
ZITI_NODEJS_LOG(DEBUG, "ServiceName: %s", ServiceName);
|
|
255
|
+
|
|
256
|
+
// Obtain isWebsocket flag
|
|
257
|
+
bool isWebsocket = false;
|
|
258
|
+
status = napi_get_value_bool(env, args[1], &isWebsocket);
|
|
259
|
+
if (status != napi_ok) {
|
|
260
|
+
napi_throw_error(env, NULL, "Failed to get isWebsocket flag");
|
|
261
|
+
}
|
|
262
|
+
ZITI_NODEJS_LOG(DEBUG, "isWebsocket is: %o", isWebsocket);
|
|
263
|
+
|
|
264
|
+
// Obtain ptr to JS 'connect' callback function
|
|
265
|
+
napi_value js_connect_cb = args[2];
|
|
266
|
+
napi_value work_name_connect;
|
|
267
|
+
|
|
268
|
+
ConnAddonData* addon_data = memset(malloc(sizeof(*addon_data)), 0, sizeof(*addon_data));
|
|
269
|
+
|
|
270
|
+
addon_data->isWebsocket = isWebsocket;
|
|
271
|
+
|
|
272
|
+
// Create a string to describe this asynchronous operation.
|
|
273
|
+
status = napi_create_string_utf8(
|
|
274
|
+
env,
|
|
275
|
+
"N-API on_connect",
|
|
276
|
+
NAPI_AUTO_LENGTH,
|
|
277
|
+
&work_name_connect);
|
|
278
|
+
if (status != napi_ok) {
|
|
279
|
+
napi_throw_error(env, NULL, "Unable to napi_create_string_utf8");
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Convert the callback retrieved from JavaScript into a thread-safe function (tsfn)
|
|
283
|
+
// which we can call from a worker thread.
|
|
284
|
+
status = napi_create_threadsafe_function(
|
|
285
|
+
env,
|
|
286
|
+
js_connect_cb,
|
|
287
|
+
NULL,
|
|
288
|
+
work_name_connect,
|
|
289
|
+
0,
|
|
290
|
+
1,
|
|
291
|
+
NULL,
|
|
292
|
+
NULL,
|
|
293
|
+
NULL,
|
|
294
|
+
CallJs_on_connect,
|
|
295
|
+
&(addon_data->tsfn_on_connect));
|
|
296
|
+
if (status != napi_ok) {
|
|
297
|
+
napi_throw_error(env, NULL, "Unable to napi_create_threadsafe_function");
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Obtain ptr to JS 'data' callback function
|
|
301
|
+
napi_value js_data_cb = args[3];
|
|
302
|
+
napi_value work_name_data;
|
|
303
|
+
|
|
304
|
+
// Create a string to describe this asynchronous operation.
|
|
305
|
+
status = napi_create_string_utf8(
|
|
306
|
+
env,
|
|
307
|
+
"N-API on_data",
|
|
308
|
+
NAPI_AUTO_LENGTH,
|
|
309
|
+
&work_name_data);
|
|
310
|
+
if (status != napi_ok) {
|
|
311
|
+
napi_throw_error(env, NULL, "Unable to napi_create_string_utf8");
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Convert the callback retrieved from JavaScript into a thread-safe function (tsfn)
|
|
315
|
+
// which we can call from a worker thread.
|
|
316
|
+
status = napi_create_threadsafe_function(
|
|
317
|
+
env,
|
|
318
|
+
js_data_cb,
|
|
319
|
+
NULL,
|
|
320
|
+
work_name_data,
|
|
321
|
+
0,
|
|
322
|
+
1,
|
|
323
|
+
NULL,
|
|
324
|
+
NULL,
|
|
325
|
+
NULL,
|
|
326
|
+
CallJs_on_data,
|
|
327
|
+
&(addon_data->tsfn_on_data));
|
|
328
|
+
if (status != napi_ok) {
|
|
329
|
+
napi_throw_error(env, NULL, "Unable to napi_create_threadsafe_function");
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
ziti_set_timeout(ztx, 5*1000);
|
|
333
|
+
|
|
334
|
+
// Init a Ziti connection object, and attach our add-on data to it so we can
|
|
335
|
+
// pass context around between our callbacks, as propagate it all the way out
|
|
336
|
+
// to the JavaScript callbacks
|
|
337
|
+
ziti_connection conn;
|
|
338
|
+
int rc = ziti_conn_init(ztx, &conn, addon_data);
|
|
339
|
+
if (rc != ZITI_OK) {
|
|
340
|
+
napi_throw_error(env, NULL, "failure in 'ziti_conn_init");
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
// Connect to the service
|
|
345
|
+
ZITI_NODEJS_LOG(DEBUG, "calling ziti_dial: %p", ztx);
|
|
346
|
+
rc = ziti_dial(conn, ServiceName, on_connect, on_data);
|
|
347
|
+
if (rc != ZITI_OK) {
|
|
348
|
+
napi_throw_error(env, NULL, "failure in 'ziti_dial");
|
|
349
|
+
}
|
|
350
|
+
ZITI_NODEJS_LOG(DEBUG, "returned from ziti_dial: %p", ztx);
|
|
351
|
+
|
|
352
|
+
return NULL;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
*
|
|
359
|
+
*/
|
|
360
|
+
void expose_ziti_dial(napi_env env, napi_value exports) {
|
|
361
|
+
napi_status status;
|
|
362
|
+
napi_value fn;
|
|
363
|
+
|
|
364
|
+
status = napi_create_function(env, NULL, 0, _ziti_dial, NULL, &fn);
|
|
365
|
+
if (status != napi_ok) {
|
|
366
|
+
napi_throw_error(env, NULL, "Unable to wrap native function '_ziti_dial");
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
status = napi_set_named_property(env, exports, "ziti_dial", fn);
|
|
370
|
+
if (status != napi_ok) {
|
|
371
|
+
napi_throw_error(env, NULL, "Unable to populate exports for 'ziti_dial");
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
}
|
|
375
|
+
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2019-2020 Netfoundry, Inc.
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
#include "ziti-nodejs.h"
|
|
18
|
+
|
|
19
|
+
ziti_context nf;
|
|
20
|
+
uv_loop_t *enroll_loop = NULL;
|
|
21
|
+
|
|
22
|
+
uv_loop_t *thread_loop;
|
|
23
|
+
uv_thread_t thread;
|
|
24
|
+
uv_async_t async;
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
typedef struct {
|
|
28
|
+
napi_async_work work;
|
|
29
|
+
napi_threadsafe_function tsfn;
|
|
30
|
+
} AddonData;
|
|
31
|
+
|
|
32
|
+
// An item that will be generated here and passed into the JavaScript enroll callback
|
|
33
|
+
typedef struct EnrollItem {
|
|
34
|
+
|
|
35
|
+
unsigned char *json_salvo;
|
|
36
|
+
int status;
|
|
37
|
+
char *err;
|
|
38
|
+
|
|
39
|
+
} EnrollItem;
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* This function is responsible for calling the JavaScript callback function
|
|
44
|
+
* that was specified when the ziti_enroll(...) was called from JavaScript.
|
|
45
|
+
*/
|
|
46
|
+
static void CallJs_on_enroll(napi_env env, napi_value js_cb, void* context, void* data) {
|
|
47
|
+
|
|
48
|
+
ZITI_NODEJS_LOG(DEBUG, "entered");
|
|
49
|
+
|
|
50
|
+
// This parameter is not used.
|
|
51
|
+
(void) context;
|
|
52
|
+
|
|
53
|
+
// Retrieve the EnrollItem created by the worker thread.
|
|
54
|
+
EnrollItem* item = (EnrollItem*)data;
|
|
55
|
+
|
|
56
|
+
ZITI_NODEJS_LOG(DEBUG, "item->json_salvo: %s", item->json_salvo);
|
|
57
|
+
ZITI_NODEJS_LOG(DEBUG, "item->status: %d", item->status);
|
|
58
|
+
ZITI_NODEJS_LOG(DEBUG, "item->err: %s", item->err);
|
|
59
|
+
|
|
60
|
+
// env and js_cb may both be NULL if Node.js is in its cleanup phase, and
|
|
61
|
+
// items are left over from earlier thread-safe calls from the worker thread.
|
|
62
|
+
// When env is NULL, we simply skip over the call into Javascript
|
|
63
|
+
if (env != NULL) {
|
|
64
|
+
|
|
65
|
+
napi_value undefined;
|
|
66
|
+
|
|
67
|
+
// Retrieve the JavaScript `undefined` value so we can use it as the `this`
|
|
68
|
+
// value of the JavaScript function call.
|
|
69
|
+
assert(napi_get_undefined(env, &undefined) == napi_ok);
|
|
70
|
+
|
|
71
|
+
// const obj = {}
|
|
72
|
+
napi_value js_enroll_item, js_json_salvo, js_status, js_err;
|
|
73
|
+
assert(napi_create_object(env, &js_enroll_item) == napi_ok);
|
|
74
|
+
|
|
75
|
+
// obj.identity = identity
|
|
76
|
+
if (NULL != item->json_salvo) {
|
|
77
|
+
assert(napi_create_string_utf8(env, (const char*)item->json_salvo, NAPI_AUTO_LENGTH, &js_json_salvo) == napi_ok);
|
|
78
|
+
assert(napi_set_named_property(env, js_enroll_item, "identity", js_json_salvo) == napi_ok);
|
|
79
|
+
} else {
|
|
80
|
+
assert(napi_set_named_property(env, js_enroll_item, "identity", undefined) == napi_ok);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// obj.status = status
|
|
84
|
+
assert(napi_create_int64(env, (int64_t)item->status, &js_status) == napi_ok);
|
|
85
|
+
assert(napi_set_named_property(env, js_enroll_item, "status", js_status) == napi_ok);
|
|
86
|
+
|
|
87
|
+
// obj.err = err
|
|
88
|
+
if (NULL != item->err) {
|
|
89
|
+
assert(napi_create_string_utf8(env, (const char*)item->err, NAPI_AUTO_LENGTH, &js_err) == napi_ok);
|
|
90
|
+
assert(napi_set_named_property(env, js_enroll_item, "err", js_err) == napi_ok);
|
|
91
|
+
} else {
|
|
92
|
+
assert(napi_set_named_property(env, js_enroll_item, "err", undefined) == napi_ok);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
// Call the JavaScript function and pass it the WriteItem
|
|
97
|
+
assert(
|
|
98
|
+
napi_call_function(
|
|
99
|
+
env,
|
|
100
|
+
undefined,
|
|
101
|
+
js_cb,
|
|
102
|
+
1,
|
|
103
|
+
&js_enroll_item,
|
|
104
|
+
NULL) == napi_ok);
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
*
|
|
112
|
+
*/
|
|
113
|
+
void on_ziti_enroll(ziti_config *cfg, int status, char *err, void *ctx) {
|
|
114
|
+
|
|
115
|
+
ZITI_NODEJS_LOG(DEBUG, "\nstatus: %d, \nerr: %s,\nctx: %p", status, err, ctx);
|
|
116
|
+
|
|
117
|
+
AddonData* addon_data = (AddonData*)ctx;
|
|
118
|
+
|
|
119
|
+
EnrollItem* item = memset(malloc(sizeof(*item)), 0, sizeof(*item));
|
|
120
|
+
|
|
121
|
+
item->status = status;
|
|
122
|
+
|
|
123
|
+
if (NULL != err) {
|
|
124
|
+
item->err = calloc(1, strlen(err));
|
|
125
|
+
strcpy(item->err, err);
|
|
126
|
+
} else {
|
|
127
|
+
item->err = NULL;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (status == ZITI_OK) {
|
|
131
|
+
size_t len;
|
|
132
|
+
char *output_buf = ziti_config_to_json(cfg, 0, &len);
|
|
133
|
+
item->json_salvo = calloc(1, len);
|
|
134
|
+
strcpy(item->json_salvo, output_buf);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Initiate the call into the JavaScript callback.
|
|
138
|
+
// The call into JavaScript will not have happened
|
|
139
|
+
// when this function returns, but it will be queued.
|
|
140
|
+
assert(
|
|
141
|
+
napi_call_threadsafe_function(
|
|
142
|
+
addon_data->tsfn,
|
|
143
|
+
item,
|
|
144
|
+
napi_tsfn_blocking) == napi_ok);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
void child_thread(void *data){
|
|
150
|
+
uv_loop_t *thread_loop = (uv_loop_t *) data;
|
|
151
|
+
|
|
152
|
+
//Start this loop
|
|
153
|
+
uv_run(thread_loop, UV_RUN_DEFAULT);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
static void consumer_notify(uv_async_t *handle, int status) { }
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
*
|
|
160
|
+
*/
|
|
161
|
+
napi_value _ziti_enroll(napi_env env, const napi_callback_info info) {
|
|
162
|
+
napi_status status;
|
|
163
|
+
napi_value jsRetval;
|
|
164
|
+
|
|
165
|
+
ZITI_NODEJS_LOG(DEBUG, "entered");
|
|
166
|
+
|
|
167
|
+
size_t argc = 2;
|
|
168
|
+
napi_value args[2];
|
|
169
|
+
status = napi_get_cb_info(env, info, &argc, args, NULL, NULL);
|
|
170
|
+
if (status != napi_ok) {
|
|
171
|
+
napi_throw_error(env, NULL, "Failed to parse arguments");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (argc < 2) {
|
|
175
|
+
napi_throw_error(env, "EINVAL", "Too few arguments");
|
|
176
|
+
return NULL;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Obtain location of JWT file
|
|
180
|
+
size_t result;
|
|
181
|
+
char JWTFileName[256];
|
|
182
|
+
status = napi_get_value_string_utf8(env, args[0], JWTFileName, 256, &result);
|
|
183
|
+
|
|
184
|
+
// Obtain ptr to JS callback function
|
|
185
|
+
napi_value js_cb = args[1];
|
|
186
|
+
napi_value work_name;
|
|
187
|
+
AddonData* addon_data = malloc(sizeof(AddonData));
|
|
188
|
+
|
|
189
|
+
// Create a string to describe this asynchronous operation.
|
|
190
|
+
assert(napi_create_string_utf8(
|
|
191
|
+
env,
|
|
192
|
+
"N-API on_ziti_enroll",
|
|
193
|
+
NAPI_AUTO_LENGTH,
|
|
194
|
+
&work_name) == napi_ok);
|
|
195
|
+
|
|
196
|
+
// Convert the callback retrieved from JavaScript into a thread-safe function (tsfn)
|
|
197
|
+
// which we can call from a worker thread.
|
|
198
|
+
assert(
|
|
199
|
+
napi_create_threadsafe_function(
|
|
200
|
+
env,
|
|
201
|
+
js_cb,
|
|
202
|
+
NULL,
|
|
203
|
+
work_name,
|
|
204
|
+
0,
|
|
205
|
+
1,
|
|
206
|
+
NULL,
|
|
207
|
+
NULL,
|
|
208
|
+
NULL,
|
|
209
|
+
CallJs_on_enroll,
|
|
210
|
+
&(addon_data->tsfn)) == napi_ok);
|
|
211
|
+
|
|
212
|
+
// Create and set up the consumer thread
|
|
213
|
+
thread_loop = uv_loop_new();
|
|
214
|
+
uv_async_init(thread_loop, &async, (uv_async_cb)consumer_notify);
|
|
215
|
+
uv_thread_create(&thread, (uv_thread_cb)child_thread, thread_loop);
|
|
216
|
+
|
|
217
|
+
// Initiate the enrollment
|
|
218
|
+
ziti_enroll_opts opts = {0};
|
|
219
|
+
opts.jwt = JWTFileName;
|
|
220
|
+
int rc = ziti_enroll(&opts, thread_loop, on_ziti_enroll, addon_data);
|
|
221
|
+
|
|
222
|
+
status = napi_create_int32(env, rc, &jsRetval);
|
|
223
|
+
if (status != napi_ok) {
|
|
224
|
+
napi_throw_error(env, NULL, "Unable to create return value");
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return jsRetval;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
void expose_ziti_enroll(napi_env env, napi_value exports) {
|
|
232
|
+
napi_status status;
|
|
233
|
+
napi_value fn;
|
|
234
|
+
|
|
235
|
+
status = napi_create_function(env, NULL, 0, _ziti_enroll, NULL, &fn);
|
|
236
|
+
if (status != napi_ok) {
|
|
237
|
+
napi_throw_error(env, NULL, "Unable to wrap native function '_ziti_enroll");
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
status = napi_set_named_property(env, exports, "ziti_enroll", fn);
|
|
241
|
+
if (status != napi_ok) {
|
|
242
|
+
napi_throw_error(env, NULL, "Unable to populate exports for 'ziti_enroll");
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
}
|
package/src/ziti_hello.c
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2019-2020 Netfoundry, Inc.
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
#include "ziti-nodejs.h"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
*
|
|
22
|
+
*/
|
|
23
|
+
napi_value _ziti_hello(napi_env env, const napi_callback_info info) {
|
|
24
|
+
napi_value jsRetval = NULL;
|
|
25
|
+
napi_status status = napi_generic_failure;
|
|
26
|
+
|
|
27
|
+
status = napi_create_string_utf8(env, "ziti", NAPI_AUTO_LENGTH, &jsRetval);
|
|
28
|
+
if (status != napi_ok) return NULL;
|
|
29
|
+
|
|
30
|
+
return jsRetval;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
*/
|
|
37
|
+
void expose_ziti_hello(napi_env env, napi_value exports) {
|
|
38
|
+
napi_status status;
|
|
39
|
+
napi_value fn;
|
|
40
|
+
|
|
41
|
+
status = napi_create_function(env, NULL, 0, _ziti_hello, NULL, &fn);
|
|
42
|
+
if (status != napi_ok) {
|
|
43
|
+
napi_throw_error(env, NULL, "Unable to wrap native function '_ziti_hello");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
status = napi_set_named_property(env, exports, "ziti_hello", fn);
|
|
47
|
+
if (status != napi_ok) {
|
|
48
|
+
napi_throw_error(env, NULL, "Unable to populate exports for 'ziti_hello");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
|