njs_value_t *retval);
static njs_int_t njs_ext_get_random_values(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused, njs_value_t *retval);
+static njs_int_t njs_ext_random_uuid(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused, njs_value_t *retval);
static njs_webcrypto_key_t *njs_webcrypto_key_alloc(njs_vm_t *vm,
njs_webcrypto_algorithm_t *alg, unsigned usage, njs_bool_t extractable);
}
},
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("randomUUID"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = njs_ext_random_uuid,
+ }
+ },
+
{
.flags = NJS_EXTERN_OBJECT,
.name.string = njs_str("subtle"),
}
+static njs_int_t
+njs_ext_random_uuid(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused, njs_value_t *retval)
+{
+ u_char *p;
+ njs_uint_t i;
+ u_char bytes[16], buf[36];
+
+ static const u_char hex[] = "0123456789abcdef";
+
+ if (RAND_bytes(bytes, 16) != 1) {
+ njs_webcrypto_error(vm, "RAND_bytes() failed");
+ return NJS_ERROR;
+ }
+
+ bytes[6] = (bytes[6] & 0x0f) | 0x40;
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
+
+ p = buf;
+
+ for (i = 0; i < 16; i++) {
+ *p++ = hex[bytes[i] >> 4];
+ *p++ = hex[bytes[i] & 0x0f];
+
+ if (i == 3 || i == 5 || i == 7 || i == 9) {
+ *p++ = '-';
+ }
+ }
+
+ return njs_vm_value_string_create(vm, retval, buf, sizeof(buf));
+}
+
+
static void
njs_webcrypto_cleanup_pkey(void *data)
{
static JSValue qjs_get_random_values(JSContext *cx, JSValueConst this_val,
int argc, JSValueConst *argv);
+static JSValue qjs_random_uuid(JSContext *cx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
static JSValue qjs_webcrypto_key_make(JSContext *cx,
qjs_webcrypto_algorithm_t *alg, unsigned usage, int extractable);
static const JSCFunctionListEntry qjs_webcrypto_export[] = {
JS_CFUNC_DEF("getRandomValues", 1, qjs_get_random_values),
+ JS_CFUNC_DEF("randomUUID", 0, qjs_random_uuid),
JS_OBJECT_DEF("subtle",
qjs_webcrypto_subtle,
njs_nitems(qjs_webcrypto_subtle),
}
+static JSValue
+qjs_random_uuid(JSContext *cx, JSValueConst this_val, int argc,
+ JSValueConst *argv)
+{
+ u_char *p;
+ uint32_t i;
+ u_char bytes[16], buf[36];
+
+ static const u_char hex[] = "0123456789abcdef";
+
+ if (RAND_bytes(bytes, 16) != 1) {
+ qjs_webcrypto_error(cx, "RAND_bytes() failed");
+ return JS_EXCEPTION;
+ }
+
+ bytes[6] = (bytes[6] & 0x0f) | 0x40;
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
+
+ p = buf;
+
+ for (i = 0; i < 16; i++) {
+ *p++ = hex[bytes[i] >> 4];
+ *p++ = hex[bytes[i] & 0x0f];
+
+ if (i == 3 || i == 5 || i == 7 || i == 9) {
+ *p++ = '-';
+ }
+ }
+
+ return JS_NewStringLen(cx, (const char *) buf, sizeof(buf));
+}
+
+
static JSValue
qjs_webcrypto_key_make(JSContext *cx, qjs_webcrypto_algorithm_t *alg,
unsigned usage, int extractable)
--- /dev/null
+/*---
+includes: [compatWebcrypto.js, runTsuite.js]
+flags: [async]
+---*/
+
+async function test(params) {
+ let uuid = crypto.randomUUID();
+
+ if (typeof uuid !== 'string') {
+ throw Error(`randomUUID returned ${typeof uuid}, expected string`);
+ }
+
+ if (uuid.length !== 36) {
+ throw Error(`randomUUID length ${uuid.length}, expected 36`);
+ }
+
+ let re = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
+ if (!re.test(uuid)) {
+ throw Error(`randomUUID format invalid: "${uuid}"`);
+ }
+
+ let uuid2 = crypto.randomUUID();
+
+ if (uuid === uuid2) {
+ throw Error(`randomUUID not unique: "${uuid}" === "${uuid2}"`);
+ }
+
+ if (!re.test(uuid2)) {
+ throw Error(`randomUUID second call format invalid: "${uuid2}"`);
+ }
+
+ return 'SUCCESS';
+}
+
+let randomUUID_tsuite = {
+ name: "crypto.randomUUID()",
+ skip: () => (!has_webcrypto()),
+ T: test,
+ prepare_args: (args) => args,
+
+ tests: [
+ { },
+]};
+
+run([randomUUID_tsuite])
+.then($DONE, $DONE);
interface Crypto {
readonly subtle: SubtleCrypto;
getRandomValues(ta:TypedArray): TypedArray;
+ randomUUID(): string;
}
declare const crypto: Crypto;