Compare commits

...

1 Commits

Author SHA1 Message Date
Meghan Denny
e57f4a7d8b node: fix test-tls-ticket-invalid-arg.js 2025-03-13 17:56:51 -07:00
9 changed files with 166 additions and 103 deletions

View File

@@ -1303,6 +1303,20 @@ JSC_DEFINE_HOST_FUNCTION(Bun::jsFunctionMakeErrorWithCode, (JSC::JSGlobalObject
return JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_IP_ADDRESS, builder.toString()));
}
case Bun::ErrorCode::ERR_INVALID_ADDRESS_FAMILY: {
auto arg0 = callFrame->argument(1);
auto str0 = arg0.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
auto arg1 = callFrame->argument(2);
auto str1 = arg1.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
auto arg2 = callFrame->argument(3);
auto str2 = arg2.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
auto message = makeString("Invalid address family: "_s, str0, " "_s, str1, ":"_s, str2);
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_ADDRESS_FAMILY, message));
}
case Bun::ErrorCode::ERR_INVALID_ARG_VALUE: {
JSValue arg0 = callFrame->argument(1);
JSValue arg1 = callFrame->argument(2);
@@ -1681,6 +1695,8 @@ JSC_DEFINE_HOST_FUNCTION(Bun::jsFunctionMakeErrorWithCode, (JSC::JSGlobalObject
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_SOCKET_CLOSED_BEFORE_CONNECTION, "Socket closed before the connection was established"_s));
case ErrorCode::ERR_TLS_RENEGOTIATION_DISABLED:
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_TLS_RENEGOTIATION_DISABLED, "TLS session renegotiation disabled for this socket"_s));
case ErrorCode::ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED:
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED, "Custom engines not supported by this BoringSSL"_s));
default: {
break;

View File

@@ -96,6 +96,8 @@ const errors: ErrorCodeMapping = [
["ERR_HTTP_INVALID_HEADER_VALUE", TypeError],
["ERR_SERVER_ALREADY_LISTEN", Error],
["ERR_CHILD_PROCESS_IPC_REQUIRED", Error],
["ERR_INVALID_ADDRESS_FAMILY", RangeError],
["ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED", Error],
// Bun-specific
["ERR_FORMDATA_PARSE_ERROR", TypeError],
@@ -158,7 +160,7 @@ const errors: ErrorCodeMapping = [
["ERR_HTTP2_HEADERS_AFTER_RESPOND", Error],
["ERR_HTTP2_PUSH_DISABLED", Error],
["ERR_HTTP2_MAX_PENDING_SETTINGS_ACK", Error],
// HTTP
["ERR_UNESCAPED_CHARACTERS", TypeError],

View File

@@ -559,7 +559,9 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_validateBuffer, (JSC::JSGlobalObject * globa
auto buffer = callFrame->argument(0);
auto name = callFrame->argument(1);
if (!buffer.isCell()) return JSValue::encode(jsUndefined());
if (!buffer.isCell()) {
return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, name, "Buffer, TypedArray, or DataView"_s, buffer);
}
auto ty = buffer.asCell()->type();
if (JSC::typedArrayType(ty) == NotTypedArray) {
@@ -621,13 +623,14 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_validateObject, (JSC::JSGlobalObject * globa
auto scope = DECLARE_THROW_SCOPE(vm);
auto value = callFrame->argument(0);
auto name = callFrame->argument(1);
if (value.isNull() || JSC::isArray(globalObject, value)) {
return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, callFrame->argument(1), "object"_s, value);
return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, name, "object"_s, value);
}
if (!value.isObject() || value.asCell()->type() != FinalObjectType) {
return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, callFrame->argument(1), "object"_s, value);
return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, name, "object"_s, value);
}
return JSValue::encode(jsUndefined());

View File

@@ -28,13 +28,12 @@ let $assert = function(check, sourceString, ...message) {
Error.prepareStackTrace = (e, stack) => {
return e.name + ': ' + e.message + '\\n' + stack.slice(1).map(x => ' at ' + x.toString()).join('\\n');
};
const e = new Error(sourceString);
const e = new Error(message ?? sourceString);
e.stack; // materialize stack
e.name = 'AssertionError';
Error.prepareStackTrace = prevPrepareStackTrace;
console.error('[${publicName}] ASSERTION FAILED: ' + sourceString);
if (message.length) console.warn(...message);
console.warn(e.stack.split('\\n')[1] + '\\n');
if (Bun.env.ASSERT === 'CRASH') process.exit(0xAA);
throw e;
}

View File

@@ -614,6 +614,8 @@ declare function $ERR_MISSING_ARGS(oneOf: string[]): TypeError;
declare function $ERR_INVALID_RETURN_VALUE(expected_type: string, name: string, actual_value: any): TypeError;
declare function $ERR_TLS_INVALID_PROTOCOL_VERSION(a: string, b: string): TypeError;
declare function $ERR_TLS_PROTOCOL_VERSION_CONFLICT(a: string, b: string): TypeError;
declare function $ERR_INVALID_IP_ADDRESS(ip: any): TypeError;
declare function $ERR_INVALID_ADDRESS_FAMILY(addressType, host, port): RangeError;
declare function $ERR_IPC_DISCONNECTED(): Error;
declare function $ERR_SERVER_NOT_RUNNING(): Error;
@@ -641,6 +643,7 @@ declare function $ERR_SERVER_ALREADY_LISTEN(): Error;
declare function $ERR_SOCKET_CLOSED(): Error;
declare function $ERR_SOCKET_CLOSED_BEFORE_CONNECTION(): Error;
declare function $ERR_TLS_RENEGOTIATION_DISABLED(): Error;
declare function $ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED(): Error;
/**
* Convert a function to a class-like object.

View File

@@ -23,5 +23,6 @@ function getTimerDuration(msecs, name) {
}
export default {
kTimeout: Symbol("timeout"), // For hiding Timeouts on other internals.
getTimerDuration,
};

View File

@@ -12,9 +12,6 @@ export default {
get promises() {
return (timersPromisesValue ??= require("node:timers/promises"));
},
set promises(value) {
timersPromisesValue = value;
},
active(timer) {
if ($isCallable(timer?.refresh)) {
timer.refresh();

View File

@@ -4,6 +4,8 @@ const net = require("node:net");
const { Duplex } = require("node:stream");
const { addServerName } = require("internal/net");
const { throwNotImplemented } = require("internal/shared");
const { validateBuffer, validateObject } = require("internal/validators");
const crypto = require("node:crypto");
const { Server: NetServer, Socket: NetSocket } = net;
@@ -263,6 +265,30 @@ var InternalSecureContext = class SecureContext {
}
this.context = context;
}
// init
// setKey
// setCert
// addCACert
// setAllowPartialTrustChain
// addCRL
// addRootCerts
// setCipherSuites
// setCiphers
// setSigalgs
// setECDHCurve
// setDHParam
// setMaxProto
// setMinProto
// getMaxProto
// getMinProto
// setOptions
// setSessionIdContext
// setSessionTimeout
// close
// loadPKCS12
// setTicketKeys
// enableTicketKeyCallback
};
function SecureContext(options) {
@@ -488,6 +514,14 @@ function Server(options, secureConnectionListener): void {
if (!(this instanceof Server)) {
return new Server(options, secureConnectionListener);
}
if (typeof options === "function") {
secureConnectionListener = options;
options = {};
} else if (options == null || typeof options === "object") {
options ??= {};
} else {
throw $ERR_INVALID_ARG_TYPE("options", "Object", options);
}
NetServer.$apply(this, [options, secureConnectionListener]);
@@ -502,100 +536,7 @@ function Server(options, secureConnectionListener): void {
this.ALPNProtocols = undefined;
let contexts: Map<string, typeof InternalSecureContext> | null = null;
this.addContext = function (hostname, context) {
if (typeof hostname !== "string") {
throw new TypeError("hostname must be a string");
}
if (!(context instanceof InternalSecureContext)) {
context = createSecureContext(context);
}
if (this._handle) {
addServerName(this._handle, hostname, context);
} else {
if (!contexts) contexts = new Map();
contexts.set(hostname, context);
}
};
this.setSecureContext = function (options) {
if (options instanceof InternalSecureContext) {
options = options.context;
}
if (options) {
const { ALPNProtocols } = options;
if (ALPNProtocols) {
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",
);
}
this.cert = cert;
}
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",
);
}
this.ca = ca;
}
let passphrase = options.passphrase;
if (passphrase && typeof passphrase !== "string") {
throw new TypeError("passphrase argument must be an string");
}
this.passphrase = passphrase;
let servername = options.servername;
if (servername && typeof servername !== "string") {
throw new TypeError("servername argument must be an string");
}
this.servername = servername;
let secureOptions = options.secureOptions || 0;
if (secureOptions && typeof secureOptions !== "number") {
throw new TypeError("secureOptions argument must be an number");
}
this.secureOptions = secureOptions;
const requestCert = options.requestCert || false;
if (requestCert) this._requestCert = requestCert;
else this._requestCert = undefined;
const rejectUnauthorized = options.rejectUnauthorized;
if (typeof rejectUnauthorized !== "undefined") {
this._rejectUnauthorized = rejectUnauthorized;
} else this._rejectUnauthorized = rejectUnauthorizedDefault;
}
};
Server.prototype.getTicketKeys = function () {
throw Error("Not implented in Bun yet");
};
Server.prototype.setTicketKeys = function () {
throw Error("Not implented in Bun yet");
};
this._contexts = contexts;
this[buntls] = function (port, host, isClient) {
return [
@@ -621,6 +562,83 @@ function Server(options, secureConnectionListener): void {
}
$toClass(Server, "Server", NetServer);
Server.prototype.addContext = function addContext(hostname, context) {
if (typeof hostname !== "string") {
throw new TypeError("hostname must be a string");
}
if (!(context instanceof InternalSecureContext)) {
context = createSecureContext(context);
}
if (this._handle) {
addServerName(this._handle, hostname, context);
} else {
(this._contexts ??= new Map()).set(hostname, context);
}
};
Server.prototype.setSecureContext = function setSecureContext(options) {
validateObject(options, "options");
this.pfx = options.pfx ? options.pfx : undefined;
this.key = options.key ? options.key : undefined;
this.passphrase = options.passphrase ? options.passphrase : undefined;
this.cert = options.cert ? options.cert : undefined;
this.clientCertEngine = options.clientCertEngine ? options.clientCertEngine : undefined;
this.ca = options.ca ? options.ca : undefined;
this.minVersion = options.minVersion ? options.minVersion : undefined;
this.maxVersion = options.maxVersion ? options.maxVersion : undefined;
this.secureProtocol = options.secureProtocol ? options.secureProtocol : undefined;
this.crl = options.crl ? options.crl : undefined;
this.sigalgs = options.sigalgs;
this.ciphers = options.ciphers ? options.ciphers : (this.ciphers = undefined);
this.ecdhCurve = options.ecdhCurve;
this.dhparam = options.dhparam ? options.dhparam : (this.dhparam = undefined);
this.honorCipherOrder = options.honorCipherOrder !== undefined ? !!options.honorCipherOrder : true;
if (options.secureOptions || 0) this.secureOptions = options.secureOptions || 0;
else this.secureOptions = undefined;
this.sessionIdContext = options.sessionIdContext ? options.sessionIdContext : crypto.createHash("sha1").update(process.argv.join(" ")).digest("hex").slice(0, 32); // prettier-ignore
this.sessionTimeout = options.sessionTimeout ? options.sessionTimeout : undefined;
this.ticketKeys = options.ticketKeys ? options.ticketKeys : undefined;
this.privateKeyIdentifier = options.privateKeyIdentifier;
this.privateKeyEngine = options.privateKeyEngine;
this._sharedCreds = createSecureContext({
pfx: this.pfx,
key: this.key,
passphrase: this.passphrase,
cert: this.cert,
clientCertEngine: this.clientCertEngine,
ca: this.ca,
ciphers: this.ciphers,
sigalgs: this.sigalgs,
ecdhCurve: this.ecdhCurve,
dhparam: this.dhparam,
minVersion: this.minVersion,
maxVersion: this.maxVersion,
secureProtocol: this.secureProtocol,
secureOptions: this.secureOptions,
honorCipherOrder: this.honorCipherOrder,
crl: this.crl,
sessionIdContext: this.sessionIdContext,
ticketKeys: this.ticketKeys,
sessionTimeout: this.sessionTimeout,
privateKeyIdentifier: this.privateKeyIdentifier,
privateKeyEngine: this.privateKeyEngine,
});
};
Server.prototype.getTicketKeys = function getTicketKeys() {
throw Error("tls.Server.prototype.getTicketKeys Not implented in Bun yet");
};
Server.prototype.setTicketKeys = function setTicketKeys(keys) {
validateBuffer(keys, "buffer");
$assert(keys.byteLength === 48, "Session ticket keys must be a 48-byte buffer");
throw Error("tls.Server.prototype.setTicketKeys not implented in Bun yet");
};
function createServer(options, connectionListener) {
return new Server(options, connectionListener);
}

View File

@@ -0,0 +1,24 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto) {
common.skip('missing crypto');
}
const assert = require('assert');
const tls = require('tls');
const server = new tls.Server();
[null, undefined, 0, 1, 1n, Symbol(), {}, [], true, false, '', () => {}]
.forEach((arg) =>
assert.throws(
() => server.setTicketKeys(arg),
{ code: 'ERR_INVALID_ARG_TYPE' }
));
[new Uint8Array(1), Buffer.from([1]), new DataView(new ArrayBuffer(2))].forEach(
(arg) =>
assert.throws(() => {
server.setTicketKeys(arg);
}, /Session ticket keys must be a 48-byte buffer/)
);