quickjs 0.13.0 → 0.14.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.
@@ -0,0 +1,1001 @@
1
+ #include "quickjsrb.h"
2
+ #include "quickjsrb_crypto_subtle.h"
3
+
4
+ // Extract algorithm name from a string or { name: "..." } object.
5
+ // Caller must JS_FreeCString the result.
6
+ static const char *js_get_algorithm_name(JSContext *ctx, JSValueConst j_algo)
7
+ {
8
+ if (JS_IsString(j_algo))
9
+ return JS_ToCString(ctx, j_algo);
10
+ JSValue j_name = JS_GetPropertyStr(ctx, j_algo, "name");
11
+ const char *name = JS_ToCString(ctx, j_name);
12
+ JS_FreeValue(ctx, j_name);
13
+ return name;
14
+ }
15
+
16
+ // Convert a JS ArrayBuffer or TypedArray to a Ruby binary String.
17
+ // Returns Qnil if the value is neither.
18
+ static VALUE js_buffer_to_ruby_str(JSContext *ctx, JSValueConst j_val)
19
+ {
20
+ size_t byte_offset = 0, byte_length = 0, bytes_per_element = 0;
21
+ int is_typed_array = 1;
22
+ JSValue j_buf = JS_GetTypedArrayBuffer(ctx, j_val, &byte_offset, &byte_length, &bytes_per_element);
23
+ if (JS_IsException(j_buf))
24
+ {
25
+ JSValue j_exc = JS_GetException(ctx);
26
+ JS_FreeValue(ctx, j_exc);
27
+ is_typed_array = 0;
28
+ j_buf = JS_DupValue(ctx, j_val);
29
+ }
30
+
31
+ size_t buf_size;
32
+ uint8_t *buf = JS_GetArrayBuffer(ctx, &buf_size, j_buf);
33
+ JS_FreeValue(ctx, j_buf);
34
+
35
+ if (!buf)
36
+ return Qnil;
37
+
38
+ size_t len = is_typed_array ? byte_length : buf_size;
39
+ VALUE r_str = rb_str_new((const char *)(buf + byte_offset), len);
40
+ rb_funcall(r_str, rb_intern("force_encoding"), 1, rb_str_new_cstr("BINARY"));
41
+ return r_str;
42
+ }
43
+
44
+ // Build a Ruby Array of strings from a JS array value.
45
+ static VALUE js_usages_to_ruby_array(JSContext *ctx, JSValueConst j_usages)
46
+ {
47
+ VALUE r_usages = rb_ary_new();
48
+ JSValue j_len = JS_GetPropertyStr(ctx, j_usages, "length");
49
+ int32_t count = 0;
50
+ JS_ToInt32(ctx, &count, j_len);
51
+ JS_FreeValue(ctx, j_len);
52
+ for (int32_t i = 0; i < count; i++)
53
+ {
54
+ JSValue j_u = JS_GetPropertyUint32(ctx, j_usages, (uint32_t)i);
55
+ const char *u_str = JS_ToCString(ctx, j_u);
56
+ if (u_str)
57
+ rb_ary_push(r_usages, rb_str_new_cstr(u_str));
58
+ JS_FreeCString(ctx, u_str);
59
+ JS_FreeValue(ctx, j_u);
60
+ }
61
+ return r_usages;
62
+ }
63
+
64
+ // Reject a promise with a plain JS Error built from Ruby exception info.
65
+ static void js_reject_with_ruby_error(JSContext *ctx, JSValueConst *resolving_funcs)
66
+ {
67
+ VALUE r_error = rb_errinfo();
68
+ VALUE r_message = rb_funcall(r_error, rb_intern("message"), 0);
69
+ JSValue j_err = JS_NewError(ctx);
70
+ JS_SetPropertyStr(ctx, j_err, "message", JS_NewString(ctx, StringValueCStr(r_message)));
71
+ JSValue ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1, (JSValueConst *)&j_err);
72
+ JS_FreeValue(ctx, j_err);
73
+ JS_FreeValue(ctx, ret);
74
+ }
75
+
76
+ // Find Ruby CryptoKey from a JS CryptoKey object via rb_object_id handle.
77
+ static VALUE r_find_alive_crypto_key(JSContext *ctx, JSValueConst j_key)
78
+ {
79
+ JSValue j_handle = JS_GetPropertyStr(ctx, j_key, "rb_object_id");
80
+ int64_t handle = 0;
81
+ JS_ToInt64(ctx, &handle, j_handle);
82
+ JS_FreeValue(ctx, j_handle);
83
+ if (handle <= 0)
84
+ return Qnil;
85
+ VMData *data = JS_GetContextOpaque(ctx);
86
+ return rb_hash_aref(data->alive_objects, LONG2NUM(handle));
87
+ }
88
+
89
+ // Build a comprehensive Ruby Hash (symbol keys) from a JS algorithm object.
90
+ // Extracts all possible properties used across SubtleCrypto operations.
91
+ static VALUE js_algo_to_ruby_hash(JSContext *ctx, JSValueConst j_algo)
92
+ {
93
+ VALUE r_hash = rb_hash_new();
94
+
95
+ const char *name = js_get_algorithm_name(ctx, j_algo);
96
+ if (name)
97
+ {
98
+ rb_hash_aset(r_hash, ID2SYM(rb_intern("name")), rb_str_new_cstr(name));
99
+ JS_FreeCString(ctx, name);
100
+ }
101
+
102
+ if (JS_IsString(j_algo))
103
+ return r_hash;
104
+
105
+ JSValue j_length = JS_GetPropertyStr(ctx, j_algo, "length");
106
+ if (!JS_IsUndefined(j_length) && !JS_IsException(j_length))
107
+ {
108
+ int32_t length = 0;
109
+ JS_ToInt32(ctx, &length, j_length);
110
+ rb_hash_aset(r_hash, ID2SYM(rb_intern("length")), INT2NUM(length));
111
+ }
112
+ JS_FreeValue(ctx, j_length);
113
+
114
+ JSValue j_named_curve = JS_GetPropertyStr(ctx, j_algo, "namedCurve");
115
+ if (!JS_IsUndefined(j_named_curve) && !JS_IsException(j_named_curve))
116
+ {
117
+ const char *nc = JS_ToCString(ctx, j_named_curve);
118
+ if (nc)
119
+ {
120
+ rb_hash_aset(r_hash, ID2SYM(rb_intern("named_curve")), rb_str_new_cstr(nc));
121
+ JS_FreeCString(ctx, nc);
122
+ }
123
+ }
124
+ JS_FreeValue(ctx, j_named_curve);
125
+
126
+ JSValue j_hash = JS_GetPropertyStr(ctx, j_algo, "hash");
127
+ if (!JS_IsUndefined(j_hash) && !JS_IsException(j_hash))
128
+ {
129
+ const char *hash_name = js_get_algorithm_name(ctx, j_hash);
130
+ if (hash_name)
131
+ {
132
+ rb_hash_aset(r_hash, ID2SYM(rb_intern("hash")), rb_str_new_cstr(hash_name));
133
+ JS_FreeCString(ctx, hash_name);
134
+ }
135
+ }
136
+ JS_FreeValue(ctx, j_hash);
137
+
138
+ JSValue j_modulus_length = JS_GetPropertyStr(ctx, j_algo, "modulusLength");
139
+ if (!JS_IsUndefined(j_modulus_length) && !JS_IsException(j_modulus_length))
140
+ {
141
+ int32_t mod_len = 0;
142
+ JS_ToInt32(ctx, &mod_len, j_modulus_length);
143
+ rb_hash_aset(r_hash, ID2SYM(rb_intern("modulus_length")), INT2NUM(mod_len));
144
+ }
145
+ JS_FreeValue(ctx, j_modulus_length);
146
+
147
+ JSValue j_pub_exp = JS_GetPropertyStr(ctx, j_algo, "publicExponent");
148
+ if (!JS_IsUndefined(j_pub_exp) && !JS_IsException(j_pub_exp))
149
+ {
150
+ VALUE r_pe = js_buffer_to_ruby_str(ctx, j_pub_exp);
151
+ if (!NIL_P(r_pe))
152
+ rb_hash_aset(r_hash, ID2SYM(rb_intern("public_exponent")), r_pe);
153
+ }
154
+ JS_FreeValue(ctx, j_pub_exp);
155
+
156
+ JSValue j_iv = JS_GetPropertyStr(ctx, j_algo, "iv");
157
+ if (!JS_IsUndefined(j_iv) && !JS_IsException(j_iv))
158
+ {
159
+ VALUE r_iv = js_buffer_to_ruby_str(ctx, j_iv);
160
+ if (!NIL_P(r_iv))
161
+ rb_hash_aset(r_hash, ID2SYM(rb_intern("iv")), r_iv);
162
+ }
163
+ JS_FreeValue(ctx, j_iv);
164
+
165
+ JSValue j_tag_length = JS_GetPropertyStr(ctx, j_algo, "tagLength");
166
+ if (!JS_IsUndefined(j_tag_length) && !JS_IsException(j_tag_length))
167
+ {
168
+ int32_t tag_length = 0;
169
+ JS_ToInt32(ctx, &tag_length, j_tag_length);
170
+ rb_hash_aset(r_hash, ID2SYM(rb_intern("tag_length")), INT2NUM(tag_length));
171
+ }
172
+ JS_FreeValue(ctx, j_tag_length);
173
+
174
+ JSValue j_additional_data = JS_GetPropertyStr(ctx, j_algo, "additionalData");
175
+ if (!JS_IsUndefined(j_additional_data) && !JS_IsException(j_additional_data))
176
+ {
177
+ VALUE r_ad = js_buffer_to_ruby_str(ctx, j_additional_data);
178
+ if (!NIL_P(r_ad))
179
+ rb_hash_aset(r_hash, ID2SYM(rb_intern("additional_data")), r_ad);
180
+ }
181
+ JS_FreeValue(ctx, j_additional_data);
182
+
183
+ JSValue j_counter = JS_GetPropertyStr(ctx, j_algo, "counter");
184
+ if (!JS_IsUndefined(j_counter) && !JS_IsException(j_counter))
185
+ {
186
+ VALUE r_counter = js_buffer_to_ruby_str(ctx, j_counter);
187
+ if (!NIL_P(r_counter))
188
+ rb_hash_aset(r_hash, ID2SYM(rb_intern("counter")), r_counter);
189
+ }
190
+ JS_FreeValue(ctx, j_counter);
191
+
192
+ JSValue j_salt = JS_GetPropertyStr(ctx, j_algo, "salt");
193
+ if (!JS_IsUndefined(j_salt) && !JS_IsException(j_salt))
194
+ {
195
+ VALUE r_salt = js_buffer_to_ruby_str(ctx, j_salt);
196
+ if (!NIL_P(r_salt))
197
+ rb_hash_aset(r_hash, ID2SYM(rb_intern("salt")), r_salt);
198
+ }
199
+ JS_FreeValue(ctx, j_salt);
200
+
201
+ JSValue j_iterations = JS_GetPropertyStr(ctx, j_algo, "iterations");
202
+ if (!JS_IsUndefined(j_iterations) && !JS_IsException(j_iterations))
203
+ {
204
+ int32_t iterations = 0;
205
+ JS_ToInt32(ctx, &iterations, j_iterations);
206
+ rb_hash_aset(r_hash, ID2SYM(rb_intern("iterations")), INT2NUM(iterations));
207
+ }
208
+ JS_FreeValue(ctx, j_iterations);
209
+
210
+ JSValue j_info = JS_GetPropertyStr(ctx, j_algo, "info");
211
+ if (!JS_IsUndefined(j_info) && !JS_IsException(j_info))
212
+ {
213
+ VALUE r_info = js_buffer_to_ruby_str(ctx, j_info);
214
+ if (!NIL_P(r_info))
215
+ rb_hash_aset(r_hash, ID2SYM(rb_intern("info")), r_info);
216
+ }
217
+ JS_FreeValue(ctx, j_info);
218
+
219
+ JSValue j_salt_length = JS_GetPropertyStr(ctx, j_algo, "saltLength");
220
+ if (!JS_IsUndefined(j_salt_length) && !JS_IsException(j_salt_length))
221
+ {
222
+ int32_t salt_length = 0;
223
+ JS_ToInt32(ctx, &salt_length, j_salt_length);
224
+ rb_hash_aset(r_hash, ID2SYM(rb_intern("salt_length")), INT2NUM(salt_length));
225
+ }
226
+ JS_FreeValue(ctx, j_salt_length);
227
+
228
+ JSValue j_label = JS_GetPropertyStr(ctx, j_algo, "label");
229
+ if (!JS_IsUndefined(j_label) && !JS_IsException(j_label))
230
+ {
231
+ VALUE r_label = js_buffer_to_ruby_str(ctx, j_label);
232
+ if (!NIL_P(r_label))
233
+ rb_hash_aset(r_hash, ID2SYM(rb_intern("label")), r_label);
234
+ }
235
+ JS_FreeValue(ctx, j_label);
236
+
237
+ JSValue j_public = JS_GetPropertyStr(ctx, j_algo, "public");
238
+ if (!JS_IsUndefined(j_public) && !JS_IsException(j_public) && JS_IsObject(j_public))
239
+ {
240
+ VALUE r_public = r_find_alive_crypto_key(ctx, j_public);
241
+ if (!NIL_P(r_public))
242
+ rb_hash_aset(r_hash, ID2SYM(rb_intern("public")), r_public);
243
+ }
244
+ JS_FreeValue(ctx, j_public);
245
+
246
+ return r_hash;
247
+ }
248
+
249
+ // Build a JS CryptoKey plain object from a Ruby Quickjs::CryptoKey.
250
+ // Stores the Ruby object in alive_objects; sets rb_object_id as non-enumerable.
251
+ static JSValue js_crypto_key_to_js(JSContext *ctx, VALUE r_key)
252
+ {
253
+ VMData *data = JS_GetContextOpaque(ctx);
254
+ VALUE r_object_id = rb_funcall(r_key, rb_intern("object_id"), 0);
255
+ rb_hash_aset(data->alive_objects, r_object_id, r_key);
256
+ int64_t handle = NUM2LONG(r_object_id);
257
+
258
+ VALUE r_type = rb_funcall(r_key, rb_intern("type"), 0);
259
+ VALUE r_extractable = rb_funcall(r_key, rb_intern("extractable"), 0);
260
+ VALUE r_algorithm = rb_funcall(r_key, rb_intern("algorithm"), 0);
261
+ VALUE r_usages = rb_funcall(r_key, rb_intern("usages"), 0);
262
+
263
+ JSValue j_key = JS_NewObject(ctx);
264
+
265
+ JS_SetPropertyStr(ctx, j_key, "type", JS_NewString(ctx, StringValueCStr(r_type)));
266
+ JS_SetPropertyStr(ctx, j_key, "extractable", JS_NewBool(ctx, RTEST(r_extractable)));
267
+
268
+ JSValue j_algo = JS_NewObject(ctx);
269
+
270
+ VALUE r_algo_name = rb_hash_aref(r_algorithm, rb_str_new_cstr("name"));
271
+ JS_SetPropertyStr(ctx, j_algo, "name", JS_NewString(ctx, StringValueCStr(r_algo_name)));
272
+
273
+ VALUE r_algo_length = rb_hash_aref(r_algorithm, rb_str_new_cstr("length"));
274
+ if (!NIL_P(r_algo_length))
275
+ JS_SetPropertyStr(ctx, j_algo, "length", JS_NewInt32(ctx, NUM2INT(r_algo_length)));
276
+
277
+ VALUE r_algo_named_curve = rb_hash_aref(r_algorithm, rb_str_new_cstr("namedCurve"));
278
+ if (!NIL_P(r_algo_named_curve))
279
+ JS_SetPropertyStr(ctx, j_algo, "namedCurve", JS_NewString(ctx, StringValueCStr(r_algo_named_curve)));
280
+
281
+ VALUE r_algo_hash = rb_hash_aref(r_algorithm, rb_str_new_cstr("hash"));
282
+ if (!NIL_P(r_algo_hash))
283
+ {
284
+ JSValue j_hash_obj = JS_NewObject(ctx);
285
+ JS_SetPropertyStr(ctx, j_hash_obj, "name", JS_NewString(ctx, StringValueCStr(r_algo_hash)));
286
+ JS_SetPropertyStr(ctx, j_algo, "hash", j_hash_obj);
287
+ }
288
+
289
+ VALUE r_algo_modulus_length = rb_hash_aref(r_algorithm, rb_str_new_cstr("modulusLength"));
290
+ if (!NIL_P(r_algo_modulus_length))
291
+ JS_SetPropertyStr(ctx, j_algo, "modulusLength", JS_NewInt32(ctx, NUM2INT(r_algo_modulus_length)));
292
+
293
+ VALUE r_algo_pub_exp = rb_hash_aref(r_algorithm, rb_str_new_cstr("publicExponent"));
294
+ if (!NIL_P(r_algo_pub_exp))
295
+ {
296
+ JSValue j_pe_buf = JS_NewArrayBufferCopy(ctx,
297
+ (const uint8_t *)RSTRING_PTR(r_algo_pub_exp),
298
+ RSTRING_LEN(r_algo_pub_exp));
299
+ JSValue j_uint8 = JS_GetPropertyStr(ctx, JS_GetGlobalObject(ctx), "Uint8Array");
300
+ JSValue j_pe = JS_CallConstructor(ctx, j_uint8, 1, (JSValueConst *)&j_pe_buf);
301
+ JS_FreeValue(ctx, j_uint8);
302
+ JS_FreeValue(ctx, j_pe_buf);
303
+ JS_SetPropertyStr(ctx, j_algo, "publicExponent", j_pe);
304
+ }
305
+
306
+ JS_SetPropertyStr(ctx, j_key, "algorithm", j_algo);
307
+
308
+ long usages_len = RARRAY_LEN(r_usages);
309
+ JSValue j_usages = JS_NewArray(ctx);
310
+ for (long i = 0; i < usages_len; i++)
311
+ {
312
+ VALUE r_usage = rb_ary_entry(r_usages, i);
313
+ JS_SetPropertyUint32(ctx, j_usages, (uint32_t)i, JS_NewString(ctx, StringValueCStr(r_usage)));
314
+ }
315
+ JS_SetPropertyStr(ctx, j_key, "usages", j_usages);
316
+
317
+ JS_DefinePropertyValueStr(ctx, j_key, "rb_object_id",
318
+ JS_NewInt64(ctx, handle),
319
+ JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
320
+
321
+ return j_key;
322
+ }
323
+
324
+ static VALUE r_subtle_digest_call(VALUE r_args)
325
+ {
326
+ VALUE r_algorithm = rb_ary_entry(r_args, 0);
327
+ VALUE r_data = rb_ary_entry(r_args, 1);
328
+ VALUE r_mod = rb_const_get(rb_const_get(rb_cObject, rb_intern("Quickjs")), rb_intern("SubtleCrypto"));
329
+ return rb_funcall(r_mod, rb_intern("digest"), 2, r_algorithm, r_data);
330
+ }
331
+
332
+ static JSValue js_subtle_digest(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
333
+ {
334
+ if (argc < 2)
335
+ return JS_ThrowTypeError(ctx, "Failed to execute 'digest': 2 arguments required.");
336
+
337
+ const char *algorithm_name = js_get_algorithm_name(ctx, argv[0]);
338
+ if (!algorithm_name)
339
+ return JS_ThrowTypeError(ctx, "Failed to execute 'digest': algorithm name is required.");
340
+ VALUE r_algorithm = rb_str_new_cstr(algorithm_name);
341
+ JS_FreeCString(ctx, algorithm_name);
342
+
343
+ VALUE r_data = js_buffer_to_ruby_str(ctx, argv[1]);
344
+ if (NIL_P(r_data))
345
+ return JS_ThrowTypeError(ctx, "Failed to execute 'digest': data must be an ArrayBuffer or TypedArray.");
346
+
347
+ JSValue promise, resolving_funcs[2];
348
+ promise = JS_NewPromiseCapability(ctx, resolving_funcs);
349
+ if (JS_IsException(promise))
350
+ return JS_EXCEPTION;
351
+
352
+ VALUE r_args = rb_ary_new3(2, r_algorithm, r_data);
353
+ int error_state;
354
+ VALUE r_result = rb_protect(r_subtle_digest_call, r_args, &error_state);
355
+
356
+ if (error_state)
357
+ {
358
+ js_reject_with_ruby_error(ctx, resolving_funcs);
359
+ }
360
+ else
361
+ {
362
+ JSValue j_result = JS_NewArrayBufferCopy(ctx, (const uint8_t *)RSTRING_PTR(r_result), RSTRING_LEN(r_result));
363
+ JSValue ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1, (JSValueConst *)&j_result);
364
+ JS_FreeValue(ctx, j_result);
365
+ JS_FreeValue(ctx, ret);
366
+ }
367
+
368
+ JS_FreeValue(ctx, resolving_funcs[0]);
369
+ JS_FreeValue(ctx, resolving_funcs[1]);
370
+
371
+ return promise;
372
+ }
373
+
374
+ static VALUE r_subtle_generate_key_call(VALUE r_args)
375
+ {
376
+ VALUE r_mod = rb_const_get(rb_const_get(rb_cObject, rb_intern("Quickjs")), rb_intern("SubtleCrypto"));
377
+ return rb_funcall(r_mod, rb_intern("generate_key"), 3,
378
+ rb_ary_entry(r_args, 0),
379
+ rb_ary_entry(r_args, 1),
380
+ rb_ary_entry(r_args, 2));
381
+ }
382
+
383
+ static JSValue js_subtle_generate_key(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
384
+ {
385
+ if (argc < 3)
386
+ return JS_ThrowTypeError(ctx, "Failed to execute 'generateKey': 3 arguments required.");
387
+
388
+ VALUE r_algo_hash = js_algo_to_ruby_hash(ctx, argv[0]);
389
+ VALUE r_extractable = JS_ToBool(ctx, argv[1]) ? Qtrue : Qfalse;
390
+ VALUE r_usages = js_usages_to_ruby_array(ctx, argv[2]);
391
+
392
+ JSValue promise, resolving_funcs[2];
393
+ promise = JS_NewPromiseCapability(ctx, resolving_funcs);
394
+ if (JS_IsException(promise))
395
+ return JS_EXCEPTION;
396
+
397
+ VALUE r_args = rb_ary_new3(3, r_algo_hash, r_extractable, r_usages);
398
+ int error_state;
399
+ VALUE r_result = rb_protect(r_subtle_generate_key_call, r_args, &error_state);
400
+
401
+ if (error_state)
402
+ {
403
+ js_reject_with_ruby_error(ctx, resolving_funcs);
404
+ }
405
+ else if (RB_TYPE_P(r_result, T_HASH))
406
+ {
407
+ VALUE r_priv = rb_hash_aref(r_result, ID2SYM(rb_intern("private_key")));
408
+ VALUE r_pub = rb_hash_aref(r_result, ID2SYM(rb_intern("public_key")));
409
+ JSValue j_pair = JS_NewObject(ctx);
410
+ JSValue j_priv = js_crypto_key_to_js(ctx, r_priv);
411
+ JSValue j_pub = js_crypto_key_to_js(ctx, r_pub);
412
+ JS_SetPropertyStr(ctx, j_pair, "privateKey", j_priv);
413
+ JS_SetPropertyStr(ctx, j_pair, "publicKey", j_pub);
414
+ JSValue ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1, (JSValueConst *)&j_pair);
415
+ JS_FreeValue(ctx, j_pair);
416
+ JS_FreeValue(ctx, ret);
417
+ }
418
+ else
419
+ {
420
+ JSValue j_result = js_crypto_key_to_js(ctx, r_result);
421
+ JSValue ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1, (JSValueConst *)&j_result);
422
+ JS_FreeValue(ctx, j_result);
423
+ JS_FreeValue(ctx, ret);
424
+ }
425
+
426
+ JS_FreeValue(ctx, resolving_funcs[0]);
427
+ JS_FreeValue(ctx, resolving_funcs[1]);
428
+
429
+ return promise;
430
+ }
431
+
432
+ static VALUE r_subtle_import_key_call(VALUE r_args)
433
+ {
434
+ VALUE r_mod = rb_const_get(rb_const_get(rb_cObject, rb_intern("Quickjs")), rb_intern("SubtleCrypto"));
435
+ return rb_funcall(r_mod, rb_intern("import_key"), 5,
436
+ rb_ary_entry(r_args, 0),
437
+ rb_ary_entry(r_args, 1),
438
+ rb_ary_entry(r_args, 2),
439
+ rb_ary_entry(r_args, 3),
440
+ rb_ary_entry(r_args, 4));
441
+ }
442
+
443
+ static JSValue js_subtle_import_key(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
444
+ {
445
+ if (argc < 5)
446
+ return JS_ThrowTypeError(ctx, "Failed to execute 'importKey': 5 arguments required.");
447
+
448
+ const char *format_cstr = JS_ToCString(ctx, argv[0]);
449
+ if (!format_cstr)
450
+ return JS_ThrowTypeError(ctx, "Failed to execute 'importKey': format must be a string.");
451
+ VALUE r_format = rb_str_new_cstr(format_cstr);
452
+ JS_FreeCString(ctx, format_cstr);
453
+
454
+ VALUE r_key_data = js_buffer_to_ruby_str(ctx, argv[1]);
455
+
456
+ VALUE r_algo_hash = js_algo_to_ruby_hash(ctx, argv[2]);
457
+ VALUE r_extractable = JS_ToBool(ctx, argv[3]) ? Qtrue : Qfalse;
458
+ VALUE r_usages = js_usages_to_ruby_array(ctx, argv[4]);
459
+
460
+ JSValue promise, resolving_funcs[2];
461
+ promise = JS_NewPromiseCapability(ctx, resolving_funcs);
462
+ if (JS_IsException(promise))
463
+ return JS_EXCEPTION;
464
+
465
+ VALUE r_args = rb_ary_new3(5, r_format, r_key_data, r_algo_hash, r_extractable, r_usages);
466
+ int error_state;
467
+ VALUE r_result = rb_protect(r_subtle_import_key_call, r_args, &error_state);
468
+
469
+ if (error_state)
470
+ {
471
+ js_reject_with_ruby_error(ctx, resolving_funcs);
472
+ }
473
+ else
474
+ {
475
+ JSValue j_result = js_crypto_key_to_js(ctx, r_result);
476
+ JSValue ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1, (JSValueConst *)&j_result);
477
+ JS_FreeValue(ctx, j_result);
478
+ JS_FreeValue(ctx, ret);
479
+ }
480
+
481
+ JS_FreeValue(ctx, resolving_funcs[0]);
482
+ JS_FreeValue(ctx, resolving_funcs[1]);
483
+
484
+ return promise;
485
+ }
486
+
487
+ static VALUE r_subtle_export_key_call(VALUE r_args)
488
+ {
489
+ VALUE r_mod = rb_const_get(rb_const_get(rb_cObject, rb_intern("Quickjs")), rb_intern("SubtleCrypto"));
490
+ return rb_funcall(r_mod, rb_intern("export_key"), 2,
491
+ rb_ary_entry(r_args, 0),
492
+ rb_ary_entry(r_args, 1));
493
+ }
494
+
495
+ static JSValue js_subtle_export_key(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
496
+ {
497
+ if (argc < 2)
498
+ return JS_ThrowTypeError(ctx, "Failed to execute 'exportKey': 2 arguments required.");
499
+
500
+ const char *format_cstr = JS_ToCString(ctx, argv[0]);
501
+ if (!format_cstr)
502
+ return JS_ThrowTypeError(ctx, "Failed to execute 'exportKey': format must be a string.");
503
+ VALUE r_format = rb_str_new_cstr(format_cstr);
504
+ JS_FreeCString(ctx, format_cstr);
505
+
506
+ VALUE r_key = r_find_alive_crypto_key(ctx, argv[1]);
507
+ if (NIL_P(r_key))
508
+ return JS_ThrowTypeError(ctx, "Failed to execute 'exportKey': invalid CryptoKey.");
509
+
510
+ JSValue promise, resolving_funcs[2];
511
+ promise = JS_NewPromiseCapability(ctx, resolving_funcs);
512
+ if (JS_IsException(promise))
513
+ return JS_EXCEPTION;
514
+
515
+ VALUE r_args = rb_ary_new3(2, r_format, r_key);
516
+ int error_state;
517
+ VALUE r_result = rb_protect(r_subtle_export_key_call, r_args, &error_state);
518
+
519
+ if (error_state)
520
+ {
521
+ js_reject_with_ruby_error(ctx, resolving_funcs);
522
+ }
523
+ else
524
+ {
525
+ JSValue j_result = JS_NewArrayBufferCopy(ctx, (const uint8_t *)RSTRING_PTR(r_result), RSTRING_LEN(r_result));
526
+ JSValue ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1, (JSValueConst *)&j_result);
527
+ JS_FreeValue(ctx, j_result);
528
+ JS_FreeValue(ctx, ret);
529
+ }
530
+
531
+ JS_FreeValue(ctx, resolving_funcs[0]);
532
+ JS_FreeValue(ctx, resolving_funcs[1]);
533
+
534
+ return promise;
535
+ }
536
+
537
+ static VALUE r_subtle_encrypt_call(VALUE r_args)
538
+ {
539
+ VALUE r_mod = rb_const_get(rb_const_get(rb_cObject, rb_intern("Quickjs")), rb_intern("SubtleCrypto"));
540
+ return rb_funcall(r_mod, rb_intern("encrypt"), 4,
541
+ rb_ary_entry(r_args, 0),
542
+ rb_ary_entry(r_args, 1),
543
+ rb_ary_entry(r_args, 2),
544
+ rb_ary_entry(r_args, 3));
545
+ }
546
+
547
+ static VALUE r_subtle_decrypt_call(VALUE r_args)
548
+ {
549
+ VALUE r_mod = rb_const_get(rb_const_get(rb_cObject, rb_intern("Quickjs")), rb_intern("SubtleCrypto"));
550
+ return rb_funcall(r_mod, rb_intern("decrypt"), 4,
551
+ rb_ary_entry(r_args, 0),
552
+ rb_ary_entry(r_args, 1),
553
+ rb_ary_entry(r_args, 2),
554
+ rb_ary_entry(r_args, 3));
555
+ }
556
+
557
+ static JSValue js_subtle_crypt(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv,
558
+ VALUE (*r_call_func)(VALUE))
559
+ {
560
+ if (argc < 3)
561
+ return JS_ThrowTypeError(ctx, "3 arguments required.");
562
+
563
+ VALUE r_algo_hash = js_algo_to_ruby_hash(ctx, argv[0]);
564
+ VALUE r_name = rb_hash_aref(r_algo_hash, ID2SYM(rb_intern("name")));
565
+ if (NIL_P(r_name))
566
+ return JS_ThrowTypeError(ctx, "algorithm name is required.");
567
+
568
+ VALUE r_key = r_find_alive_crypto_key(ctx, argv[1]);
569
+ if (NIL_P(r_key))
570
+ return JS_ThrowTypeError(ctx, "invalid CryptoKey.");
571
+
572
+ VALUE r_data = js_buffer_to_ruby_str(ctx, argv[2]);
573
+ if (NIL_P(r_data))
574
+ return JS_ThrowTypeError(ctx, "data must be an ArrayBuffer or TypedArray.");
575
+
576
+ VALUE r_args = rb_ary_new3(4, r_name, r_key, r_data, r_algo_hash);
577
+
578
+ JSValue promise, resolving_funcs[2];
579
+ promise = JS_NewPromiseCapability(ctx, resolving_funcs);
580
+ if (JS_IsException(promise))
581
+ return JS_EXCEPTION;
582
+
583
+ int error_state;
584
+ VALUE r_result = rb_protect(r_call_func, r_args, &error_state);
585
+
586
+ if (error_state)
587
+ {
588
+ js_reject_with_ruby_error(ctx, resolving_funcs);
589
+ }
590
+ else
591
+ {
592
+ JSValue j_result = JS_NewArrayBufferCopy(ctx, (const uint8_t *)RSTRING_PTR(r_result), RSTRING_LEN(r_result));
593
+ JSValue ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1, (JSValueConst *)&j_result);
594
+ JS_FreeValue(ctx, j_result);
595
+ JS_FreeValue(ctx, ret);
596
+ }
597
+
598
+ JS_FreeValue(ctx, resolving_funcs[0]);
599
+ JS_FreeValue(ctx, resolving_funcs[1]);
600
+
601
+ return promise;
602
+ }
603
+
604
+ static JSValue js_subtle_encrypt(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
605
+ {
606
+ return js_subtle_crypt(ctx, this_val, argc, argv, r_subtle_encrypt_call);
607
+ }
608
+
609
+ static JSValue js_subtle_decrypt(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
610
+ {
611
+ return js_subtle_crypt(ctx, this_val, argc, argv, r_subtle_decrypt_call);
612
+ }
613
+
614
+ static VALUE r_subtle_sign_call(VALUE r_args)
615
+ {
616
+ VALUE r_mod = rb_const_get(rb_const_get(rb_cObject, rb_intern("Quickjs")), rb_intern("SubtleCrypto"));
617
+ return rb_funcall(r_mod, rb_intern("sign"), 4,
618
+ rb_ary_entry(r_args, 0),
619
+ rb_ary_entry(r_args, 1),
620
+ rb_ary_entry(r_args, 2),
621
+ rb_ary_entry(r_args, 3));
622
+ }
623
+
624
+ static JSValue js_subtle_sign(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
625
+ {
626
+ if (argc < 3)
627
+ return JS_ThrowTypeError(ctx, "Failed to execute 'sign': 3 arguments required.");
628
+
629
+ VALUE r_algo_hash = js_algo_to_ruby_hash(ctx, argv[0]);
630
+ VALUE r_name = rb_hash_aref(r_algo_hash, ID2SYM(rb_intern("name")));
631
+ if (NIL_P(r_name))
632
+ return JS_ThrowTypeError(ctx, "Failed to execute 'sign': algorithm name is required.");
633
+
634
+ VALUE r_key = r_find_alive_crypto_key(ctx, argv[1]);
635
+ if (NIL_P(r_key))
636
+ return JS_ThrowTypeError(ctx, "Failed to execute 'sign': invalid CryptoKey.");
637
+
638
+ VALUE r_data = js_buffer_to_ruby_str(ctx, argv[2]);
639
+ if (NIL_P(r_data))
640
+ return JS_ThrowTypeError(ctx, "Failed to execute 'sign': data must be an ArrayBuffer or TypedArray.");
641
+
642
+ JSValue promise, resolving_funcs[2];
643
+ promise = JS_NewPromiseCapability(ctx, resolving_funcs);
644
+ if (JS_IsException(promise))
645
+ return JS_EXCEPTION;
646
+
647
+ VALUE r_args = rb_ary_new3(4, r_name, r_key, r_data, r_algo_hash);
648
+ int error_state;
649
+ VALUE r_result = rb_protect(r_subtle_sign_call, r_args, &error_state);
650
+
651
+ if (error_state)
652
+ {
653
+ js_reject_with_ruby_error(ctx, resolving_funcs);
654
+ }
655
+ else
656
+ {
657
+ JSValue j_result = JS_NewArrayBufferCopy(ctx, (const uint8_t *)RSTRING_PTR(r_result), RSTRING_LEN(r_result));
658
+ JSValue ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1, (JSValueConst *)&j_result);
659
+ JS_FreeValue(ctx, j_result);
660
+ JS_FreeValue(ctx, ret);
661
+ }
662
+
663
+ JS_FreeValue(ctx, resolving_funcs[0]);
664
+ JS_FreeValue(ctx, resolving_funcs[1]);
665
+
666
+ return promise;
667
+ }
668
+
669
+ static VALUE r_subtle_verify_call(VALUE r_args)
670
+ {
671
+ VALUE r_mod = rb_const_get(rb_const_get(rb_cObject, rb_intern("Quickjs")), rb_intern("SubtleCrypto"));
672
+ return rb_funcall(r_mod, rb_intern("verify"), 5,
673
+ rb_ary_entry(r_args, 0),
674
+ rb_ary_entry(r_args, 1),
675
+ rb_ary_entry(r_args, 2),
676
+ rb_ary_entry(r_args, 3),
677
+ rb_ary_entry(r_args, 4));
678
+ }
679
+
680
+ static JSValue js_subtle_verify(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
681
+ {
682
+ if (argc < 4)
683
+ return JS_ThrowTypeError(ctx, "Failed to execute 'verify': 4 arguments required.");
684
+
685
+ VALUE r_algo_hash = js_algo_to_ruby_hash(ctx, argv[0]);
686
+ VALUE r_name = rb_hash_aref(r_algo_hash, ID2SYM(rb_intern("name")));
687
+ if (NIL_P(r_name))
688
+ return JS_ThrowTypeError(ctx, "Failed to execute 'verify': algorithm name is required.");
689
+
690
+ VALUE r_key = r_find_alive_crypto_key(ctx, argv[1]);
691
+ if (NIL_P(r_key))
692
+ return JS_ThrowTypeError(ctx, "Failed to execute 'verify': invalid CryptoKey.");
693
+
694
+ VALUE r_signature = js_buffer_to_ruby_str(ctx, argv[2]);
695
+ if (NIL_P(r_signature))
696
+ return JS_ThrowTypeError(ctx, "Failed to execute 'verify': signature must be an ArrayBuffer or TypedArray.");
697
+
698
+ VALUE r_data = js_buffer_to_ruby_str(ctx, argv[3]);
699
+ if (NIL_P(r_data))
700
+ return JS_ThrowTypeError(ctx, "Failed to execute 'verify': data must be an ArrayBuffer or TypedArray.");
701
+
702
+ JSValue promise, resolving_funcs[2];
703
+ promise = JS_NewPromiseCapability(ctx, resolving_funcs);
704
+ if (JS_IsException(promise))
705
+ return JS_EXCEPTION;
706
+
707
+ VALUE r_args = rb_ary_new3(5, r_name, r_key, r_signature, r_data, r_algo_hash);
708
+ int error_state;
709
+ VALUE r_result = rb_protect(r_subtle_verify_call, r_args, &error_state);
710
+
711
+ if (error_state)
712
+ {
713
+ js_reject_with_ruby_error(ctx, resolving_funcs);
714
+ }
715
+ else
716
+ {
717
+ JSValue j_result = JS_NewBool(ctx, RTEST(r_result));
718
+ JSValue ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1, (JSValueConst *)&j_result);
719
+ JS_FreeValue(ctx, ret);
720
+ }
721
+
722
+ JS_FreeValue(ctx, resolving_funcs[0]);
723
+ JS_FreeValue(ctx, resolving_funcs[1]);
724
+
725
+ return promise;
726
+ }
727
+
728
+ static VALUE r_subtle_derive_bits_call(VALUE r_args)
729
+ {
730
+ VALUE r_mod = rb_const_get(rb_const_get(rb_cObject, rb_intern("Quickjs")), rb_intern("SubtleCrypto"));
731
+ return rb_funcall(r_mod, rb_intern("derive_bits"), 4,
732
+ rb_ary_entry(r_args, 0),
733
+ rb_ary_entry(r_args, 1),
734
+ rb_ary_entry(r_args, 2),
735
+ rb_ary_entry(r_args, 3));
736
+ }
737
+
738
+ static JSValue js_subtle_derive_bits(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
739
+ {
740
+ if (argc < 3)
741
+ return JS_ThrowTypeError(ctx, "Failed to execute 'deriveBits': 3 arguments required.");
742
+
743
+ VALUE r_algo_hash = js_algo_to_ruby_hash(ctx, argv[0]);
744
+ VALUE r_name = rb_hash_aref(r_algo_hash, ID2SYM(rb_intern("name")));
745
+ if (NIL_P(r_name))
746
+ return JS_ThrowTypeError(ctx, "Failed to execute 'deriveBits': algorithm name is required.");
747
+
748
+ VALUE r_key = r_find_alive_crypto_key(ctx, argv[1]);
749
+ if (NIL_P(r_key))
750
+ return JS_ThrowTypeError(ctx, "Failed to execute 'deriveBits': invalid CryptoKey.");
751
+
752
+ int32_t length_bits = 0;
753
+ JS_ToInt32(ctx, &length_bits, argv[2]);
754
+
755
+ JSValue promise, resolving_funcs[2];
756
+ promise = JS_NewPromiseCapability(ctx, resolving_funcs);
757
+ if (JS_IsException(promise))
758
+ return JS_EXCEPTION;
759
+
760
+ VALUE r_args = rb_ary_new3(4, r_name, r_key, INT2NUM(length_bits), r_algo_hash);
761
+ int error_state;
762
+ VALUE r_result = rb_protect(r_subtle_derive_bits_call, r_args, &error_state);
763
+
764
+ if (error_state)
765
+ {
766
+ js_reject_with_ruby_error(ctx, resolving_funcs);
767
+ }
768
+ else
769
+ {
770
+ JSValue j_result = JS_NewArrayBufferCopy(ctx, (const uint8_t *)RSTRING_PTR(r_result), RSTRING_LEN(r_result));
771
+ JSValue ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1, (JSValueConst *)&j_result);
772
+ JS_FreeValue(ctx, j_result);
773
+ JS_FreeValue(ctx, ret);
774
+ }
775
+
776
+ JS_FreeValue(ctx, resolving_funcs[0]);
777
+ JS_FreeValue(ctx, resolving_funcs[1]);
778
+
779
+ return promise;
780
+ }
781
+
782
+ static VALUE r_subtle_derive_key_call(VALUE r_args)
783
+ {
784
+ VALUE r_mod = rb_const_get(rb_const_get(rb_cObject, rb_intern("Quickjs")), rb_intern("SubtleCrypto"));
785
+ return rb_funcall(r_mod, rb_intern("derive_key"), 6,
786
+ rb_ary_entry(r_args, 0),
787
+ rb_ary_entry(r_args, 1),
788
+ rb_ary_entry(r_args, 2),
789
+ rb_ary_entry(r_args, 3),
790
+ rb_ary_entry(r_args, 4),
791
+ rb_ary_entry(r_args, 5));
792
+ }
793
+
794
+ static JSValue js_subtle_derive_key(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
795
+ {
796
+ if (argc < 5)
797
+ return JS_ThrowTypeError(ctx, "Failed to execute 'deriveKey': 5 arguments required.");
798
+
799
+ VALUE r_algo_hash = js_algo_to_ruby_hash(ctx, argv[0]);
800
+ VALUE r_name = rb_hash_aref(r_algo_hash, ID2SYM(rb_intern("name")));
801
+ if (NIL_P(r_name))
802
+ return JS_ThrowTypeError(ctx, "Failed to execute 'deriveKey': algorithm name is required.");
803
+
804
+ VALUE r_key = r_find_alive_crypto_key(ctx, argv[1]);
805
+ if (NIL_P(r_key))
806
+ return JS_ThrowTypeError(ctx, "Failed to execute 'deriveKey': invalid CryptoKey.");
807
+
808
+ VALUE r_derived_algo_hash = js_algo_to_ruby_hash(ctx, argv[2]);
809
+ VALUE r_extractable = JS_ToBool(ctx, argv[3]) ? Qtrue : Qfalse;
810
+ VALUE r_usages = js_usages_to_ruby_array(ctx, argv[4]);
811
+
812
+ JSValue promise, resolving_funcs[2];
813
+ promise = JS_NewPromiseCapability(ctx, resolving_funcs);
814
+ if (JS_IsException(promise))
815
+ return JS_EXCEPTION;
816
+
817
+ VALUE r_args = rb_ary_new3(6, r_name, r_key, r_derived_algo_hash, r_extractable, r_usages, r_algo_hash);
818
+ int error_state;
819
+ VALUE r_result = rb_protect(r_subtle_derive_key_call, r_args, &error_state);
820
+
821
+ if (error_state)
822
+ {
823
+ js_reject_with_ruby_error(ctx, resolving_funcs);
824
+ }
825
+ else
826
+ {
827
+ JSValue j_result = js_crypto_key_to_js(ctx, r_result);
828
+ JSValue ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1, (JSValueConst *)&j_result);
829
+ JS_FreeValue(ctx, j_result);
830
+ JS_FreeValue(ctx, ret);
831
+ }
832
+
833
+ JS_FreeValue(ctx, resolving_funcs[0]);
834
+ JS_FreeValue(ctx, resolving_funcs[1]);
835
+
836
+ return promise;
837
+ }
838
+
839
+ static VALUE r_subtle_wrap_key_call(VALUE r_args)
840
+ {
841
+ VALUE r_mod = rb_const_get(rb_const_get(rb_cObject, rb_intern("Quickjs")), rb_intern("SubtleCrypto"));
842
+ return rb_funcall(r_mod, rb_intern("wrap_key"), 5,
843
+ rb_ary_entry(r_args, 0),
844
+ rb_ary_entry(r_args, 1),
845
+ rb_ary_entry(r_args, 2),
846
+ rb_ary_entry(r_args, 3),
847
+ rb_ary_entry(r_args, 4));
848
+ }
849
+
850
+ static JSValue js_subtle_wrap_key(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
851
+ {
852
+ if (argc < 4)
853
+ return JS_ThrowTypeError(ctx, "Failed to execute 'wrapKey': 4 arguments required.");
854
+
855
+ const char *format_cstr = JS_ToCString(ctx, argv[0]);
856
+ if (!format_cstr)
857
+ return JS_ThrowTypeError(ctx, "Failed to execute 'wrapKey': format must be a string.");
858
+ VALUE r_format = rb_str_new_cstr(format_cstr);
859
+ JS_FreeCString(ctx, format_cstr);
860
+
861
+ VALUE r_key = r_find_alive_crypto_key(ctx, argv[1]);
862
+ if (NIL_P(r_key))
863
+ return JS_ThrowTypeError(ctx, "Failed to execute 'wrapKey': invalid CryptoKey.");
864
+
865
+ VALUE r_wrapping_key = r_find_alive_crypto_key(ctx, argv[2]);
866
+ if (NIL_P(r_wrapping_key))
867
+ return JS_ThrowTypeError(ctx, "Failed to execute 'wrapKey': invalid wrapping CryptoKey.");
868
+
869
+ VALUE r_wrap_algo_hash = js_algo_to_ruby_hash(ctx, argv[3]);
870
+
871
+ JSValue promise, resolving_funcs[2];
872
+ promise = JS_NewPromiseCapability(ctx, resolving_funcs);
873
+ if (JS_IsException(promise))
874
+ return JS_EXCEPTION;
875
+
876
+ VALUE r_args = rb_ary_new3(5, r_format, r_key, r_wrapping_key, r_wrap_algo_hash,
877
+ rb_hash_aref(r_wrap_algo_hash, ID2SYM(rb_intern("name"))));
878
+ int error_state;
879
+ VALUE r_result = rb_protect(r_subtle_wrap_key_call, r_args, &error_state);
880
+
881
+ if (error_state)
882
+ {
883
+ js_reject_with_ruby_error(ctx, resolving_funcs);
884
+ }
885
+ else
886
+ {
887
+ JSValue j_result = JS_NewArrayBufferCopy(ctx, (const uint8_t *)RSTRING_PTR(r_result), RSTRING_LEN(r_result));
888
+ JSValue ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1, (JSValueConst *)&j_result);
889
+ JS_FreeValue(ctx, j_result);
890
+ JS_FreeValue(ctx, ret);
891
+ }
892
+
893
+ JS_FreeValue(ctx, resolving_funcs[0]);
894
+ JS_FreeValue(ctx, resolving_funcs[1]);
895
+
896
+ return promise;
897
+ }
898
+
899
+ static VALUE r_subtle_unwrap_key_call(VALUE r_args)
900
+ {
901
+ VALUE r_mod = rb_const_get(rb_const_get(rb_cObject, rb_intern("Quickjs")), rb_intern("SubtleCrypto"));
902
+ return rb_funcall(r_mod, rb_intern("unwrap_key"), 8,
903
+ rb_ary_entry(r_args, 0),
904
+ rb_ary_entry(r_args, 1),
905
+ rb_ary_entry(r_args, 2),
906
+ rb_ary_entry(r_args, 3),
907
+ rb_ary_entry(r_args, 4),
908
+ rb_ary_entry(r_args, 5),
909
+ rb_ary_entry(r_args, 6),
910
+ rb_ary_entry(r_args, 7));
911
+ }
912
+
913
+ static JSValue js_subtle_unwrap_key(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
914
+ {
915
+ if (argc < 7)
916
+ return JS_ThrowTypeError(ctx, "Failed to execute 'unwrapKey': 7 arguments required.");
917
+
918
+ const char *format_cstr = JS_ToCString(ctx, argv[0]);
919
+ if (!format_cstr)
920
+ return JS_ThrowTypeError(ctx, "Failed to execute 'unwrapKey': format must be a string.");
921
+ VALUE r_format = rb_str_new_cstr(format_cstr);
922
+ JS_FreeCString(ctx, format_cstr);
923
+
924
+ VALUE r_wrapped_key = js_buffer_to_ruby_str(ctx, argv[1]);
925
+ if (NIL_P(r_wrapped_key))
926
+ return JS_ThrowTypeError(ctx, "Failed to execute 'unwrapKey': wrapped key data must be an ArrayBuffer or TypedArray.");
927
+
928
+ VALUE r_unwrapping_key = r_find_alive_crypto_key(ctx, argv[2]);
929
+ if (NIL_P(r_unwrapping_key))
930
+ return JS_ThrowTypeError(ctx, "Failed to execute 'unwrapKey': invalid unwrapping CryptoKey.");
931
+
932
+ VALUE r_unwrap_algo_hash = js_algo_to_ruby_hash(ctx, argv[3]);
933
+ VALUE r_unwrapped_algo_hash = js_algo_to_ruby_hash(ctx, argv[4]);
934
+ VALUE r_extractable = JS_ToBool(ctx, argv[5]) ? Qtrue : Qfalse;
935
+ VALUE r_usages = js_usages_to_ruby_array(ctx, argv[6]);
936
+
937
+ JSValue promise, resolving_funcs[2];
938
+ promise = JS_NewPromiseCapability(ctx, resolving_funcs);
939
+ if (JS_IsException(promise))
940
+ return JS_EXCEPTION;
941
+
942
+ VALUE r_args = rb_ary_new();
943
+ rb_ary_push(r_args, r_format);
944
+ rb_ary_push(r_args, r_wrapped_key);
945
+ rb_ary_push(r_args, r_unwrapping_key);
946
+ rb_ary_push(r_args, r_unwrap_algo_hash);
947
+ rb_ary_push(r_args, r_unwrapped_algo_hash);
948
+ rb_ary_push(r_args, r_extractable);
949
+ rb_ary_push(r_args, r_usages);
950
+ rb_ary_push(r_args, rb_hash_aref(r_unwrap_algo_hash, ID2SYM(rb_intern("name"))));
951
+
952
+ int error_state;
953
+ VALUE r_result = rb_protect(r_subtle_unwrap_key_call, r_args, &error_state);
954
+
955
+ if (error_state)
956
+ {
957
+ js_reject_with_ruby_error(ctx, resolving_funcs);
958
+ }
959
+ else
960
+ {
961
+ JSValue j_result = js_crypto_key_to_js(ctx, r_result);
962
+ JSValue ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1, (JSValueConst *)&j_result);
963
+ JS_FreeValue(ctx, j_result);
964
+ JS_FreeValue(ctx, ret);
965
+ }
966
+
967
+ JS_FreeValue(ctx, resolving_funcs[0]);
968
+ JS_FreeValue(ctx, resolving_funcs[1]);
969
+
970
+ return promise;
971
+ }
972
+
973
+ void quickjsrb_init_crypto_subtle(JSContext *ctx, JSValueConst j_crypto)
974
+ {
975
+ JSValue j_subtle = JS_NewObject(ctx);
976
+ JS_SetPropertyStr(ctx, j_subtle, "digest",
977
+ JS_NewCFunction(ctx, js_subtle_digest, "digest", 2));
978
+ JS_SetPropertyStr(ctx, j_subtle, "generateKey",
979
+ JS_NewCFunction(ctx, js_subtle_generate_key, "generateKey", 3));
980
+ JS_SetPropertyStr(ctx, j_subtle, "importKey",
981
+ JS_NewCFunction(ctx, js_subtle_import_key, "importKey", 5));
982
+ JS_SetPropertyStr(ctx, j_subtle, "exportKey",
983
+ JS_NewCFunction(ctx, js_subtle_export_key, "exportKey", 2));
984
+ JS_SetPropertyStr(ctx, j_subtle, "encrypt",
985
+ JS_NewCFunction(ctx, js_subtle_encrypt, "encrypt", 3));
986
+ JS_SetPropertyStr(ctx, j_subtle, "decrypt",
987
+ JS_NewCFunction(ctx, js_subtle_decrypt, "decrypt", 3));
988
+ JS_SetPropertyStr(ctx, j_subtle, "sign",
989
+ JS_NewCFunction(ctx, js_subtle_sign, "sign", 3));
990
+ JS_SetPropertyStr(ctx, j_subtle, "verify",
991
+ JS_NewCFunction(ctx, js_subtle_verify, "verify", 4));
992
+ JS_SetPropertyStr(ctx, j_subtle, "deriveBits",
993
+ JS_NewCFunction(ctx, js_subtle_derive_bits, "deriveBits", 3));
994
+ JS_SetPropertyStr(ctx, j_subtle, "deriveKey",
995
+ JS_NewCFunction(ctx, js_subtle_derive_key, "deriveKey", 5));
996
+ JS_SetPropertyStr(ctx, j_subtle, "wrapKey",
997
+ JS_NewCFunction(ctx, js_subtle_wrap_key, "wrapKey", 4));
998
+ JS_SetPropertyStr(ctx, j_subtle, "unwrapKey",
999
+ JS_NewCFunction(ctx, js_subtle_unwrap_key, "unwrapKey", 7));
1000
+ JS_SetPropertyStr(ctx, j_crypto, "subtle", j_subtle);
1001
+ }