summaryrefslogtreecommitdiff
path: root/ext/node/polyfills/internal/crypto/_randomFill.mjs
blob: 8ef864562fd6529414d9c3e9c8c72190a3771e0d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

// TODO(petamoriken): enable prefer-primordials for node polyfills
// deno-lint-ignore-file prefer-primordials

import { op_node_fill_random, op_node_fill_random_async } from "ext:core/ops";

import { MAX_SIZE as kMaxUint32 } from "ext:deno_node/internal/crypto/_randomBytes.ts";
import { Buffer } from "node:buffer";
import { isAnyArrayBuffer, isArrayBufferView } from "node:util/types";
import { ERR_INVALID_ARG_TYPE } from "ext:deno_node/internal/errors.ts";

const kBufferMaxLength = 0x7fffffff;

function assertOffset(offset, length) {
  if (offset > kMaxUint32 || offset < 0) {
    throw new TypeError("offset must be a uint32");
  }

  if (offset > kBufferMaxLength || offset > length) {
    throw new RangeError("offset out of range");
  }
}

function assertSize(size, offset, length) {
  if (size > kMaxUint32 || size < 0) {
    throw new TypeError("size must be a uint32");
  }

  if (size + offset > length || size > kBufferMaxLength) {
    throw new RangeError("buffer too small");
  }
}

export default function randomFill(buf, offset, size, cb) {
  if (typeof offset === "function") {
    cb = offset;
    offset = 0;
    size = buf.length;
  } else if (typeof size === "function") {
    cb = size;
    size = buf.length - Number(offset);
  }

  assertOffset(offset, buf.length);
  assertSize(size, offset, buf.length);

  op_node_fill_random_async(Math.floor(size)).then((randomData) => {
    const randomBuf = Buffer.from(randomData.buffer);
    randomBuf.copy(buf, offset, 0, size);
    cb(null, buf);
  });
}

export function randomFillSync(buf, offset = 0, size) {
  if (!isAnyArrayBuffer(buf) && !isArrayBufferView(buf)) {
    throw new ERR_INVALID_ARG_TYPE(
      "buf",
      ["ArrayBuffer", "ArrayBufferView"],
      buf,
    );
  }

  assertOffset(offset, buf.byteLength);

  if (size === undefined) {
    size = buf.byteLength - offset;
  } else {
    assertSize(size, offset, buf.byteLength);
  }

  if (size === 0) {
    return buf;
  }

  const bytes = isAnyArrayBuffer(buf)
    ? new Uint8Array(buf, offset, size)
    : new Uint8Array(buf.buffer, buf.byteOffset + offset, size);
  op_node_fill_random(bytes);

  return buf;
}