Skip to content

Commit

Permalink
Implement X509Certificate
Browse files Browse the repository at this point in the history
  • Loading branch information
Jarred-Sumner committed Jan 5, 2025
1 parent 034f776 commit 741b768
Show file tree
Hide file tree
Showing 35 changed files with 6,758 additions and 597 deletions.
33 changes: 33 additions & 0 deletions src/bun.js/api/bun/socket.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3218,6 +3218,39 @@ fn NewSocket(comptime ssl: bool) type {
return JSValue.jsUndefined();
}

pub fn getPeerX509Certificate(
this: *This,
globalObject: *JSC.JSGlobalObject,
_: *JSC.CallFrame,
) bun.JSError!JSValue {
if (comptime ssl == false) {
return JSValue.jsUndefined();
}
const ssl_ptr = this.socket.ssl() orelse return JSValue.jsUndefined();
const cert = BoringSSL.SSL_get_peer_certificate(ssl_ptr);
if (cert) |x509| {
return X509.toJSObject(x509, globalObject);
}
return JSValue.jsUndefined();
}

pub fn getX509Certificate(
this: *This,
globalObject: *JSC.JSGlobalObject,
_: *JSC.CallFrame,
) bun.JSError!JSValue {
if (comptime ssl == false) {
return JSValue.jsUndefined();
}

const ssl_ptr = this.socket.ssl() orelse return JSValue.jsUndefined();
const cert = BoringSSL.SSL_get_certificate(ssl_ptr);
if (cert) |x509| {
return X509.toJSObject(x509, globalObject);
}
return JSValue.jsUndefined();
}

pub fn getServername(
this: *This,
globalObject: *JSC.JSGlobalObject,
Expand Down
513 changes: 6 additions & 507 deletions src/bun.js/api/bun/x509.zig

Large diffs are not rendered by default.

20 changes: 16 additions & 4 deletions src/bun.js/api/sockets.classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,7 @@ function generate(ssl) {
fn: "getPeerCertificate",
length: 1,
},
getCertificate: {
fn: "getCertificate",
length: 0,
},

authorized: {
getter: "getAuthorized",
},
Expand Down Expand Up @@ -203,12 +200,27 @@ function generate(ssl) {
length: 2,
privateSymbol: "end",
},
getCertificate: {
fn: "getCertificate",
length: 0,
},
...(ssl ? sslOnly : {}),
},
finalize: true,
construct: true,
klass: {},
});
}
const sslOnly = {
getPeerX509Certificate: {
fn: "getPeerX509Certificate",
length: 0,
},
getX509Certificate: {
fn: "getX509Certificate",
length: 0,
},
} as const;
export default [
generate(true),
generate(false),
Expand Down
50 changes: 50 additions & 0 deletions src/bun.js/bindings/BunString.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#pragma once

#include "root.h"

#include <wtf/text/WTFString.h>
#include <wtf/text/CString.h>

namespace Bun {
class UTF8View {
public:
UTF8View()
{
m_isCString = false;
m_underlying = {};
m_view = {};
}

UTF8View(WTF::StringView view)
{
if (view.is8Bit() && view.containsOnlyASCII()) {
m_view = view;
} else {
m_underlying = view.utf8();
m_isCString = true;
}
}
UTF8View(const WTF::String& str)
{
if (str.is8Bit() && str.containsOnlyASCII()) {
m_view = str;
} else {
m_underlying = str.utf8();
m_isCString = true;
}
}

WTF::CString m_underlying {};
WTF::StringView m_view {};
bool m_isCString { false };

std::span<const char> span() const
{
if (m_isCString) {
return std::span(reinterpret_cast<const char*>(m_underlying.data()), m_underlying.length());
}

return std::span(reinterpret_cast<const char*>(m_view.span8().data()), m_view.length());
}
};
}
18 changes: 16 additions & 2 deletions src/bun.js/bindings/ErrorCode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#include "JavaScriptCore/ErrorInstanceInlines.h"
#include "JavaScriptCore/JSInternalFieldObjectImplInlines.h"
#include "JSDOMException.h"

#include <openssl/err.h>
#include "ErrorCode.h"

static JSC::JSObject* createErrorPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::ErrorType type, WTF::ASCIILiteral name, WTF::ASCIILiteral code, bool isDOMExceptionPrototype = false)
Expand Down Expand Up @@ -725,6 +725,19 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_UNHANDLED_ERROR, (JSC::JSGlobalObject *
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_UNHANDLED_ERROR, makeString("Unhandled error. ("_s, err_str, ")"_s)));
}

