Skip to content

Commit eed8395

Browse files
committed
feat: fork bcryptjs as @opensourceframework/bcryptjs
- Adds new package under packages/bcryptjs - Preserves original API - Includes minimal smoke test Fixes #108
1 parent 45606c1 commit eed8395

13 files changed

Lines changed: 3291 additions & 0 deletions

File tree

packages/bcryptjs/LICENSE

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
bcrypt.js
2+
---------
3+
Copyright (c) 2012 Nevins Bartolomeo <nevins.bartolomeo@gmail.com>
4+
Copyright (c) 2012 Shane Girish <shaneGirish@gmail.com>
5+
Copyright (c) 2025 Daniel Wirtz <dcode@dcode.io>
6+
7+
Redistribution and use in source and binary forms, with or without
8+
modification, are permitted provided that the following conditions
9+
are met:
10+
1. Redistributions of source code must retain the above copyright
11+
notice, this list of conditions and the following disclaimer.
12+
2. Redistributions in binary form must reproduce the above copyright
13+
notice, this list of conditions and the following disclaimer in the
14+
documentation and/or other materials provided with the distribution.
15+
3. The name of the author may not be used to endorse or promote products
16+
derived from this software without specific prior written permission.
17+
18+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19+
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20+
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21+
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23+
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27+
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

