Generatepasswd.php example

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

Raw Paste

Comments 0
Login to post a comment.
  • No comments yet. Be the first.
Login to post a comment. Login or Register
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 or Cloudflare Turnstile), and — with your consent — to measure usage and show ads. See Privacy.