Skip to content

Commit

Permalink
fix(uuid): validate namespace UUIDs in v3.generate() and `v5.genera…
Browse files Browse the repository at this point in the history
…te()` (#4874)

* fix(uuid): validate namespace UUIDs

* update

* revert

* tweak

* tweaks
  • Loading branch information
iuioiua authored May 29, 2024
1 parent 5ffeab7 commit bd7c465
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 25 deletions.
11 changes: 6 additions & 5 deletions uuid/v3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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";
Expand All @@ -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);
Expand Down
17 changes: 9 additions & 8 deletions uuid/v3_test.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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",
);
});
10 changes: 6 additions & 4 deletions uuid/v5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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";
Expand All @@ -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);
Expand Down
17 changes: 9 additions & 8 deletions uuid/v5_test.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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",
);
});

0 comments on commit bd7c465

Please sign in to comment.