├── logo.jpg ├── favicon.ico ├── logo-social.jpg ├── README.md ├── make-hell.js ├── make-hell-pretty.css ├── log-hell.js └── index.html /logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/troyhunt/password-purgatory/HEAD/logo.jpg -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/troyhunt/password-purgatory/HEAD/favicon.ico -------------------------------------------------------------------------------- /logo-social.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/troyhunt/password-purgatory/HEAD/logo-social.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # password-purgatory 2 | Deliberately making password creation hell 3 | 4 | Contributions welcome! Here's what needs to be done: 5 | 6 | 1. Hook into form submission on the front page to run the password against the API 7 | 2. Build up make-hell.js such that it can be dropped in anywhere 8 | 3. Add the API docs at the bottom of the page 9 | 4. Make it all look pretty and cross-device friendly 😊 10 | 11 | --- 12 | 13 | [Blog post introducing the project](https://www.troyhunt.com/building-password-purgatory-with-cloudflare-pages-and-workers/) 14 | 15 | [Live site](https://password-purgatory.pages.dev/) 16 | 17 | --- 18 | 19 | ## Code Formatting 20 | Had a little Twitter discussion re code formatting here: https://twitter.com/troyhunt/status/1506395329255514112 21 | 22 | Consensus is to use Prettier: https://prettier.io/ 23 | 24 | I'll look at tying this into a GitHub action in the future for further validation. 25 | -------------------------------------------------------------------------------- /make-hell.js: -------------------------------------------------------------------------------- 1 | window.addEventListener("load", function () { 2 | document 3 | .getElementById("passwordPurgatory") 4 | .addEventListener("submit", function (e) { 5 | e.preventDefault(); 6 | 7 | let password = document.getElementById("password").value; 8 | let feedback = document.getElementById("response"); 9 | 10 | submitHell(password, feedback); 11 | 12 | return false; 13 | }); 14 | }); 15 | 16 | async function submitHell(password, feedback) { 17 | // Hide the existing response 18 | feedback.style.display = "none"; 19 | 20 | let url = `https://api.passwordpurgatory.com/make-hell?password=${encodeURIComponent( 21 | password 22 | )}`; 23 | 24 | let headers = new Headers({ 25 | "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", 26 | }); 27 | 28 | let params = { 29 | headers, 30 | mode: "cors", 31 | }; 32 | 33 | let response = await fetch(url, params); 34 | let json = await response.json(); 35 | 36 | // Add a visible delay before showing the response 37 | setTimeout(function () { 38 | feedback.textContent = json.message; 39 | feedback.style.display = "block"; 40 | }, 900); 41 | } 42 | -------------------------------------------------------------------------------- /make-hell-pretty.css: -------------------------------------------------------------------------------- 1 | body { 2 | height: 100vh; 3 | background-color: black; 4 | font-family: "Courier New", Courier, monospace; 5 | padding: 20px; 6 | } 7 | 8 | body, 9 | a { 10 | color: white; 11 | } 12 | 13 | header { 14 | text-align: center; 15 | } 16 | 17 | header img { 18 | max-width: 100%; 19 | } 20 | 21 | input { 22 | font-size: 2em; 23 | } 24 | 25 | button { 26 | background-color: #fc9707; 27 | font-size: 2em; 28 | } 29 | 30 | h1, 31 | h2 { 32 | color: #fc9707; 33 | } 34 | 35 | h2 { 36 | margin-bottom: 0.2em; 37 | } 38 | 39 | code, 40 | .spammer-hell-summary { 41 | display: inline-block; 42 | background-color: #fadf2e; 43 | border-radius: 4px; 44 | padding: 10px; 45 | color: black; 46 | } 47 | 48 | .spammer-hell-summary { 49 | font-size: 2em; 50 | } 51 | 52 | ol { 53 | padding: 0; 54 | } 55 | 56 | li { 57 | list-style-type: none; 58 | } 59 | 60 | dl { 61 | display: grid; 62 | grid-template-columns: max-content auto; 63 | margin-top: 0.3em; 64 | margin-bottom: 3em; 65 | } 66 | 67 | dt { 68 | grid-column-start: 1; 69 | } 70 | 71 | dd { 72 | grid-column-start: 2; 73 | } 74 | 75 | #search { 76 | text-align: center; 77 | } 78 | 79 | #response { 80 | padding: 10px; 81 | border-radius: 4px; 82 | color: red; 83 | font-size: 2em; 84 | } 85 | -------------------------------------------------------------------------------- /log-hell.js: -------------------------------------------------------------------------------- 1 | window.addEventListener("load", function () { 2 | document 3 | .getElementById("passwordPurgatory") 4 | .addEventListener("submit", function (e) { 5 | e.preventDefault(); 6 | 7 | const params = new Proxy(new URLSearchParams(window.location.search), { 8 | get: (searchParams, prop) => searchParams.get(prop), 9 | }); 10 | 11 | let kvKey = params.kvKey; 12 | let criteria = document.getElementById("response").innerHTML; 13 | let password = document.getElementById("password").value; 14 | 15 | logHell(kvKey, criteria, password); 16 | 17 | return false; 18 | }); 19 | }); 20 | 21 | async function logHell(kvKey, criteria, password) { 22 | (async () => { 23 | // Specify your own domain using the apiDomain varaible. If nothing defined, then stick to the default 24 | let domain = typeof loggerDomain !== 'undefined' ? loggerDomain : "https://api.passwordpurgatory.com"; 25 | const rawResponse = await fetch( 26 | domain + "/log-hell", 27 | { 28 | method: "POST", 29 | headers: { 30 | Accept: "application/json", 31 | "Content-Type": "application/json", 32 | }, 33 | body: JSON.stringify({ 34 | kvKey: kvKey, 35 | criteria: criteria, 36 | password: password, 37 | }), 38 | } 39 | ); 40 | })(); 41 | } 42 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 |
14 | 35 | Password Purgatory is an intentionally infuriating API to request inane 36 | and ultimately unachievable password criteria intended to deliberately 37 | frustrate the user. Regardless of the password used, it will always be 38 | rejected hence subjecting the user to "purgatory". Read more in 39 | the launch blog post. 43 |
44 | 45 |47 | There is a single API endpoint that can be invoked with a GET request 48 | passing the password as a query string: 49 |
50 |GET
52 | https://api.passwordpurgatory.com/make-hell?password={password}
54 |
55 | 57 | A JSON response is returned containing a message describing how the 58 | password did not meet the required criteria: 59 |
60 | { "message": "Password must contain at least 1 number" }
61 |
62 | CORS is enabled to allow calling the API from all origins.
64 | 65 |67 | To orchestrate the request to the API and display of the returned 68 | message, the "make-hell.js" JavaScript file can be directly embedded in 69 | any consuming websites: 70 |
71 |
72 | <script
73 | src="https://passwordpurgatory.com/make-hell.js"></script>
74 |
75 | The script expects the embedding page to provide the following:
76 |ToDo: implement SRI integrity check once version is stable
82 | 83 |
85 | In order to enable logging you will need to first deploy the logger on Cloudflare github.com/troyhunt/password-purgatory-logger.
88 | Once that is done, you will then need to include the following scripts in your code making sure to replace the logger domain with your own Cloudflare worker domain.
89 |
91 | <script>let loggerDomain = "https://my-password-purgatory-logger.my-username.workers.dev";</script>
92 | <script src="https://passwordpurgatory.com/log-hell.js"></script>
93 |
94 |
95 | 97 | All code in Password Purgatory is open source and available on GitHub in 98 | the following repositories: 99 |
100 |