Skip to content

Commit

Permalink
API call to PwnedPasswords
Browse files Browse the repository at this point in the history
  • Loading branch information
hotblac committed Jul 31, 2018
1 parent 24a2665 commit 9188419
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 2 deletions.
42 changes: 42 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-scripts": "1.1.4",
"react-test-renderer": "^16.4.1"
"react-test-renderer": "^16.4.1",
"sha1": "^1.1.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"devDependencies": {
"jest-fetch-mock": "^1.6.5"
}
}
21 changes: 21 additions & 0 deletions src/Pwnedpasswords.api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const sha1 = require('sha1');

/**
* Check given password agains pwnedpasswords API.
* @param password
* @returns
* @link https://haveibeenpwned.com/API/v2#SearchingPwnedPasswordsByRange
*/
export const isPasswordPwned = (password) => {

// Send the first 5 digits of the hash to API
const hash = sha1(password);
const prefix = hash.substring(0,5); // First 5 characters of SHA-1 hash
const suffix = hash.substring(5); // Remaining characters of SHA-1 hash

return fetch('https://api.pwnedpasswords.com/range/' + prefix)
.then(response => response.text()) // Response is plain text - 1 result per line
.then(response => response.split(/\r?\n/)) // Make an array of results
.then(lines => lines.map(line => line.split(':')[0].toLowerCase())) // Hash suffix is string up to colon
.then(lines => lines.includes(suffix.toLowerCase()));
};
42 changes: 42 additions & 0 deletions src/Pwnedpasswords.api.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {isPasswordPwned} from "./Pwnedpasswords.api";

describe('isPasswordPwned', () => {

const password = 'password';
const uniquePassword = 'aPasswordNotInThePwnedList';

/**
* First 5 characters of SHA-1 hash of password
* @type {string}
*/
const expectedHashPrefix = '5baa6';

/**
* Partial response from API
* https://api.pwnedpasswords.com/range/5baa6
* @type {string}
*/
const apiResponse = '1E2AAA439972480CEC7F16C795BBB429372:1\n' +
'1E3687A61BFCE35F69B7408158101C8E414:1\n' +
'1E4C9B93F3F0682250B6CF8331B7EE68FD8:3533661'; // This hash corresponds to 'password'

beforeEach(() => {
fetch.resetMocks();
fetch.mockResponseOnce(apiResponse);
});

it('requests pwned passwords by partial hash', () => {
isPasswordPwned(password);
expect(fetch.mock.calls[0][0]).toBe('https://api.pwnedpasswords.com/range/' + expectedHashPrefix);
});

it('returns true when password is pwned', async () => {
const result = await isPasswordPwned(password);
expect(result).toBe(true);
});

it('returns false when password is not pwned', async () => {
const result = await isPasswordPwned(uniquePassword);
expect(result).toBe(false);
});
});
4 changes: 3 additions & 1 deletion src/setupTests.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

configure({ adapter: new Adapter() });
configure({ adapter: new Adapter() });

global.fetch = require('jest-fetch-mock')

0 comments on commit 9188419

Please sign in to comment.