void throwBoringSSLError(JSC::VM& vm, JSC::ThrowScope& scope, JSGlobalObject* globalObject, int errorCode)
{
char buf[256] = { 0 };
ERR_error_string_n(static_cast<uint32_t>(errorCode), buf, sizeof(buf));
auto message = String::fromUTF8(buf);
scope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_CRYPTO_INVALID_STATE, message));
}

void throwCryptoOperationFailed(JSGlobalObject* globalObject, JSC::ThrowScope& scope)
{
scope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_CRYPTO_OPERATION_FAILED, "Crypto operation failed"_s));
}

} // namespace Bun

JSC::JSValue WebCore::toJS(JSC::JSGlobalObject* globalObject, CommonAbortReason abortReason)
Expand Down Expand Up @@ -772,7 +785,8 @@ JSC::JSObject* Bun::createInvalidThisError(JSC::JSGlobalObject* globalObject, JS

JSC::EncodedJSValue Bun::throwError(JSC::JSGlobalObject* globalObject, JSC::ThrowScope& scope, Bun::ErrorCode code, const WTF::String& message)
{
return JSC::JSValue::encode(scope.throwException(globalObject, createError(globalObject, code, message)));
scope.throwException(globalObject, createError(globalObject, code, message));
return {};
}

JSC_DEFINE_HOST_FUNCTION(Bun::jsFunctionMakeErrorWithCode, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
Expand Down
3 changes: 3 additions & 0 deletions src/bun.js/bindings/ErrorCode.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,7 @@ JSC::EncodedJSValue SOCKET_BAD_PORT(JSC::ThrowScope& throwScope, JSC::JSGlobalOb

}

void throwBoringSSLError(JSC::VM& vm, JSC::ThrowScope& scope, JSGlobalObject* globalObject, int errorCode);
void throwCryptoOperationFailed(JSGlobalObject* globalObject, JSC::ThrowScope& scope);

}
36 changes: 19 additions & 17 deletions src/bun.js/bindings/ErrorCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,46 +12,48 @@ type ErrorCodeMapping = Array<

export default [
["ABORT_ERR", Error, "AbortError"],
["ERR_BROTLI_INVALID_PARAM", RangeError],
["ERR_BUFFER_OUT_OF_BOUNDS", RangeError],
["ERR_BUFFER_TOO_LARGE", RangeError],
["ERR_CRYPTO_INVALID_DIGEST", TypeError],
["ERR_CRYPTO_INVALID_SCRYPT_PARAMS", RangeError],
["ERR_CRYPTO_INVALID_STATE", Error],
["ERR_CRYPTO_OPERATION_FAILED", Error],
["ERR_CRYPTO_SCRYPT_INVALID_PARAMETER", Error],
["ERR_ENCODING_INVALID_ENCODED_DATA", TypeError],
["ERR_ILLEGAL_CONSTRUCTOR", TypeError],
["ERR_INCOMPATIBLE_OPTION_PAIR", TypeError, "TypeError"],
["ERR_INVALID_ARG_TYPE", TypeError],
["ERR_INVALID_ARG_VALUE", TypeError],
["ERR_INVALID_PROTOCOL", TypeError],
["ERR_INVALID_STATE", Error],
["ERR_INVALID_THIS", TypeError],
["ERR_INVALID_URI", URIError, "URIError"],
["ERR_INVALID_URL", TypeError],
["ERR_IPC_CHANNEL_CLOSED", Error],
["ERR_IPC_DISCONNECTED", Error],
["ERR_MISSING_ARGS", TypeError],
["ERR_OUT_OF_RANGE", RangeError],
["ERR_PARSE_ARGS_INVALID_OPTION_VALUE", TypeError],
["ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL", TypeError],
["ERR_PARSE_ARGS_UNKNOWN_OPTION", TypeError],
["ERR_SCRIPT_EXECUTION_INTERRUPTED", Error, "Error"],
["ERR_SCRIPT_EXECUTION_TIMEOUT", Error, "Error"],
["ERR_SERVER_NOT_RUNNING", Error],
["ERR_SOCKET_BAD_PORT", RangeError],
["ERR_SOCKET_BAD_TYPE", TypeError],
["ERR_STREAM_ALREADY_FINISHED", TypeError],
["ERR_STREAM_CANNOT_PIPE", TypeError],
["ERR_STREAM_DESTROYED", TypeError],
["ERR_STREAM_NULL_VALUES", TypeError],
["ERR_STREAM_RELEASE_LOCK", Error, "AbortError"],
["ERR_STREAM_WRITE_AFTER_END", TypeError],
["ERR_ZLIB_INITIALIZATION_FAILED", Error],
["ERR_STRING_TOO_LONG", Error],
["ERR_CRYPTO_SCRYPT_INVALID_PARAMETER", Error],
["ERR_CRYPTO_INVALID_SCRYPT_PARAMS", RangeError],
["MODULE_NOT_FOUND", Error],
["ERR_ILLEGAL_CONSTRUCTOR", TypeError],
["ERR_INVALID_URL", TypeError],
["ERR_BUFFER_TOO_LARGE", RangeError],
["ERR_BROTLI_INVALID_PARAM", RangeError],
["ERR_UNHANDLED_ERROR", Error],
["ERR_UNKNOWN_ENCODING", TypeError],
["ERR_INVALID_STATE", Error],
["ERR_BUFFER_OUT_OF_BOUNDS", RangeError],
["ERR_UNKNOWN_SIGNAL", TypeError],
["ERR_SOCKET_BAD_PORT", RangeError],
["ERR_STREAM_RELEASE_LOCK", Error, "AbortError"],
["ERR_INCOMPATIBLE_OPTION_PAIR", TypeError, "TypeError"],
["ERR_INVALID_URI", URIError, "URIError"],
["ERR_SCRIPT_EXECUTION_TIMEOUT", Error, "Error"],
["ERR_SCRIPT_EXECUTION_INTERRUPTED", Error, "Error"],
["ERR_UNHANDLED_ERROR", Error],
["ERR_ZLIB_INITIALIZATION_FAILED", Error],
["MODULE_NOT_FOUND", Error],

// Bun-specific
["ERR_FORMDATA_PARSE_ERROR", TypeError],
Expand Down
8 changes: 8 additions & 0 deletions src/bun.js/bindings/JSBuffer.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@


#include "root.h"

#include "ZigGlobalObject.h"
#include "JavaScriptCore/ExceptionHelpers.h"
#include "JavaScriptCore/JSString.h"
#include "JavaScriptCore/Error.h"
Expand Down Expand Up @@ -356,6 +358,12 @@ static inline JSC::EncodedJSValue writeToBuffer(JSC::JSGlobalObject* lexicalGlob
return JSC::JSValue::encode(JSC::jsNumber(written));
}

JSC::JSUint8Array* createBuffer(JSC::JSGlobalObject* lexicalGlobalObject, Ref<JSC::ArrayBuffer>&& backingStore)
{
size_t length = backingStore->byteLength();
return JSC::JSUint8Array::create(lexicalGlobalObject, defaultGlobalObject(lexicalGlobalObject)->JSBufferSubclassStructure(), WTFMove(backingStore), 0, length);
}

JSC::JSUint8Array* createBuffer(JSC::JSGlobalObject* lexicalGlobalObject, const uint8_t* ptr, size_t length)
{
auto* buffer = createUninitializedBuffer(lexicalGlobalObject, length);
Expand Down
2 changes: 2 additions & 0 deletions src/bun.js/bindings/JSBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#pragma once

#include "JavaScriptCore/ArrayBuffer.h"
#include "root.h"

#include <JavaScriptCore/JSGlobalObject.h>
Expand Down Expand Up @@ -57,6 +58,7 @@ JSC::JSUint8Array* createBuffer(JSC::JSGlobalObject* lexicalGlobalObject, const
JSC::JSUint8Array* createBuffer(JSC::JSGlobalObject* lexicalGlobalObject, const Vector<uint8_t>& data);
JSC::JSUint8Array* createBuffer(JSC::JSGlobalObject* lexicalGlobalObject, const std::span<const uint8_t> data);
JSC::JSUint8Array* createBuffer(JSC::JSGlobalObject* lexicalGlobalObject, const char* ptr, size_t length);
JSC::JSUint8Array* createBuffer(JSC::JSGlobalObject* lexicalGlobalObject, Ref<JSC::ArrayBuffer>&& backingStore);
JSC::JSUint8Array* createEmptyBuffer(JSC::JSGlobalObject* lexicalGlobalObject);

JSC_DECLARE_HOST_FUNCTION(constructSlowBuffer);
Expand Down
14 changes: 13 additions & 1 deletion src/bun.js/bindings/JSDOMExceptionHandling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,14 +296,26 @@ String makeThisTypeErrorMessage(const char* interfaceName, const char* functionN
return makeString("Can only call "_s, interfaceNameSpan, '.', span(functionName), " on instances of "_s, interfaceNameSpan);
}

String makeThisTypeErrorMessage(ASCIILiteral interfaceName, ASCIILiteral functionName)
{
return makeString("Can only call "_s, interfaceName, '.', functionName, " on instances of "_s, interfaceName);
}

String makeUnsupportedIndexedSetterErrorMessage(ASCIILiteral interfaceName)
{
return makeString("Failed to set an indexed property on "_s, interfaceName, ": Indexed property setter is not supported."_s);
}

EncodedJSValue throwThisTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, const char* interfaceName, const char* functionName)
{
return JSValue::encode(scope.throwException(&lexicalGlobalObject, Bun::createInvalidThisError(&lexicalGlobalObject, makeThisTypeErrorMessage(interfaceName, functionName))));
scope.throwException(&lexicalGlobalObject, Bun::createInvalidThisError(&lexicalGlobalObject, makeThisTypeErrorMessage(interfaceName, functionName)));
return {};
}

EncodedJSValue throwThisTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, ASCIILiteral interfaceName, ASCIILiteral attributeName)
{
scope.throwException(&lexicalGlobalObject, Bun::createInvalidThisError(&lexicalGlobalObject, makeThisTypeErrorMessage(interfaceName, attributeName)));
return {};
}

JSC::EncodedJSValue rejectPromiseWithThisTypeError(DeferredPromise& promise, const char* interfaceName, const char* methodName)
Expand Down
3 changes: 3 additions & 0 deletions src/bun.js/bindings/JSDOMExceptionHandling.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include "ExceptionDetails.h"
#include "ExceptionOr.h"
#include "wtf/text/ASCIILiteral.h"
#include <JavaScriptCore/ThrowScope.h>

namespace JSC {
Expand Down Expand Up @@ -54,9 +55,11 @@ WEBCORE_EXPORT JSC::EncodedJSValue throwRequiredMemberTypeError(JSC::JSGlobalObj
JSC::EncodedJSValue throwConstructorScriptExecutionContextUnavailableError(JSC::JSGlobalObject&, JSC::ThrowScope&, ASCIILiteral interfaceName);

String makeThisTypeErrorMessage(const char* interfaceName, const char* attributeName);
String makeThisTypeErrorMessage(ASCIILiteral interfaceName, ASCIILiteral functionName);
String makeUnsupportedIndexedSetterErrorMessage(ASCIILiteral interfaceName);

WEBCORE_EXPORT JSC::EncodedJSValue throwThisTypeError(JSC::JSGlobalObject&, JSC::ThrowScope&, const char* interfaceName, const char* functionName);
WEBCORE_EXPORT JSC::EncodedJSValue throwThisTypeError(JSC::JSGlobalObject&, JSC::ThrowScope&, ASCIILiteral interfaceName, ASCIILiteral attributeName);

WEBCORE_EXPORT JSC::EncodedJSValue rejectPromiseWithGetterTypeError(JSC::JSGlobalObject&, const JSC::ClassInfo*, JSC::PropertyName attributeName);
WEBCORE_EXPORT JSC::EncodedJSValue rejectPromiseWithThisTypeError(DeferredPromise&, const char* interfaceName, const char* operationName);
Expand Down
Loading

0 comments on commit 741b768

Please sign in to comment.