├── .gitignore
├── .npmrc
├── .travis.yml
├── LICENSE
├── README.md
├── browser.html
├── cli.js
├── index.js
├── package.json
├── screenshot.png
├── test.js
└── webpack.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "5"
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Dheeraj Joshi
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # passw0rd [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![XO code style][xo-image]][xo-url]
2 |
3 | [travis-image]: https://img.shields.io/travis/djadmin/passw0rd/master.svg
4 | [travis-url]: https://travis-ci.org/djadmin/passw0rd
5 | [npm-image]: https://img.shields.io/npm/v/passw0rd.svg
6 | [npm-url]: https://npmjs.org/package/passw0rd
7 | [xo-image]: https://img.shields.io/badge/code_style-XO-5ed9c7.svg
8 | [xo-url]: https://github.com/xojs/xo
9 |
10 | 🔑 securely checks a password to see if it has been previously exposed in a data breach
11 |
12 | ## CLI 💻
13 |
14 | * Keeps your password hidden
15 | * Clears your clipboard automatically
16 |
17 | ### Installation 🚀
18 |
19 | Ensure you have Node.js version 5 or higher installed. Then run the following:
20 |
21 | ```$ npm install --global passw0rd```
22 |
23 | ### Checking your password 🔍
24 |
25 | ```$ passw0rd```
26 |
27 | 
28 |
29 | ## API 📝
30 |
31 | ### Installation
32 |
33 | ```$ npm install passw0rd```
34 |
35 | ### Usage
36 |
37 | ```js
38 | const passw0rd = require('passw0rd');
39 |
40 | passw0rd.check('passw0rd').then(res => {
41 | console.log(`Password was found ${res.count} times`);
42 | });
43 | ```
44 |
45 | **Browser**
46 |
47 | Run the following command to get [UMD](https://github.com/umdjs/umd) version of the library under the `dist` folder
48 |
49 | `$ npm run build`
50 |
51 | ```html
52 |
53 | ```
54 | You can find the library on `window.passw0rd`. A very simple POC is available at [browser.html](./browser.html)
55 |
56 | ## How it works ⚙
57 |
58 | [Pwned Passwords](https://www.troyhunt.com/ive-just-launched-pwned-passwords-version-2/) has implemented a k-Anonymity model that allows a password to be searched for by partial hash. This allows the first 5 characters of a SHA-1 password hash (not case-sensitive) to be passed to the API.
59 |
60 | `GET https://api.pwnedpasswords.com/range/{first 5 hash chars}`
61 |
62 | **passw0rd** is using [Pwned Passwords API](https://haveibeenpwned.com/API/v2#PwnedPasswords) which searches through a database of more than 500 million passwords collected from various breaches.
63 |
64 | ## Todo
65 |
66 | * Add CLI Help Menu
67 | * Add Icon / GIF
68 | * Add babel
69 | * Reduce bundle size using webpack
70 | * Write unit test cases
71 | * Improve performance for browser api
72 | * Improve browser POC
73 | * Move cli/lib to a different repo
74 | * Add security checks
75 | * Add to node-awesomejs
76 |
77 | ## FAQ - Why is it named passw0rd? 💫
78 |
79 | > `passw0rd` is one of the most commonly used passwords and has been found 200297 times in various data breaches!
80 |
81 | ## See Also
82 |
83 | * Active Directory - [Checking for Breached Passwords in Active Directory](https://jacksonvd.com/checking-for-breached-passwords-ad-using-k-anonymity/)
84 | * 1Password - [Check your 1password exported passwords](https://github.com/eblin/1passpwnedcheck)
85 |
86 | ## License
87 |
88 | MIT © [Dheeraj Joshi](https://djadmin.in)
89 |
--------------------------------------------------------------------------------
/browser.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | passw0rd.js demo
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
25 |
--------------------------------------------------------------------------------
/cli.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict';
3 |
4 | const Prompt = require('prompt-password');
5 | const clipboardy = require('clipboardy');
6 | const cowsay = require('cowsay');
7 | const chalk = require('chalk');
8 | const logSymbols = require('log-symbols');
9 | const boxen = require('boxen');
10 | const passw0rd = require('.');
11 |
12 | const prompt = new Prompt({
13 | type: 'password',
14 | message: 'Enter your password please',
15 | name: 'pass'
16 | });
17 |
18 | let isCopied = false; // For clipboard checking
19 |
20 | /**
21 | * Check clipboard if the given password was copied
22 | * @param {string} pass - The password to check
23 | */
24 | const checkClipboard = pass => {
25 | return clipboardy.readSync() === pass;
26 | };
27 |
28 | /**
29 | * Clear clipboard util
30 | * @param {string} res - Result from the pwned password
31 | */
32 | const clearClipboard = res => {
33 | if (!isCopied) {
34 | return;
35 | }
36 | console.log(`\n${logSymbols.info} clearing clipboard...`);
37 | // Appreciate :)
38 | clipboardy.writeSync(res.pwned ? '' : '😇 Thanks for using a strong password');
39 | };
40 |
41 | const showWarning = () => {
42 | const msg = `This password should ${chalk.red('never')} be used.`;
43 | // Use a password manager to have strong, unique passwords for each app
44 | const opt = {
45 | padding: 1,
46 | margin: 0,
47 | align: 'center',
48 | borderColor: 'yellow',
49 | borderStyle: 'round'
50 | };
51 | console.log(boxen(msg, opt));
52 | };
53 |
54 | /**
55 | * Display information for the given password
56 | * @param {Object} res - results obtained from passw0rd check
57 | */
58 | const showResult = res => {
59 | const messages = {
60 | pwned: `${logSymbols.error} Pwned ${chalk.yellow(res.count)} times!`,
61 | safe: `${logSymbols.success} Yay! No records found!`
62 | };
63 | console.log();
64 | if (res.pwned) {
65 | console.log(cowsay.think({text: messages.pwned, e: 'oO'}));
66 | showWarning();
67 | } else {
68 | console.log(cowsay.say({text: messages.safe, f: 'tux'}));
69 | }
70 | return res;
71 | };
72 |
73 | /**
74 | * Check given password
75 | * @param {string} pass - user provided password
76 | */
77 | const checkPass = pass => {
78 | if (!pass) {
79 | console.error(`${logSymbols.warning} Specify a password`);
80 | process.exit(1);
81 | }
82 | isCopied = checkClipboard(pass);
83 | return passw0rd.check(pass);
84 | };
85 |
86 | prompt.run()
87 | .then(checkPass)
88 | .then(showResult)
89 | .then(clearClipboard);
90 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const sha1 = require('js-sha1');
3 | const fetch = require('node-fetch');
4 |
5 | /**
6 | * Search for a hash in a list of hashes separately
7 | * @param {string} body - A list of partially matches hashed
8 | * @param {string} hash - A hash to be matched
9 | * @returns {Object} returns { boolean, count }
10 | */
11 | const search = (body, hash) => {
12 | const result = {pwned: false, count: 0};
13 |
14 | // Every password hash is followed by a colon (:) and the password count
15 | const pattern = new RegExp(hash + ':(\\d+)');
16 | const match = body.match(pattern);
17 | if (match) {
18 | result.pwned = true;
19 | result.count = match[1];
20 | }
21 | return result;
22 | };
23 |
24 | /**
25 | * Check if a password has appeared in any data breach
26 | * using hibp (https://haveibeenpwned.com/Passwords) API
27 | * @param {string} pass - The password to check
28 | * @returns {Promise