Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/bun-types/bun.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2017,6 +2017,10 @@ declare module "bun" {
* time, given in number of iterations.
*/
timeCost?: number;
/**
* The number of parallel threads.
*/
parallelism?: number;
}

interface BCryptAlgorithm {
Expand Down
14 changes: 13 additions & 1 deletion src/bun.js/api/crypto/PasswordObject.zig
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ pub const PasswordObject = struct {
argon.memory_cost = @as(u32, @intCast(memory_cost));
}

if (try value.getTruthy(globalObject, "parallelism")) |parallelism_value| {
if (!parallelism_value.isNumber()) {
return globalObject.throwInvalidArgumentType("hash", "parallelism", "number");
}
const parallelism = try parallelism_value.coerce(i32, globalObject);
if (parallelism < 1) {
return globalObject.throwInvalidArguments("Parallelism must be greater than 0", .{});
}
argon.parallelism = @as(u24, @intCast(parallelism));
}

return @unionInit(Algorithm.Value, @tagName(tag), argon);
},
}
Expand Down Expand Up @@ -130,12 +141,13 @@ pub const PasswordObject = struct {
// we don't support the other options right now, but can add them later if someone asks
memory_cost: u32 = pwhash.argon2.Params.interactive_2id.m,
time_cost: u32 = pwhash.argon2.Params.interactive_2id.t,
parallelism: u24 = pwhash.argon2.Params.interactive_2id.p,

pub fn toParams(this: Argon2Params) pwhash.argon2.Params {
return pwhash.argon2.Params{
.t = this.time_cost,
.m = this.memory_cost,
.p = 1,
.p = this.parallelism,
};
}
};
Expand Down
11 changes: 9 additions & 2 deletions test/js/bun/util/password.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ describe("hash", () => {
}),
).toThrow();

expect(() =>
hash(placeholder, {
algorithm: "argon2id",
parallelism: -1,
}),
).toThrow();

expect(() =>
hash(placeholder, {
algorithm: "argon2id",
Expand Down Expand Up @@ -237,13 +244,13 @@ for (let algorithmValue of algorithms) {
}

async function runSlowTestWithOptions(algorithmLabel: any) {
const algorithm = { algorithm: algorithmLabel, timeCost: 5, memoryCost: 8 };
const algorithm = { algorithm: algorithmLabel, timeCost: 5, memoryCost: 8, parallelism: 2 };
const hashed = await password.hash(input, algorithm);
const prefix = "$" + algorithmLabel;
expect(hashed).toStartWith(prefix);
expect(hashed).toContain("t=5");
expect(hashed).toContain("m=8");
expect(hashed).toContain("p=1");
expect(hashed).toContain("p=2");
expect(await password.verify(input, hashed, algorithmLabel)).toBeTrue();
expect(() => password.verify(hashed, input, algorithmLabel)).toThrow();
expect(await password.verify(input + "\0", hashed, algorithmLabel)).toBeFalse();
Expand Down