├── 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 | Password Purgatory - Making Life Hell for Spammers 9 | 10 | 11 | 12 |
13 | Password Purgatory 14 |
15 | 16 | 31 | 32 |
33 |

Documentation

34 |

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 |

Request

46 |

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 |

Response

56 |

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 |

Cross-Origin Resource Sharing (CORS)

63 |

CORS is enabled to allow calling the API from all origins.

64 | 65 |

Embedding in an External Website

66 |

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 |
    77 |
  1. A form named "passwordPurgatory"
  2. 78 |
  3. A password field named "password"
  4. 79 |
  5. An element for the response named "response"
  6. 80 |
81 |

ToDo: implement SRI integrity check once version is stable

82 | 83 |

Enabling Logging

84 |

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 |

90 | 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 |

Source Code

96 |

97 | All code in Password Purgatory is open source and available on GitHub in 98 | the following repositories: 99 |

100 |
    101 |
  1. 102 | This website: 103 | github.com/troyhunt/password-purgatory 106 |
  2. 107 |
  3. 108 | The API: 109 | github.com/troyhunt/password-purgatory-api 112 |
  4. 113 |
  5. 114 | The Logger: 115 | github.com/troyhunt/password-purgatory-logger 118 |
  6. 119 |
120 |
121 | 122 | 123 | --------------------------------------------------------------------------------