diff --git a/src/js/internal/http.ts b/src/js/internal/http.ts index a910b7ecd5..7317f1da6e 100644 --- a/src/js/internal/http.ts +++ b/src/js/internal/http.ts @@ -1,5 +1,3 @@ -const { isTypedArray, isArrayBuffer } = require("node:util/types"); - const { getHeader, setHeader, @@ -195,19 +193,6 @@ function validateMsecs(numberlike: any, field: string) { return numberlike; } -function isValidTLSArray(obj) { - if (typeof obj === "string" || isTypedArray(obj) || isArrayBuffer(obj) || $inheritsBlob(obj)) return true; - if (Array.isArray(obj)) { - const length = obj.length; - for (var i = 0; i < length; i++) { - const item = obj[i]; - if (typeof item !== "string" && !isTypedArray(item) && !isArrayBuffer(item) && !$inheritsBlob(item)) return false; // prettier-ignore - } - return true; - } - return false; -} - class ConnResetException extends Error { constructor(msg) { super(msg); @@ -367,83 +352,82 @@ function emitErrorNt(msg, err, callback) { } export { - kDeprecatedReplySymbol, - kBodyChunks, - kPath, - kPort, - kMethod, - kHost, - kProtocol, - kAgent, - kFetchRequest, - kTls, - kUseDefaultPort, - kRes, - kUpgradeOrConnect, - kParser, - kMaxHeadersCount, - kReusedSocket, - kTimeoutTimer, - kOptions, - kSocketPath, - kSignal, - kMaxHeaderSize, abortedSymbol, - kClearTimeout, - emitErrorNextTickIfErrorListenerNT, - headerStateSymbol, - kEmitState, + assignHeadersFast, bodyStreamSymbol, - controllerSymbol, - runSymbol, - deferredSymbol, - eofInProgress, - fakeSocketSymbol, - firstWriteSymbol, - headersSymbol, - isTlsSymbol, - kHandle, - kRealListen, - noBodySymbol, - optionsSymbol, - reqSymbol, - timeoutTimerSymbol, - tlsSymbol, - typeSymbol, - webRequestOrResponse, - statusCodeSymbol, - kAbortController, - statusMessageSymbol, - kInternalSocketData, - serverSymbol, - kPendingCallbacks, - kRequest, - kCloseCallback, - kDeferredTimeouts, - isAbortError, - kEmptyObject, - getIsNextIncomingMessageHTTPS, - setIsNextIncomingMessageHTTPS, callCloseCallback, + ConnResetException, + controllerSymbol, + deferredSymbol, + drainMicrotasks, emitCloseNT, emitCloseNTAndComplete, emitEOFIncomingMessage, - validateMsecs, - isValidTLSArray, - ConnResetException, - METHODS, - STATUS_CODES, - hasServerResponseFinished, - getHeader, - setHeader, - Headers, - assignHeadersFast, - setRequestTimeout, - headersTuple, - webRequestOrResponseHasBodyValue, + emitErrorNextTickIfErrorListenerNT, + eofInProgress, + fakeSocketSymbol, + firstWriteSymbol, getCompleteWebRequestOrResponseBodyValueAsArrayBuffer, - drainMicrotasks, - setServerIdleTimeout, + getHeader, + getIsNextIncomingMessageHTTPS, getRawKeys, + hasServerResponseFinished, + Headers, + headersSymbol, + headerStateSymbol, + headersTuple, + isAbortError, + isTlsSymbol, + kAbortController, + kAgent, + kBodyChunks, + kClearTimeout, + kCloseCallback, + kDeferredTimeouts, + kDeprecatedReplySymbol, + kEmitState, + kEmptyObject, + kFetchRequest, + kHandle, + kHost, + kInternalSocketData, + kMaxHeadersCount, + kMaxHeaderSize, + kMethod, + kOptions, + kParser, + kPath, + kPendingCallbacks, + kPort, + kProtocol, + kRealListen, + kRequest, + kRes, + kReusedSocket, + kSignal, + kSocketPath, + kTimeoutTimer, + kTls, + kUpgradeOrConnect, + kUseDefaultPort, + METHODS, + noBodySymbol, + optionsSymbol, + reqSymbol, + runSymbol, + serverSymbol, + setHeader, + setIsNextIncomingMessageHTTPS, + setRequestTimeout, setRequireHostHeader, + setServerIdleTimeout, + STATUS_CODES, + statusCodeSymbol, + statusMessageSymbol, + timeoutTimerSymbol, + tlsSymbol, + typeSymbol, + validateMsecs, + webRequestOrResponse, + webRequestOrResponseHasBodyValue, }; diff --git a/src/js/internal/tls.ts b/src/js/internal/tls.ts new file mode 100644 index 0000000000..63b04b7e3f --- /dev/null +++ b/src/js/internal/tls.ts @@ -0,0 +1,53 @@ +const { isTypedArray, isArrayBuffer } = require("node:util/types"); + +function isPemObject(obj: unknown): obj is { pem: unknown } { + return $isObject(obj) && "pem" in obj; +} + +function isPemArray(obj: unknown): obj is [{ pem: unknown }] { + // if (obj instanceof Object && "pem" in obj) return isValidTLSArray(obj.pem); + return $isArray(obj) && obj.every(isPemObject); +} + +function isValidTLSItem(obj: unknown) { + if (typeof obj === "string" || isTypedArray(obj) || isArrayBuffer(obj) || $inheritsBlob(obj) || isPemArray(obj)) { + return true; + } + + return false; +} + +function findInvalidTLSItem(obj: unknown) { + if ($isArray(obj)) { + for (var i = 0, length = obj.length; i < length; i++) { + const item = obj[i]; + if (!isValidTLSItem(item)) return item; + } + } + return obj; +} + +function throwOnInvalidTLSArray(name: string, value: unknown) { + if (!isValidTLSArray(value)) { + throw $ERR_INVALID_ARG_TYPE(name, VALID_TLS_ERROR_MESSAGE_TYPES, findInvalidTLSItem(value)); + } +} + +function isValidTLSArray(obj: unknown) { + if (isValidTLSItem(obj)) return true; + + if ($isArray(obj)) { + for (var i = 0, length = obj.length; i < length; i++) { + const item = obj[i]; + if (!isValidTLSItem(item)) return false; + } + + return true; + } + + return false; +} + +const VALID_TLS_ERROR_MESSAGE_TYPES = "string or an instance of Buffer, TypedArray, DataView, or BunFile"; + +export { isValidTLSArray, isValidTLSItem, throwOnInvalidTLSArray, VALID_TLS_ERROR_MESSAGE_TYPES }; diff --git a/src/js/node/_http_client.ts b/src/js/node/_http_client.ts index 3b49c3ceab..d99931f8e8 100644 --- a/src/js/node/_http_client.ts +++ b/src/js/node/_http_client.ts @@ -2,6 +2,7 @@ const { isIP, isIPv6 } = require("node:net"); const { checkIsHttpToken, validateFunction, validateInteger, validateBoolean } = require("internal/validators"); const { urlToHttpOptions } = require("internal/url"); +const { isValidTLSArray } = require("internal/tls"); const { kBodyChunks, abortedSymbol, @@ -39,7 +40,6 @@ const { callCloseCallback, emitCloseNTAndComplete, validateMsecs, - isValidTLSArray, ConnResetException, } = require("internal/http"); diff --git a/src/js/node/_http_server.ts b/src/js/node/_http_server.ts index 0cbc6842bd..1c1abfeb38 100644 --- a/src/js/node/_http_server.ts +++ b/src/js/node/_http_server.ts @@ -3,7 +3,7 @@ const { Duplex, Stream } = require("node:stream"); const { validateObject, validateLinkHeaderValue, validateBoolean, validateInteger } = require("internal/validators"); const { isPrimary } = require("internal/cluster/isPrimary"); - +const { throwOnInvalidTLSArray } = require("internal/tls"); const { kInternalSocketData, serverSymbol, @@ -25,7 +25,6 @@ const { setIsNextIncomingMessageHTTPS, callCloseCallback, emitCloseNT, - isValidTLSArray, ConnResetException, NodeHTTPResponseAbortEvent, STATUS_CODES, @@ -601,47 +600,38 @@ const Server = function Server(options, callback) { } else { validateObject(options, "options"); options = { ...options }; - let key = options.key; - if (key) { - if (!isValidTLSArray(key)) { - throw new TypeError( - "key argument must be a string, Buffer, TypedArray or BunFile, or an array containing string, Buffer, TypedArray or BunFile", - ); - } - this[isTlsSymbol] = true; - } + let cert = options.cert; if (cert) { - if (!isValidTLSArray(cert)) { - throw new TypeError( - "cert argument must be a string, Buffer, TypedArray or BunFile, or an array containing string, Buffer, TypedArray or BunFile", - ); - } + throwOnInvalidTLSArray("options.cert", cert); + this[isTlsSymbol] = true; + } + + let key = options.key; + if (key) { + throwOnInvalidTLSArray("options.key", key); this[isTlsSymbol] = true; } let ca = options.ca; if (ca) { - if (!isValidTLSArray(ca)) { - throw new TypeError( - "ca argument must be a string, Buffer, TypedArray or BunFile, or an array containing string, Buffer, TypedArray or BunFile", - ); - } + throwOnInvalidTLSArray("options.ca", ca); this[isTlsSymbol] = true; } + let passphrase = options.passphrase; if (passphrase && typeof passphrase !== "string") { - throw new TypeError("passphrase argument must be a string"); + throw $ERR_INVALID_ARG_TYPE("options.passphrase", "string", passphrase); } let serverName = options.servername; if (serverName && typeof serverName !== "string") { - throw new TypeError("serverName argument must be a string"); + throw $ERR_INVALID_ARG_TYPE("options.servername", "string", serverName); } let secureOptions = options.secureOptions || 0; if (secureOptions && typeof secureOptions !== "number") { - throw new TypeError("secureOptions argument must be an number"); + throw $ERR_INVALID_ARG_TYPE("options.secureOptions", "number", secureOptions); } if (this[isTlsSymbol]) { diff --git a/src/js/node/tls.ts b/src/js/node/tls.ts index 66fe91de39..6a4c751c54 100644 --- a/src/js/node/tls.ts +++ b/src/js/node/tls.ts @@ -1,9 +1,10 @@ // Hardcoded module "node:tls" -const { isArrayBufferView, isArrayBuffer, isTypedArray } = require("node:util/types"); +const { isArrayBufferView, isTypedArray } = require("node:util/types"); const net = require("node:net"); const { Duplex } = require("node:stream"); const { addServerName } = require("internal/net"); const { throwNotImplemented } = require("internal/shared"); +const { throwOnInvalidTLSArray } = require("internal/tls"); const { Server: NetServer, Socket: NetSocket } = net; @@ -37,17 +38,6 @@ function parseCertString() { const rejectUnauthorizedDefault = process.env.NODE_TLS_REJECT_UNAUTHORIZED !== "0" && process.env.NODE_TLS_REJECT_UNAUTHORIZED !== "false"; -function isValidTLSArray(obj) { - if (typeof obj === "string" || isTypedArray(obj) || isArrayBuffer(obj) || $inheritsBlob(obj)) return true; - if (Array.isArray(obj)) { - for (var i = 0; i < obj.length; i++) { - const item = obj[i]; - if (typeof item !== "string" && !isTypedArray(item) && !isArrayBuffer(item) && !$inheritsBlob(item)) return false; - } - return true; - } - return false; -} function unfqdn(host) { return RegExpPrototypeSymbolReplace.$call(/[.]$/, host, ""); @@ -215,33 +205,23 @@ var InternalSecureContext = class SecureContext { constructor(options) { const context = {}; + if (options) { - let key = options.key; - if (key) { - if (!isValidTLSArray(key)) { - throw new TypeError( - "key argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", - ); - } - this.key = key; - } let cert = options.cert; if (cert) { - if (!isValidTLSArray(cert)) { - throw new TypeError( - "cert argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", - ); - } + throwOnInvalidTLSArray("options.cert", cert); this.cert = cert; } + let key = options.key; + if (key) { + throwOnInvalidTLSArray("options.key", key); + this.key = key; + } + let ca = options.ca; if (ca) { - if (!isValidTLSArray(ca)) { - throw new TypeError( - "ca argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", - ); - } + throwOnInvalidTLSArray("options.ca", ca); this.ca = ca; } @@ -536,50 +516,39 @@ function Server(options, secureConnectionListener): void { convertALPNProtocols(ALPNProtocols, this); } - let key = options.key; - if (key) { - if (!isValidTLSArray(key)) { - throw new TypeError( - "key argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", - ); - } - this.key = key; - } let cert = options.cert; if (cert) { - if (!isValidTLSArray(cert)) { - throw new TypeError( - "cert argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", - ); - } + throwOnInvalidTLSArray("options.cert", cert); this.cert = cert; } + let key = options.key; + if (key) { + throwOnInvalidTLSArray("options.key", key); + this.key = key; + } + let ca = options.ca; if (ca) { - if (!isValidTLSArray(ca)) { - throw new TypeError( - "ca argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", - ); - } + throwOnInvalidTLSArray("options.ca", ca); this.ca = ca; } let passphrase = options.passphrase; if (passphrase && typeof passphrase !== "string") { - throw new TypeError("passphrase argument must be an string"); + throw $ERR_INVALID_ARG_TYPE("options.passphrase", "string", passphrase); } this.passphrase = passphrase; let servername = options.servername; if (servername && typeof servername !== "string") { - throw new TypeError("servername argument must be an string"); + throw $ERR_INVALID_ARG_TYPE("options.servername", "string", servername); } this.servername = servername; let secureOptions = options.secureOptions || 0; if (secureOptions && typeof secureOptions !== "number") { - throw new TypeError("secureOptions argument must be an number"); + throw $ERR_INVALID_ARG_TYPE("options.secureOptions", "number", secureOptions); } this.secureOptions = secureOptions; diff --git a/test/js/node/test/parallel/test-https-options-boolean-check.js b/test/js/node/test/parallel/test-https-options-boolean-check.js new file mode 100644 index 0000000000..8ee2ebc993 --- /dev/null +++ b/test/js/node/test/parallel/test-https-options-boolean-check.js @@ -0,0 +1,154 @@ +const common = require('../common'); +const fixtures = require('../common/fixtures'); + +if (!common.hasCrypto) + common.skip('missing crypto'); + +const assert = require('assert'); +const https = require('https'); + +function toArrayBuffer(buf) { + const ab = new ArrayBuffer(buf.length); + const view = new Uint8Array(ab); + return buf.map((b, i) => view[i] = b); +} + +function toDataView(buf) { + const ab = new ArrayBuffer(buf.length); + const view = new DataView(ab); + return buf.map((b, i) => view[i] = b); +} + +const keyBuff = fixtures.readKey('agent1-key.pem'); +const certBuff = fixtures.readKey('agent1-cert.pem'); +const keyBuff2 = fixtures.readKey('ec-key.pem'); +const certBuff2 = fixtures.readKey('ec-cert.pem'); +const caCert = fixtures.readKey('ca1-cert.pem'); +const caCert2 = fixtures.readKey('ca2-cert.pem'); +const keyStr = keyBuff.toString(); +const certStr = certBuff.toString(); +const keyStr2 = keyBuff2.toString(); +const certStr2 = certBuff2.toString(); +const caCertStr = caCert.toString(); +const caCertStr2 = caCert2.toString(); +const keyArrBuff = toArrayBuffer(keyBuff); +const certArrBuff = toArrayBuffer(certBuff); +const caArrBuff = toArrayBuffer(caCert); +const keyDataView = toDataView(keyBuff); +const certDataView = toDataView(certBuff); +const caArrDataView = toDataView(caCert); + +// Checks to ensure https.createServer doesn't throw an error +// Format ['key', 'cert'] +[ + [keyBuff, certBuff], + [false, certBuff], + [keyBuff, false], + [keyStr, certStr], + [false, certStr], + [keyStr, false], + [false, false], + [keyArrBuff, certArrBuff], + [keyArrBuff, false], + [false, certArrBuff], + [keyDataView, certDataView], + [keyDataView, false], + [false, certDataView], + [[keyBuff, keyBuff2], [certBuff, certBuff2]], + [[keyStr, keyStr2], [certStr, certStr2]], + [[keyStr, keyStr2], false], + [false, [certStr, certStr2]], + [[{ pem: keyBuff }], false], + [[{ pem: keyBuff }, { pem: keyBuff }], false], +].forEach(([key, cert]) => { + https.createServer({ key, cert }); +}); + +// Checks to ensure https.createServer predictably throws an error +// Format ['key', 'cert', 'expected message'] +[ + [true, certBuff], + [true, certStr], + [true, certArrBuff], + [true, certDataView], + [true, false], + [true, false], + [{ pem: keyBuff }, false], + [1, false], + [[keyBuff, true], [certBuff, certBuff2], 1], + [[true, keyStr2], [certStr, certStr2], 0], + [[true, false], [certBuff, certBuff2], 0], + [true, [certBuff, certBuff2]], +].forEach(([key, cert, index]) => { + const val = index === undefined ? key : key[index]; + assert.throws(() => { + https.createServer({ key, cert }); + }, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "options.key" property must be of type string or an ' + + 'instance of Buffer, TypedArray, DataView, or BunFile.' + + common.invalidArgTypeHelper(val) + }); +}); + +[ + [keyBuff, true], + [keyStr, true], + [keyArrBuff, true], + [keyDataView, true], + [true, true], + [false, true], + [false, { pem: keyBuff }], + [false, 1], + [[keyBuff, keyBuff2], [true, certBuff2], 0], + [[keyStr, keyStr2], [certStr, true], 1], + [[keyStr, keyStr2], [true, false], 0], + [[keyStr, keyStr2], true], +].forEach(([key, cert, index]) => { + const val = index === undefined ? cert : cert[index]; + assert.throws(() => { + https.createServer({ key, cert }); + }, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "options.cert" property must be of type string or an ' + + 'instance of Buffer, TypedArray, DataView, or BunFile.' + + common.invalidArgTypeHelper(val) + }); +}); + +// Checks to ensure https.createServer works with the CA parameter +// Format ['key', 'cert', 'ca'] +[ + [keyBuff, certBuff, caCert], + [keyBuff, certBuff, [caCert, caCert2]], + [keyBuff, certBuff, caCertStr], + [keyBuff, certBuff, [caCertStr, caCertStr2]], + [keyBuff, certBuff, caArrBuff], + [keyBuff, certBuff, caArrDataView], + [keyBuff, certBuff, false], +].forEach(([key, cert, ca]) => { + https.createServer({ key, cert, ca }); +}); + +// Checks to ensure https.createServer throws an error for CA assignment +// Format ['key', 'cert', 'ca'] +[ + [keyBuff, certBuff, true], + [keyBuff, certBuff, {}], + [keyBuff, certBuff, 1], + [keyBuff, certBuff, true], + [keyBuff, certBuff, [caCert, true], 1], +].forEach(([key, cert, ca, index]) => { + const val = index === undefined ? ca : ca[index]; + assert.throws(() => { + https.createServer({ key, cert, ca }); + }, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "options.ca" property must be of type string or an instance' + + ' of Buffer, TypedArray, DataView, or BunFile.' + + common.invalidArgTypeHelper(val) + }); +}); \ No newline at end of file diff --git a/test/js/node/test/parallel/test-tls-options-boolean-check.js b/test/js/node/test/parallel/test-tls-options-boolean-check.js new file mode 100644 index 0000000000..9a23d1db8a --- /dev/null +++ b/test/js/node/test/parallel/test-tls-options-boolean-check.js @@ -0,0 +1,167 @@ +'use strict'; + +const common = require('../common'); +const fixtures = require('../common/fixtures'); + +if (!common.hasCrypto) + common.skip('missing crypto'); + +const assert = require('assert'); +const tls = require('tls'); + +function toArrayBuffer(buf) { + const ab = new ArrayBuffer(buf.length); + const view = new Uint8Array(ab); + return buf.map((b, i) => view[i] = b); +} + +function toDataView(buf) { + const ab = new ArrayBuffer(buf.length); + const view = new DataView(ab); + return buf.map((b, i) => view[i] = b); +} + +const keyBuff = fixtures.readKey('agent1-key.pem'); +const certBuff = fixtures.readKey('agent1-cert.pem'); +const keyBuff2 = fixtures.readKey('ec-key.pem'); +const certBuff2 = fixtures.readKey('ec-cert.pem'); +const caCert = fixtures.readKey('ca1-cert.pem'); +const caCert2 = fixtures.readKey('ca2-cert.pem'); +const keyStr = keyBuff.toString(); +const certStr = certBuff.toString(); +const keyStr2 = keyBuff2.toString(); +const certStr2 = certBuff2.toString(); +const caCertStr = caCert.toString(); +const caCertStr2 = caCert2.toString(); +const keyArrBuff = toArrayBuffer(keyBuff); +const certArrBuff = toArrayBuffer(certBuff); +const caArrBuff = toArrayBuffer(caCert); +const keyDataView = toDataView(keyBuff); +const certDataView = toDataView(certBuff); +const caArrDataView = toDataView(caCert); + +// Checks to ensure tls.createServer doesn't throw an error +// Format ['key', 'cert'] +[ + [keyBuff, certBuff], + [false, certBuff], + [keyBuff, false], + [keyStr, certStr], + [false, certStr], + [keyStr, false], + [false, false], + [keyArrBuff, certArrBuff], + [keyArrBuff, false], + [false, certArrBuff], + [keyDataView, certDataView], + [keyDataView, false], + [false, certDataView], + [[keyBuff, keyBuff2], [certBuff, certBuff2]], + [[keyStr, keyStr2], [certStr, certStr2]], + [[keyStr, keyStr2], false], + [false, [certStr, certStr2]], + [[{ pem: keyBuff }], false], + [[{ pem: keyBuff }, { pem: keyBuff }], false], +].forEach(([key, cert]) => { + tls.createServer({ key, cert }); +}); + +// Checks to ensure tls.createServer predictably throws an error +// Format ['key', 'cert', 'expected message'] +[ + [true, certBuff], + [true, certStr], + [true, certArrBuff], + [true, certDataView], + [true, false], + [true, false], + [{ pem: keyBuff }, false], + [[keyBuff, true], [certBuff, certBuff2], 1], + [[true, keyStr2], [certStr, certStr2], 0], + [[true, false], [certBuff, certBuff2], 0], + [true, [certBuff, certBuff2]], +].forEach(([key, cert, index]) => { + const val = index === undefined ? key : key[index]; + assert.throws(() => { + tls.createServer({ key, cert }); + }, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "options.key" property must be of type string or an ' + + 'instance of Buffer, TypedArray, DataView, or BunFile.' + + common.invalidArgTypeHelper(val) + }); +}); + +[ + [keyBuff, true], + [keyStr, true], + [keyArrBuff, true], + [keyDataView, true], + [true, true], + [false, true], + [false, { pem: keyBuff }], + [false, 1], + [[keyBuff, keyBuff2], [true, certBuff2], 0], + [[keyStr, keyStr2], [certStr, true], 1], + [[keyStr, keyStr2], [true, false], 0], + [[keyStr, keyStr2], true], +].forEach(([key, cert, index]) => { + const val = index === undefined ? cert : cert[index]; + assert.throws(() => { + tls.createServer({ key, cert }); + }, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "options.cert" property must be of type string or an ' + + 'instance of Buffer, TypedArray, DataView, or BunFile.' + + common.invalidArgTypeHelper(val) + }); +}); + +// Checks to ensure tls.createServer works with the CA parameter +// Format ['key', 'cert', 'ca'] +[ + [keyBuff, certBuff, caCert], + [keyBuff, certBuff, [caCert, caCert2]], + [keyBuff, certBuff, caCertStr], + [keyBuff, certBuff, [caCertStr, caCertStr2]], + [keyBuff, certBuff, caArrBuff], + [keyBuff, certBuff, caArrDataView], + [keyBuff, certBuff, false], +].forEach(([key, cert, ca]) => { + tls.createServer({ key, cert, ca }); +}); + +// Checks to ensure tls.createServer throws an error for CA assignment +// Format ['key', 'cert', 'ca'] +[ + [keyBuff, certBuff, true], + [keyBuff, certBuff, {}], + [keyBuff, certBuff, 1], + [keyBuff, certBuff, true], + [keyBuff, certBuff, [caCert, true], 1], +].forEach(([key, cert, ca, index]) => { + const val = index === undefined ? ca : ca[index]; + assert.throws(() => { + tls.createServer({ key, cert, ca }); + }, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "options.ca" property must be of type string or an instance' + + ' of Buffer, TypedArray, DataView, or BunFile.' + + common.invalidArgTypeHelper(val) + }); +}); + +// Checks to ensure tls.createSecureContext works with false-y input +// Format ['key', 'cert', 'ca'] +[ + [null, null, null], + [false, false, false], + [undefined, undefined, undefined], + ['', '', ''], + [0, 0, 0], +].forEach(([key, cert, ca]) => { + tls.createSecureContext({ key, cert, ca }); +}); \ No newline at end of file