Compare commits

..

2 Commits

Author SHA1 Message Date
autofix-ci[bot]
e222414173 [autofix.ci] apply automated fixes 2026-02-26 19:57:27 +00:00
Claude Bot
8267c13a37 fix(docs): correct bcrypt rounds description from log10 to log2
The bcrypt cost parameter is a power-of-2 exponent (e.g., cost=10 means
2^10 = 1,024 rounds), not log10. This is confirmed by the implementation
in PasswordObject.zig which uses the cost as `rounds_log` with a valid
range of 4-31 (2^4 through 2^31).

Fixes #27474

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-26 19:55:17 +00:00
3 changed files with 4 additions and 77 deletions

View File

@@ -96,7 +96,7 @@ $2b$10$Lyj9kHYZtiyfxh2G60TEfeqs7xkkGiEFFDi3iJGc50ZG/XJ1sxIFi;
The format is composed of:
- `bcrypt`: `$2b`
- `rounds`: `$10` - rounds (log10 of the actual number of rounds)
- `rounds`: `$10` - rounds (log2 of the actual number of rounds)
- `salt`: `$Lyj9kHYZtiyfxh2G60TEfeqs7xkkGiEFFDi3iJGc50ZG/XJ1sxIFi`
- `hash`: `$GzJ8PuBi+K+BVojzPfS5mjnC8OpLGtv8KJqF99eP6a4`

View File

@@ -97,7 +97,6 @@ JSX509CertificateConstructor* JSX509CertificateConstructor::create(VM& vm, JSGlo
void JSX509CertificateConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, JSObject* prototype)
{
Base::finishCreation(vm, 1, "X509Certificate"_s, PropertyAdditionMode::WithStructureTransition);
putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
}
static JSValue createX509Certificate(JSC::VM& vm, JSGlobalObject* globalObject, Structure* structure, JSValue arg)
{
@@ -159,14 +158,15 @@ JSC_DEFINE_HOST_FUNCTION(x509CertificateConstructorConstruct, (JSGlobalObject *
Structure* structure = zigGlobalObject->m_JSX509CertificateClassStructure.get(zigGlobalObject);
JSValue newTarget = callFrame->newTarget();
if (zigGlobalObject->m_JSX509CertificateClassStructure.constructor(zigGlobalObject) != newTarget) [[unlikely]] {
auto scope = DECLARE_THROW_SCOPE(vm);
if (!newTarget) {
throwTypeError(globalObject, scope, "Class constructor X509Certificate cannot be invoked without 'new'"_s);
throwTypeError(globalObject, scope, "Class constructor Script cannot be invoked without 'new'"_s);
return {};
}
auto* functionGlobalObject = defaultGlobalObject(getFunctionRealm(globalObject, newTarget.getObject()));
RETURN_IF_EXCEPTION(scope, {});
structure = InternalFunction::createSubclassStructure(globalObject, newTarget.getObject(), functionGlobalObject->m_JSX509CertificateClassStructure.get(functionGlobalObject));
structure = InternalFunction::createSubclassStructure(globalObject, newTarget.getObject(), functionGlobalObject->NodeVMScriptStructure());
RETURN_IF_EXCEPTION(scope, {});
}

View File

@@ -1,73 +0,0 @@
import { describe, expect, test } from "bun:test";
import { X509Certificate } from "node:crypto";
import { readFileSync } from "node:fs";
import path from "node:path";
// Regression test for X509Certificate subclassing.
// Previously, subclassing used NodeVMScriptStructure() instead of the
// X509Certificate structure (copy-paste bug), causing subclass instances
// to inherit from vm.Script.prototype instead of X509Certificate.prototype.
// Also, X509Certificate.prototype was undefined because finishCreation()
// did not call putDirectWithoutTransition for the prototype property.
const certPath = path.join(import.meta.dir, "..", "test", "fixtures", "keys", "agent1-cert.pem");
const certPem = readFileSync(certPath);
describe("X509Certificate", () => {
test("constructor has .prototype property", () => {
expect(X509Certificate.prototype).toBeDefined();
expect(typeof X509Certificate.prototype).toBe("object");
});
test("prototype has expected methods", () => {
expect(typeof X509Certificate.prototype.checkHost).toBe("function");
expect(typeof X509Certificate.prototype.toJSON).toBe("function");
expect(typeof X509Certificate.prototype.toString).toBe("function");
});
test("instance uses correct prototype", () => {
const cert = new X509Certificate(certPem);
expect(Object.getPrototypeOf(cert)).toBe(X509Certificate.prototype);
expect(cert instanceof X509Certificate).toBe(true);
});
test("can be subclassed", () => {
class MyX509 extends X509Certificate {
customMethod() {
return "custom";
}
}
const cert = new MyX509(certPem);
expect(cert instanceof MyX509).toBe(true);
expect(cert instanceof X509Certificate).toBe(true);
expect(cert.customMethod()).toBe("custom");
// Should still have X509Certificate methods
expect(typeof cert.subject).toBe("string");
});
test("subclass prototype chain is correct", () => {
class MyX509 extends X509Certificate {}
const cert = new MyX509(certPem);
const proto = Object.getPrototypeOf(cert);
expect(proto).toBe(MyX509.prototype);
expect(Object.getPrototypeOf(proto)).toBe(X509Certificate.prototype);
// Verify it's NOT inheriting from vm.Script (the previous bug)
const vm = require("node:vm");
expect(cert instanceof vm.Script).toBe(false);
expect(Object.getPrototypeOf(proto)).not.toBe(vm.Script.prototype);
});
test("subclass instance accesses X509 getters correctly", () => {
class MyX509 extends X509Certificate {}
const cert = new MyX509(certPem);
// These getters rely on the correct Structure to read internal fields
expect(cert.subject).toBeDefined();
expect(cert.issuer).toBeDefined();
expect(cert.serialNumber).toBeDefined();
expect(typeof cert.fingerprint).toBe("string");
});
});