Generatepasswd.php example

PHP Detected boxlabs 3 Views Size: 12.14 KB Posted on: Sep 5, 25 @ 11:39 PM
  1. 1<?php
  2. 2/*
  3. 3 * File: generatepasswd.php for Paste
  4. 4 * Just a little Bootstrap 5 tool for the registration page.
  5. 5 * Fully client side generation.
  6. 6 * License: GPLv3
  7. 7 */
  8. 8?><!DOCTYPE html>
  9. 9<html lang="en">
  10. 10<head>
  11. 11 <meta charset="utf-8">
  12. 12 <title>Password Generator</title>
  13. 13 <meta name="viewport" content="width=device-width, initial-scale=1">
  14. 14 <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
  15. 15 <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css" rel="stylesheet">
  16. 16
  17. 17 <style>
  18. 18 /* Keep styles minimal*/
  19. 19 :root {
  20. 20 --brand-blue: #399BFF;
  21. 21 --card-bg: rgba(255,255,255,0.04);
  22. 22 --text-muted: #9aa4ad;
  23. 23 }
  24. 24 @media (prefers-color-scheme: light) {
  25. 25 :root {
  26. 26 --card-bg: #ffffff;
  27. 27 --text-muted: #6c757d;
  28. 28 }
  29. 29 }
  30. 30
  31. 31 body {
  32. 32 font-family: "Fira Sans", system-ui, -apple-system, Segoe UI, Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  33. 33 min-height: 100vh;
  34. 34 display: flex;
  35. 35 flex-direction: column;
  36. 36 background:
  37. 37 radial-gradient(1200px 600px at 10% -10%, rgba(57,155,255,.20), transparent 60%),
  38. 38 radial-gradient(1200px 600px at 110% 10%, rgba(57,155,255,.15), transparent 60%);
  39. 39 }
  40. 40
  41. 41 .page-wrap { flex: 1 0 auto; }
  42. 42 .hero {
  43. 43 text-align: center;
  44. 44 margin-top: 2rem;
  45. 45 margin-bottom: 1.25rem;
  46. 46 }
  47. 47 .hero h1 {
  48. 48 font-weight: 700;
  49. 49 letter-spacing: .2px;
  50. 50 }
  51. 51 .hero p {
  52. 52 color: var(--text-muted);
  53. 53 margin: .5rem 0 0;
  54. 54 }
  55. 55
  56. 56 .generator-card {
  57. 57 background: var(--card-bg);
  58. 58 border: 1px solid rgba(255,255,255,0.08);
  59. 59 border-radius: 1rem;
  60. 60 backdrop-filter: saturate(120%) blur(6px);
  61. 61 }
  62. 62
  63. 63 .password-box {
  64. 64 font-family: "Fira Code", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  65. 65 font-size: 1.125rem;
  66. 66 user-select: all;
  67. 67 letter-spacing: .2px;
  68. 68 }
  69. 69
  70. 70 .btn-perky {
  71. 71 --bs-btn-bg: var(--brand-blue);
  72. 72 --bs-btn-border-color: var(--brand-blue);
  73. 73 --bs-btn-hover-bg: #2f8ae5;
  74. 74 --bs-btn-hover-border-color: #2f8ae5;
  75. 75 --bs-btn-color: #fff;
  76. 76 }
  77. 77
  78. 78 .entropy-badge {
  79. 79 font-variant-numeric: tabular-nums;
  80. 80 }
  81. 81
  82. 82 .footer-note {
  83. 83 color: var(--text-muted);
  84. 84 font-size: .9rem;
  85. 85 }
  86. 86
  87. 87 .range-output {
  88. 88 min-width: 2.5ch;
  89. 89 text-align: right;
  90. 90 display: inline-block;
  91. 91 }
  92. 92 .form-check .form-text {
  93. 93 margin-left: 1.65rem;
  94. 94 margin-top: .25rem;
  95. 95 }
  96. 96 </style>
  97. 97</head>
  98. 98<body>
  99. 99 <main class="page-wrap">
  100. 100 <div class="container">
  101. 101 <div class="hero">
  102. 102 <h1>Generate a Secure Password</h1>
  103. 103 <p>Client-side generator &mdash; No data leaves your browser</p>
  104. 104 </div>
  105. 105
  106. 106 <div class="row justify-content-center">
  107. 107 <div class="col-12 col-lg-8">
  108. 108 <div class="generator-card shadow-sm p-3 p-md-4">
  109. 109 <!-- Output -->
  110. 110 <div class="mb-3">
  111. 111 <label class="form-label fw-semibold">Password</label>
  112. 112 <div class="input-group">
  113. 113 <input id="out" type="text" class="form-control password-box" readonly aria-describedby="copyBtn">
  114. 114 <button id="regenBtn" class="btn btn-outline-secondary" type="button" title="Regenerate">
  115. 115 <i class="bi bi-arrow-repeat"></i>
  116. 116 </button>
  117. 117 <button id="copyBtn" class="btn btn-perky fw-semibold" type="button" title="Copy to clipboard">
  118. 118 <i class="bi bi-clipboard-check"></i> Copy
  119. 119 </button>
  120. 120 </div>
  121. 121 <div class="d-flex align-items-center gap-3 mt-2">
  122. 122 <span class="badge text-bg-secondary entropy-badge" id="entropyBadge" title="Estimated entropy in bits">— bits</span>
  123. 123 <span id="strengthLabel" class="small"></span>
  124. 124 </div>
  125. 125 </div>
  126. 126
  127. 127 <hr class="my-4">
  128. 128
  129. 129 <!-- Controls -->
  130. 130 <form class="row gy-3">
  131. 131 <div class="col-12 col-md-6">
  132. 132 <label for="len" class="form-label fw-semibold">Length:
  133. 133 <span class="range-output" id="lenOut">16</span>
  134. 134 </label>
  135. 135 <input id="len" type="range" class="form-range" min="8" max="64" step="1" value="16" aria-describedby="lenHelp">
  136. 136 <div id="lenHelp" class="form-text">Longer is stronger; 16–24 is a great default.</div>
  137. 137 </div>
  138. 138
  139. 139 <div class="col-12 col-md-6">
  140. 140 <div class="row">
  141. 141 <div class="col-6">
  142. 142 <div class="form-check">
  143. 143 <input class="form-check-input" type="checkbox" id="lower" checked>
  144. 144 <label class="form-check-label" for="lower">Lowercase (az)</label>
  145. 145 </div>
  146. 146 <div class="form-check">
  147. 147 <input class="form-check-input" type="checkbox" id="upper" checked>
  148. 148 <label class="form-check-label" for="upper">Uppercase (AZ)</label>
  149. 149 </div>
  150. 150 </div>
  151. 151 <div class="col-6">
  152. 152 <div class="form-check">
  153. 153 <input class="form-check-input" type="checkbox" id="digits" checked>
  154. 154 <label class="form-check-label" for="digits">Digits (0–9)</label>
  155. 155 </div>
  156. 156 <div class="form-check">
  157. 157 <input class="form-check-input" type="checkbox" id="symbols" checked>
  158. 158 <label class="form-check-label" for="symbols">Symbols (!@#$…)</label>
  159. 159 </div>
  160. 160 </div>
  161. 161 </div>
  162. 162 <div class="form-check mt-2">
  163. 163 <input class="form-check-input" type="checkbox" id="noAmbig" checked>
  164. 164 <label class="form-check-label" for="noAmbig">Avoid ambiguous characters</label>
  165. 165 <div class="form-text">Skips look-alikes like <code>O</code>/<code>0</code>, <code>l</code>/<code>1</code>, <code>{}</code>/<code>[]</code>.</div>
  166. 166 </div>
  167. 167 </div>
  168. 168
  169. 169 <div class="col-12">
  170. 170 <div class="d-flex gap-2">
  171. 171 <button type="button" id="generateBtn" class="btn btn-perky fw-semibold">
  172. 172 <i class="bi bi-magic"></i> Generate
  173. 173 </button>
  174. 174 <button type="button" id="copyBtn2" class="btn btn-outline-secondary">
  175. 175 <i class="bi bi-clipboard"></i> Copy
  176. 176 </button>
  177. 177 </div>
  178. 178 </div>
  179. 179 </form>
  180. 180
  181. 181 <div class="mt-4 footer-note">
  182. 182 Tip: Use a unique password for every site. Consider a password manager.
  183. 183 </div>
  184. 184 </div>
  185. 185
  186. 186 <div class="text-center mt-3">
  187. 187 <a class="small text-decoration-underline" href="/" aria-label="Back to Paste">← Back to Paste</a>
  188. 188 </div>
  189. 189 </div>
  190. 190 </div>
  191. 191 </div>
  192. 192 </main>
  193. 193
  194. 194 <script>
  195. 195 (function () {
  196. 196 "use strict";
  197. 197
  198. 198 const $ = (id) => document.getElementById(id);
  199. 199
  200. 200 const lowerChars = "abcdefghijklmnopqrstuvwxyz";
  201. 201 const upperChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  202. 202 const digitChars = "0123456789";
  203. 203 const symbolChars = "!@#$%^&*()-_=+[]{};:,.<>/?~";
  204. 204 const ambiguous = "O0oIl1|[]{}()<>`'\".,;:~";
  205. 205
  206. 206 const len = $("len");
  207. 207 const lenOut = $("lenOut");
  208. 208 const lower = $("lower");
  209. 209 const upper = $("upper");
  210. 210 const digits = $("digits");
  211. 211 const symbols = $("symbols");
  212. 212 const noAmbig = $("noAmbig");
  213. 213
  214. 214 const out = $("out");
  215. 215 const generateBtn = $("generateBtn");
  216. 216 const regenBtn = $("regenBtn");
  217. 217 const copyBtn = $("copyBtn");
  218. 218 const copyBtn2 = $("copyBtn2");
  219. 219 const entropyBadge = $("entropyBadge");
  220. 220 const strengthLabel= $("strengthLabel");
  221. 221
  222. 222 function updateLenOutput() {
  223. 223 lenOut.textContent = String(len.value);
  224. 224 }
  225. 225
  226. 226 function buildCharset() {
  227. 227 let set = "";
  228. 228 if (lower.checked) set += lowerChars;
  229. 229 if (upper.checked) set += upperChars;
  230. 230 if (digits.checked) set += digitChars;
  231. 231 if (symbols.checked) set += symbolChars;
  232. 232 if (noAmbig.checked) {
  233. 233 set = [...set].filter(ch => !ambiguous.includes(ch)).join("");
  234. 234 }
  235. 235 return Array.from(new Set(set)).join(""); // dedupe
  236. 236 }
  237. 237
  238. 238 function getRandomValues(length) {
  239. 239 const arr = new Uint32Array(length);
  240. 240 if (window.crypto && window.crypto.getRandomValues) {
  241. 241 window.crypto.getRandomValues(arr);
  242. 242 } else {
  243. 243 // Fallback (should almost never happen): use Math.random
  244. 244 for (let i = 0; i < length; i++) arr[i] = Math.floor(Math.random() * 0xFFFFFFFF);
  245. 245 }
  246. 246 return arr;
  247. 247 }
  248. 248
  249. 249 function generatePassword() {
  250. 250 const L = parseInt(len.value, 10);
  251. 251 let charset = buildCharset();
  252. 252 if (!charset) {
  253. 253 alert("Please select at least one character set.");
  254. 254 return;
  255. 255 }
  256. 256 // Ensure we sample uniformly from charset using rejection sampling
  257. 257 const chars = Array.from(charset);
  258. 258 const n = chars.length;
  259. 259 const outChars = [];
  260. 260 const rand = getRandomValues(L * 2); // buffer
  261. 261 let i = 0;
  262. 262
  263. 263 const max = Math.floor(0x100000000 / n) * n; // highest multiple of n below 2^32
  264. 264
  265. 265 for (let produced = 0; produced < L; ) {
  266. 266 if (i >= rand.length) {
  267. 267 // refill
  268. 268 const refill = getRandomValues(L);
  269. 269 for (let k = 0; k < refill.length; k++) rand[k] = refill[k];
  270. 270 i = 0;
  271. 271 }
  272. 272 const r = rand[i++];
  273. 273 if (r < max) {
  274. 274 outChars.push(chars[r % n]);
  275. 275 produced++;
  276. 276 }
  277. 277 }
  278. 278
  279. 279 const pwd = outChars.join("");
  280. 280 out.value = pwd;
  281. 281 updateStrength(pwd, n);
  282. 282 }
  283. 283
  284. 284 function log2(x) { return Math.log(x) / Math.log(2); }
  285. 285
  286. 286 function updateStrength(pwd, charsetSize) {
  287. 287 const L = pwd.length || 0;
  288. 288 // Shannon-style estimate (assuming uniform random from charset)
  289. 289 const bits = Math.round(L * log2(Math.max(2, charsetSize)));
  290. 290 entropyBadge.textContent = bits + " bits";
  291. 291
  292. 292 let label = "";
  293. 293 let cls = "text-secondary";
  294. 294 if (bits < 45) { label = "Weak"; cls = "text-danger"; }
  295. 295 else if (bits < 64) { label = "Fair"; cls = "text-warning"; }
  296. 296 else if (bits < 90) { label = "Strong"; cls = "text-success"; }
  297. 297 else { label = "Excellent"; cls = "text-success"; }
  298. 298
  299. 299 strengthLabel.className = "small " + cls;
  300. 300 strengthLabel.textContent = label + " (charset " + charsetSize + ", length " + L + ")";
  301. 301 }
  302. 302
  303. 303 function copyToClipboard() {
  304. 304 out.select();
  305. 305 out.setSelectionRange(0, 99999);
  306. 306 navigator.clipboard?.writeText(out.value).then(() => {
  307. 307 flashCopied(copyBtn);
  308. 308 flashCopied(copyBtn2);
  309. 309 }).catch(() => {
  310. 310 // Fallback
  311. 311 document.execCommand("copy");
  312. 312 flashCopied(copyBtn);
  313. 313 flashCopied(copyBtn2);
  314. 314 });
  315. 315 }
  316. 316
  317. 317 function flashCopied(btn) {
  318. 318 if (!btn) return;
  319. 319 const original = btn.innerHTML;
  320. 320 btn.innerHTML = '<i class="bi bi-check2-circle"></i> Copied';
  321. 321 btn.disabled = true;
  322. 322 setTimeout(() => {
  323. 323 btn.innerHTML = original;
  324. 324 btn.disabled = false;
  325. 325 }, 1200);
  326. 326 }
  327. 327
  328. 328 // Events
  329. 329 len.addEventListener("input", updateLenOutput);
  330. 330 generateBtn.addEventListener("click", generatePassword);
  331. 331 regenBtn.addEventListener("click", generatePassword);
  332. 332 copyBtn.addEventListener("click", copyToClipboard);
  333. 333 copyBtn2.addEventListener("click", copyToClipboard);
  334. 334 [lower, upper, digits, symbols, noAmbig].forEach(el => {
  335. 335 el.addEventListener("change", generatePassword);
  336. 336 });
  337. 337
  338. 338 // Init
  339. 339 updateLenOutput();
  340. 340 generatePassword();
  341. 341 })();
  342. 342 </script>
  343. 343</body>
  344. 344</html>

Raw Paste

Comments 0
Login to join the discussion
  • No comments yet — be the first!
Login to post a comment. Login
We use cookies. To comply with GDPR in the EU and the UK we have to show you these.

We use cookies and similar technologies to keep this website functional (including spam protection via Google reCAPTCHA), and — with your consent — to measure usage and show ads. See Privacy.