{"_id":"phpass","_rev":"10-2ee2662f6b192649b122355a8942eafa","name":"phpass","dist-tags":{"latest":"1.0.0"},"versions":{"0.1.0":{"name":"phpass","version":"0.1.0","keywords":["auth","password","hashing","blowfish","phpass"],"author":{"name":"John Hurliman","email":"jhurliman@cull.tv"},"_id":"phpass@0.1.0","contributors":[],"dist":{"shasum":"8e398c459c3283ef4642fd370acfb52e1cb4b56d","tarball":"https://registry.npmjs.org/phpass/-/phpass-0.1.0.tgz","integrity":"sha512-CuAaoUH6faqXhgG0VNvi8USZUs0bHRbuawpkw8FsFN1WGuLoVtP549tU88v41I1XagYL0yofqk48Wm9Xuw6zLA==","signatures":[{"sig":"MEUCIGp0YH8Y1PfEgCEnNlElLrsi4mRCd5c6Sv5lquT0YJAFAiEA/FDumyW+2yCwqCW8cOCfjv3vOy7mf+KZJ67CbW7hfuA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"index","engines":{"node":"*"},"scripts":{},"_npmVersion":"1.0.6","description":"A pure node.js JavaScript port of the portable PHP password hashing framework.","directories":{"lib":"./lib"},"_nodeVersion":"v0.4.8","dependencies":{},"_defaultsLoaded":true,"devDependencies":{},"_engineSupported":true},"0.1.1":{"name":"phpass","version":"0.1.1","keywords":["auth","password","hashing","blowfish","phpass"],"author":{"name":"John Hurliman","email":"jhurliman@cull.tv"},"_id":"phpass@0.1.1","maintainers":[{"name":"jhurliman","email":"jhurliman@cull.tv"}],"contributors":[],"dist":{"shasum":"5626676d11e2feb7a4b5daedb34e5f7598df80b5","tarball":"https://registry.npmjs.org/phpass/-/phpass-0.1.1.tgz","integrity":"sha512-ZGkvcdZbIVN6k94p87LavU+GJbVJ8u1BKUkG/qRhdKi8v8YQONT8Ad1DaeXTeEjHBQbMK0+eiI03/M3PbNHB5g==","signatures":[{"sig":"MEUCIHeIrmjJdtz/Ya6cRL3zCYOstIpLDI3zeUP0muKYfI2eAiEA3Eusn7iOsl552HIpTUdebtac1gHoHPqmciiqYFiJzZo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"index","engines":{"node":"*"},"_npmUser":{"name":"jhurliman","email":"jhurliman@jhurliman.org"},"_npmVersion":"1.1.61","description":"A pure node.js JavaScript port of the portable PHP password hashing framework.","directories":{"lib":"./lib"},"dependencies":{}},"1.0.0":{"_id":"phpass@1.0.0","bugs":{"url":"https://github.com/jhurliman/node-phpass/issues"},"dist":{"shasum":"1ca08278ab6c89b3794a7f439a863a705562af14","tarball":"https://registry.npmjs.org/phpass/-/phpass-1.0.0.tgz","fileCount":12,"integrity":"sha512-+t1HwTJVpWQHcLrUuu1OcHPzrV5j9jowHcSWCqKRDMQwh564OuETVbl75KvQuFwBltTsREOIlkwWapRtHOVtrQ==","signatures":[{"sig":"MEUCIQD+J9XvJc3ND2WGjN+TWx3qibxEyukxaeZbN/dmFYkoDQIgbBEX6QXsqTPCzKGrOM/8eZcwAWRngv+2IJ3jxHRcyB0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCICs4cKy8WIZgOqnmtUZFRFgs6vCIDKeyBr7Sgz2fEGdKAiEAy5HIswJGR9NuQuQsPzrnxmSJH4p5sBwK24jTjiFMi68="}],"unpackedSize":40128},"main":"index.js","name":"phpass","_from":"file:phpass-1.0.0.tgz","types":"index.d.ts","author":{"name":"John Hurliman","email":"jhurliman@cull.tv"},"engines":{"node":">=22"},"license":"MIT","scripts":{"test":"node --test","test:types":"tsc --noEmit --strict --module nodenext --target es2022 type-tests/consumer.mts type-tests/consumer.cts","test:coverage":"node --test --experimental-test-coverage"},"version":"1.0.0","_npmUser":{"name":"jhurliman","email":"jhurliman@jhurliman.org"},"homepage":"https://github.com/jhurliman/node-phpass#readme","keywords":["auth","password","hashing","blowfish","phpass"],"_resolved":"/Users/jhurliman/Documents/Codex/2026-09-09/you-recently-reviewed-node-rate-limiter-4/work/releases/node-phpass/phpass-1.0.0.tgz","_integrity":"sha512-+t1HwTJVpWQHcLrUuu1OcHPzrV5j9jowHcSWCqKRDMQwh564OuETVbl75KvQuFwBltTsREOIlkwWapRtHOVtrQ==","repository":{"url":"git+https://github.com/jhurliman/node-phpass.git","type":"git"},"_npmVersion":"11.19.0","description":"Verify phpass portable hashes and bcrypt passwords in Node.js, with an explicit migration path for legacy node-phpass hashes.","directories":{"lib":"./lib"},"maintainers":[{"name":"jhurliman","email":"jhurliman@jhurliman.org"}],"_nodeVersion":"26.7.0","contributors":[],"dependencies":{"bcryptjs":"^3.0.3"},"_hasShrinkwrap":false,"devDependencies":{"bcrypt":"6.0.0","typescript":"7.0.2"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/phpass_1.0.0_1789090594947_0.4252877440300604"}}},"time":{"created":"2011-06-08T23:27:21.049Z","modified":"2026-09-11T01:36:35.230Z","0.1.0":"2011-06-08T23:27:21.588Z","0.1.1":"2012-10-09T18:39:49.497Z","1.0.0":"2026-09-11T01:36:35.056Z"},"author":{"name":"John Hurliman","email":"jhurliman@cull.tv"},"description":"Verify phpass portable hashes and bcrypt passwords in Node.js, with an explicit migration path for legacy node-phpass hashes.","keywords":["auth","password","hashing","blowfish","phpass"],"contributors":[],"maintainers":[{"name":"jhurliman","email":"jhurliman@jhurliman.org"}],"readme":"# phpass\n\n[![CI](https://github.com/jhurliman/node-phpass/actions/workflows/ci.yml/badge.svg)](https://github.com/jhurliman/node-phpass/actions/workflows/ci.yml)\n[![npm](https://img.shields.io/npm/v/phpass.svg)](https://www.npmjs.com/package/phpass)\n\nBring a legacy PHP password database into Node.js. **phpass** verifies portable\n`$P$` / `$H$` hashes and standard bcrypt hashes, and generates new bcrypt hashes\nthrough [bcrypt.js](https://github.com/dcodeIO/bcrypt.js). It includes synchronous\nand Promise APIs, TypeScript declarations, and a separate migration path for\npasswords created by the original `node-phpass` implementation.\n\nIts purpose is interoperability with existing databases. Portable hashes are\nverified for migration; new hashes use bcrypt. This package does not implement\nPHP's extended DES fallback, Drupal `$S$` hashes, or application-specific wrappers.\n\n## Install\n\n```sh\nnpm install phpass\n```\n\nVersion 1 requires Node.js 22 or newer. Its runtime uses JavaScript and Node's\nbuilt-in crypto API; consumers do not need a native compiler.\n\n## Hash and verify\n\nSave as `example.mjs` and run `node example.mjs`:\n\n```js\nimport { PasswordHash } from 'phpass';\n\nconst passwords = new PasswordHash(10);\nconst storedHash = await passwords.hashPasswordAsync('correct horse battery staple');\n\nconsole.log(await passwords.checkPasswordAsync('correct horse battery staple', storedHash));\n// true\nconsole.log(await passwords.checkPasswordAsync('wrong password', storedHash));\n// false\n```\n\nFor CommonJS use `const { PasswordHash } = require('phpass')`. The original\nsynchronous API remains available as `hashPassword()` and `checkPassword()`.\n\n## Supported formats\n\n| Stored hash | Verification | New hash generation |\n| --- | --- | --- |\n| bcrypt `$2a$`, `$2b$`, `$2y$` | `checkPassword()` / `checkPasswordAsync()` | bcrypt `$2b$` |\n| phpass portable `$P$` | Same methods | Unsupported |\n| phpBB portable `$H$` | Same methods | Unsupported |\n| Non-ASCII hashes created by node-phpass 0.1.x | Explicit `checkPasswordLegacy()` | Unsupported |\n\nPortable verification implements the public-domain\n[Openwall phpass algorithm](https://github.com/openwall/phpass/blob/main/src/PasswordHash.php).\nThe tests include outputs from Openwall's independent C implementation, covering\nempty, ASCII, UTF-8, and long passwords at multiple iteration counts.\n\n## Migrate a portable hash\n\nVerify the supplied password against the stored hash. After successful\nverification, create a new hash from that same password and persist it through\nyour application's normal account update:\n\n```js\nimport { PasswordHash } from 'phpass';\n\nconst passwords = new PasswordHash(10);\n// A public test fixture for the password \"test\", not a real account credential.\nconst oldHash = '$P$5123456782Jd0mCwOvdg2EsRtmpU9H1';\n\nif (await passwords.checkPasswordAsync('test', oldHash)) {\n  const replacement = await passwords.hashPasswordAsync('test');\n  console.log(replacement); // Store this in place of oldHash.\n}\n```\n\nPasswords over 72 UTF-8 bytes can be verified against portable hashes, but cannot\nbe passed to `hashPassword()`: choose an explicit account migration/reset policy\nfor those records rather than silently truncating their passwords.\n\n## API and limits\n\n```js\nconst passwords = new PasswordHash(10, false, {\n  maxBcryptCost: 16,\n  maxPortableCost: 20,\n});\n```\n\nThe first argument is the bcrypt generation cost (default `10`). Verification\nreads the cost from the **stored hash**, independently of that setting. The\nsecond argument must remain `false`: portable hash generation is unsupported.\nThe optional third argument bounds verification work before hashing begins.\n\n| Method | Returns |\n| --- | --- |\n| `hashPassword(password)` | A bcrypt hash; blocks until complete |\n| `hashPasswordAsync(password)` | `Promise<string>`; bcrypt work yields between chunks |\n| `checkPassword(password, storedHash)` | Whether a supported hash matches; blocks until complete |\n| `checkPasswordAsync(password, storedHash)` | `Promise<boolean>`; portable work uses a worker thread |\n| `checkPasswordLegacy(password, storedHash)` | Whether an explicitly identified node-phpass 0.1.x hash matches |\n\nPasswords are strings encoded as UTF-8. New bcrypt passwords may contain at most\n72 bytes. Verification accepts up to 4,096 UTF-8 bytes; bcrypt retains its\nhistorical 72-byte truncation behavior when checking an existing hash. Legacy\nverification instead limits the old representation to 4,096 UTF-16 code units.\n\nMalformed, unsupported, and over-policy hashes return `false`. Non-string\npasswords and invalid configuration throw (async methods reject). Hashing errors,\nsuch as an unavailable MD5 implementation in a restricted crypto runtime, also\npropagate. Generation cost must be an integer from 4 through `maxBcryptCost`;\nverification ceilings allow 4–31 for bcrypt and 7–30 for portable hashes. Each\ncost increment doubles the work, so choose ceilings for your stored database\nand workload before increasing them.\n\nAsync methods do not impose a concurrency limit. Bound concurrent verification\nin your application, particularly portable verification, which starts one\nworker per call. Sync methods run on the calling thread. None of these methods\nhandles account storage, login throttling, or session management.\n\n## Upgrading from 0.1.x\n\nVersion 1 deliberately changes several behaviors:\n\n- New salts use cryptographic randomness; the bundled `Math.random()` salt path\n  is replaced. The default generation cost increases from 8 to 10.\n- Verification uses each stored hash's cost. You no longer need a separate\n  `PasswordHash` instance matching every record's original cost.\n- New passwords use standard UTF-8 bcrypt encoding and reject inputs beyond\n  72 bytes. Generated hashes use `$2b$`.\n- Malformed/unsupported hashes return `false`, configuration is validated, and\n  verification costs are bounded. TypeScript declarations are included.\n\n**Identify records created by node-phpass 0.1.x before migrating non-ASCII\npasswords.** That release reduced UTF-16 code units to individual low bytes,\nwhich is not UTF-8 and can map different passwords to the same byte sequence.\nFor those records only, use `checkPasswordLegacy()`, then replace the hash after\na successful check. It is synchronous and retains the old encoding behavior\nsolely for migration. The normal verification methods never fall back to it\nautomatically. The `$2a$` prefix alone does not identify a node-phpass record.\n\nSee [CHANGELOG.md](CHANGELOG.md) for release details.\n\n## Development\n\n```sh\nnpm ci\nnpm test\nnpm run test:types\nnpm run test:coverage\nnpm pack --dry-run\n```\n\nCI runs on Node.js 22, 24, and 26. Tests cross-check standard hashes with native\nbcrypt, portable hashes with Openwall-generated fixtures, and legacy hashes with\nfixtures generated by node-phpass 0.1.1. Native bcrypt is a development-only\noracle and is not installed by package consumers.\n\n## License and credits\n\n[MIT](LICENSE), with original code copyright © 2011 Cull TV, Inc.\nThe legacy bcrypt implementation was originally credited to\n[jsBCrypt](https://code.google.com/archive/p/javascript-bcrypt/) under the New BSD\nlicense. Portable verification follows Solar Designer's public-domain algorithm;\nstandard bcrypt is provided by bcrypt.js. See [THIRD_PARTY.md](THIRD_PARTY.md).\n","homepage":"https://github.com/jhurliman/node-phpass#readme","repository":{"url":"git+https://github.com/jhurliman/node-phpass.git","type":"git"},"bugs":{"url":"https://github.com/jhurliman/node-phpass/issues"},"license":"MIT","readmeFilename":"README.md"}