packages/bcryptjs/README.md

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
# bcrypt.js
2+
3+
Optimized bcrypt in JavaScript with zero dependencies, with TypeScript support. Compatible to the C++
4+
[bcrypt](https://npmjs.org/package/bcrypt) binding on Node.js and also working in the browser.
5+
6+
[![Build Status](https://img.shields.io/github/actions/workflow/status/dcodeIO/bcrypt.js/test.yml?branch=main&label=test&logo=github)](https://github.com/dcodeIO/bcrypt.js/actions/workflows/test.yml) [![Publish Status](https://img.shields.io/github/actions/workflow/status/dcodeIO/bcrypt.js/publish.yml?branch=main&label=publish&logo=github)](https://github.com/dcodeIO/bcrypt.js/actions/workflows/publish.yml) [![npm](https://img.shields.io/npm/v/bcryptjs.svg?label=npm&color=007acc&logo=npm)](https://www.npmjs.com/package/bcryptjs)
7+
8+
## Security considerations
9+
10+
Besides incorporating a salt to protect against rainbow table attacks, bcrypt is an adaptive function: over time, the
11+
iteration count can be increased to make it slower, so it remains resistant to brute-force search attacks even with
12+
increasing computation power. ([see](http://en.wikipedia.org/wiki/Bcrypt))
13+
14+
While bcrypt.js is compatible to the C++ bcrypt binding, it is written in pure JavaScript and thus slower ([about 30%](https://github.com/dcodeIO/bcrypt.js/wiki/Benchmark)), effectively reducing the number of iterations that can be
15+
processed in an equal time span.
16+
17+
The maximum input length is 72 bytes (note that UTF-8 encoded characters use up to 4 bytes) and the length of generated
18+
hashes is 60 characters. Note that maximum input length is not implicitly checked by the library for compatibility with
19+
the C++ binding on Node.js, but should be checked with `bcrypt.truncates(password)` where necessary.
20+
21+
## Usage
22+
23+
The package exports an ECMAScript module with an UMD fallback.
24+
25+
```
26+
$> npm install bcryptjs
27+
```
28+
29+
```ts
30+
import bcrypt from "bcryptjs";
31+
```
32+
33+
### Usage with a CDN
34+
35+
- From GitHub via [jsDelivr](https://www.jsdelivr.com):<br />
36+
`https://cdn.jsdelivr.net/gh/dcodeIO/bcrypt.js@TAG/index.js` (ESM)
37+
- From npm via [jsDelivr](https://www.jsdelivr.com):<br />
38+
`https://cdn.jsdelivr.net/npm/bcryptjs@VERSION/index.js` (ESM)<br />
39+
`https://cdn.jsdelivr.net/npm/bcryptjs@VERSION/umd/index.js` (UMD)
40+
- From npm via [unpkg](https://unpkg.com):<br />
41+
`https://unpkg.com/bcryptjs@VERSION/index.js` (ESM)<br />
42+
`https://unpkg.com/bcryptjs@VERSION/umd/index.js` (UMD)
43+
44+
Replace `TAG` respectively `VERSION` with a [specific version](https://github.com/dcodeIO/bcrypt.js/releases) or omit it (not recommended in production) to use latest.
45+
46+
When using the ESM variant in a browser, the `crypto` import needs to be stubbed out, for example using an [import map](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap). Bundlers should omit it automatically.
47+
48+
### Usage - Sync
49+
50+
To hash a password:
51+
52+
```ts
53+
const salt = bcrypt.genSaltSync(10);
54+
const hash = bcrypt.hashSync("B4c0/\/", salt);
55+
// Store hash in your password DB
56+
```
57+
58+
To check a password:
59+
60+
```ts
61+
// Load hash from your password DB
62+
bcrypt.compareSync("B4c0/\/", hash); // true
63+
bcrypt.compareSync("not_bacon", hash); // false
64+
```
65+
66+
Auto-gen a salt and hash:
67+
68+
```ts
69+
const hash = bcrypt.hashSync("bacon", 10);
70+
```
71+
72+
### Usage - Async
73+
74+
To hash a password:
75+
76+
```ts
77+
const salt = await bcrypt.genSalt(10);
78+
const hash = await bcrypt.hash("B4c0/\/", salt);
79+
// Store hash in your password DB
80+
```
81+
82+
```ts
83+
bcrypt.genSalt(10, (err, salt) => {
84+
bcrypt.hash("B4c0/\/", salt, function (err, hash) {
85+
// Store hash in your password DB
86+
});
87+
});
88+
```
89+
90+
To check a password:
91+
92+
```ts
93+
// Load hash from your password DB
94+
await bcrypt.compare("B4c0/\/", hash); // true
95+
await bcrypt.compare("not_bacon", hash); // false
96+
```
97+
98+
```ts
99+
// Load hash from your password DB
100+
bcrypt.compare("B4c0/\/", hash, (err, res) => {
101+
// res === true
102+
});
103+
bcrypt.compare("not_bacon", hash, (err, res) => {
104+
// res === false
105+
});
106+
```
107+
108+
Auto-gen a salt and hash:
109+
110+
```ts
111+
await bcrypt.hash("B4c0/\/", 10);
112+
// Store hash in your password DB
113+
```
114+
115+
```ts
116+
bcrypt.hash("B4c0/\/", 10, (err, hash) => {
117+
// Store hash in your password DB
118+
});
119+
```
120+
121+
**Note:** Under the hood, asynchronous APIs split an operation into small chunks. After the completion of a chunk, the execution of the next chunk is placed on the back of the [JS event queue](https://developer.mozilla.org/en/docs/Web/JavaScript/EventLoop), efficiently yielding for other computation to execute.
122+
123+
### Usage - Command Line
124+
125+
```
126+
Usage: bcrypt <input> [rounds|salt]
127+
```
128+
129+
## API
130+
131+
### Callback types
132+
133+
- **Callback<`T`>**: `(err: Error | null, result?: T) => void`<br />
134+
Called with an error on failure or a value of type `T` upon success.
135+
136+
- **ProgressCallback**: `(percentage: number) => void`<br />
137+
Called with the percentage of rounds completed (0.0 - 1.0), maximally once per `MAX_EXECUTION_TIME = 100` ms.
138+
139+
- **RandomFallback**: `(length: number) => number[]`<br />
140+
Called to obtain random bytes when both [Web Crypto API](http://www.w3.org/TR/WebCryptoAPI/) and Node.js
141+
[crypto](http://nodejs.org/api/crypto.html) are not available.
142+
143+
### Functions
144+
145+
- bcrypt.**genSaltSync**(rounds?: `number`): `string`<br />
146+
Synchronously generates a salt. Number of rounds defaults to 10 when omitted.
147+
148+
- bcrypt.**genSalt**(rounds?: `number`): `Promise<string>`<br />
149+
Asynchronously generates a salt. Number of rounds defaults to 10 when omitted.
150+
151+
- bcrypt.**genSalt**([rounds: `number`, ]callback: `Callback<string>`): `void`<br />
152+
Asynchronously generates a salt. Number of rounds defaults to 10 when omitted.
153+
154+
- bcrypt.**truncates**(password: `string`): `boolean`<br />
155+
Tests if a password will be truncated when hashed, that is its length is greater than 72 bytes when converted to UTF-8.
156+
157+
- bcrypt.**hashSync**(password: `string`, salt?: `number | string`): `string`
158+
Synchronously generates a hash for the given password. Number of rounds defaults to 10 when omitted.
159+
160+
- bcrypt.**hash**(password: `string`, salt: `number | string`): `Promise<string>`<br />
161+
Asynchronously generates a hash for the given password.
162+
163+
- bcrypt.**hash**(password: `string`, salt: `number | string`, callback: `Callback<string>`, progressCallback?: `ProgressCallback`): `void`<br />
164+
Asynchronously generates a hash for the given password.
165+
166+
- bcrypt.**compareSync**(password: `string`, hash: `string`): `boolean`<br />
167+
Synchronously tests a password against a hash.
168+
169+
- bcrypt.**compare**(password: `string`, hash: `string`): `Promise<boolean>`<br />
170+
Asynchronously compares a password against a hash.
171+
172+
- bcrypt.**compare**(password: `string`, hash: `string`, callback: `Callback<boolean>`, progressCallback?: `ProgressCallback`)<br />
173+
Asynchronously compares a password against a hash.
174+
175+
- bcrypt.**getRounds**(hash: `string`): `number`<br />
176+
Gets the number of rounds used to encrypt the specified hash.
177+
178+
- bcrypt.**getSalt**(hash: `string`): `string`<br />
179+
Gets the salt portion from a hash. Does not validate the hash.
180+
181+
- bcrypt.**setRandomFallback**(random: `RandomFallback`): `void`<br />
182+
Sets the pseudo random number generator to use as a fallback if neither [Web Crypto API](http://www.w3.org/TR/WebCryptoAPI/) nor Node.js [crypto](http://nodejs.org/api/crypto.html) are available. Please note: It is highly important that the PRNG used is cryptographically secure and that it is seeded properly!
183+
184+
## Building
185+
186+
Building the UMD fallback:
187+
188+
```
189+
$> npm run build
190+
```
191+
192+
Running the [tests](./tests):
193+
194+
```
195+
$> npm test
196+
```
197+
198+
## Credits
199+
200+
Based on work started by Shane Girish at [bcrypt-nodejs](https://github.com/shaneGirish/bcrypt-nodejs), which is itself
201+
based on [javascript-bcrypt](http://code.google.com/p/javascript-bcrypt/) (New BSD-licensed).

packages/bcryptjs/bin/bcrypt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/env node
2+
3+
import path from "node:path";
4+
import bcrypt from "../index.js";
5+
6+
if (process.argv.length < 3) {
7+
console.log(
8+
"Usage: " + path.basename(process.argv[1]) + " <input> [rounds|salt]",
9+
);
10+
process.exit(1);
11+
} else {
12+
var salt;
13+
if (process.argv.length > 3) {
14+
salt = process.argv[3];
15+
var rounds = parseInt(salt, 10);
16+
if (rounds == salt) {
17+
salt = bcrypt.genSaltSync(rounds);
18+
}
19+
} else {
20+
salt = bcrypt.genSaltSync();
21+
}
22+
console.log(bcrypt.hashSync(process.argv[2], salt));
23+
}

packages/bcryptjs/index.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import * as bcrypt from "./types.js";
2+
export * from "./types.js";
3+
export default bcrypt;

0 commit comments

Comments
 (0)