fix(uuid): validate namespace UUIDs in v3.generate() and v5.generate() (#4874)

* fix(uuid): validate namespace UUIDs

* update

* revert

* tweak

* tweaks
This commit is contained in:
Asher Gomez 2024-05-29 19:09:30 +10:00 committed by GitHub
parent 5ffeab756e
commit bd7c465ccb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 30 additions and 25 deletions

View File

@ -3,8 +3,8 @@
import { bytesToUuid, uuidToBytes } from "./_common.ts";
import { concat } from "@std/bytes/concat";
import { assert } from "@std/assert/assert";
import { crypto } from "@std/crypto/crypto";
import { validate as validateCommon } from "./common.ts";
const UUID_RE =
/^[0-9a-f]{8}-[0-9a-f]{4}-[3][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
@ -39,6 +39,8 @@ export function validate(id: string): boolean {
*
* @returns A UUIDv3 string.
*
* @throws {TypeError} If the namespace is not a valid UUID.
*
* @example Usage
* ```ts
* import { NAMESPACE_URL } from "@std/uuid/constants";
@ -55,11 +57,10 @@ export async function generate(
namespace: string,
data: Uint8Array,
): Promise<string> {
// TODO(lino-levan): validate that `namespace` is a valid UUID.
if (!validateCommon(namespace)) {
throw new TypeError("Invalid namespace UUID");
}
const space = uuidToBytes(namespace);
assert(space.length === 16, "namespace must be a valid UUID");
const toHash = concat([new Uint8Array(space), data]);
const buffer = await crypto.subtle.digest("MD5", toHash);
const bytes = new Uint8Array(buffer);

View File

@ -1,10 +1,5 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import {
assert,
assertEquals,
AssertionError,
assertRejects,
} from "@std/assert";
import { assert, assertEquals, assertRejects } from "@std/assert";
import { generate, validate } from "./v3.ts";
const NAMESPACE = "1b671a64-40d5-491e-99b0-da01ff1f3341";
@ -46,7 +41,13 @@ Deno.test("validate() checks if a string is a valid v3 UUID", async () => {
Deno.test("generate() throws on invalid namespace", async () => {
await assertRejects(
async () => await generate("invalid-uuid", new Uint8Array()),
AssertionError,
"namespace must be a valid UUID",
TypeError,
"Invalid namespace UUID",
);
await assertRejects(
async () =>
await generate("1b671a64-40d5-491e-99b0-da01ff1f334Z", new Uint8Array()),
TypeError,
"Invalid namespace UUID",
);
});

View File

@ -3,7 +3,7 @@
import { bytesToUuid, uuidToBytes } from "./_common.ts";
import { concat } from "@std/bytes/concat";
import { assert } from "@std/assert/assert";
import { validate as validateCommon } from "./common.ts";
const UUID_RE =
/^[0-9a-f]{8}-[0-9a-f]{4}-[5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
@ -38,6 +38,8 @@ export function validate(id: string): boolean {
*
* @returns A UUIDv5 string.
*
* @throws {TypeError} If the namespace is not a valid UUID.
*
* @example Usage
* ```ts
* import { NAMESPACE_URL } from "@std/uuid/constants";
@ -54,11 +56,11 @@ export async function generate(
namespace: string,
data: Uint8Array,
): Promise<string> {
// TODO(lucacasonato): validate that `namespace` is a valid UUID.
if (!validateCommon(namespace)) {
throw new TypeError("Invalid namespace UUID");
}
const space = uuidToBytes(namespace);
assert(space.length === 16, "namespace must be a valid UUID");
const toHash = concat([new Uint8Array(space), data]);
const buffer = await crypto.subtle.digest("sha-1", toHash);
const bytes = new Uint8Array(buffer);

View File

@ -1,10 +1,5 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import {
assert,
assertEquals,
AssertionError,
assertRejects,
} from "@std/assert";
import { assert, assertEquals, assertRejects } from "@std/assert";
import { generate, validate } from "./v5.ts";
const NAMESPACE = "1b671a64-40d5-491e-99b0-da01ff1f3341";
@ -46,7 +41,13 @@ Deno.test("validate() checks if a string is a valid v5 UUID", async () => {
Deno.test("generate() throws on invalid namespace", async () => {
await assertRejects(
async () => await generate("invalid-uuid", new Uint8Array()),
AssertionError,
"namespace must be a valid UUID",
TypeError,
"Invalid namespace UUID",
);
await assertRejects(
async () =>
await generate("1b671a64-40d5-491e-99b0-da01ff1f334Z", new Uint8Array()),
TypeError,
"Invalid namespace UUID",
);
});