Secure Password Generator

安全密碼生成器 (純前端單檔案版)

💡 設計亮點 / Key Features:
原始碼使用說明 / How to Use

請將下方代碼複製並儲存為 index.html 檔案,直接上傳到您的伺服器、次網域(例如 password.mbsharesite.com)即可完美運作。無須任何後端資料庫。

Save the code below as index.html and host it anywhere. It runs fully client-side without any server-side database requirements.

完整原始碼 / Complete Source Code (index.html)
<!DOCTYPE html> <html lang="zh-Hant"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Secure Password Generator | 安全密碼生成器</title> <style> :root { --primary: #2563eb; --primary-hover: #1d4ed8; --bg: #f8fafc; --card-bg: #ffffff; --text: #0f172a; --text-light: #64748b; --border: #e2e8f0; --success: #16a34a; } * { box-sizing: border-box; margin: 0; padding: 0; font-family: -apple-system, sans-serif; } body { background-color: var(--bg); color: var(--text); padding: 20px; display: flex; justify-content: center; align-items: center; min-height: 100vh; } .wrapper { width: 100%; max-width: 550px; background: var(--card-bg); padding: 30px; border-radius: 16px; box-shadow: 0 10px 25px -5px rgba(0,0,0,0.05); border: 1px solid var(--border); } .lang-switch { display: flex; justify-content: flex-end; gap: 10px; margin-bottom: 20px; } .lang-btn { background: none; border: none; color: var(--primary); cursor: pointer; font-size: 14px; font-weight: 600; } .lang-btn:hover { text-decoration: underline; } h1 { font-size: 24px; text-align: center; margin-bottom: 8px; color: var(--text); } .subtitle { text-align: center; font-size: 14px; color: var(--text-light); margin-bottom: 25px; } .result-container { position: relative; display: flex; background: var(--bg); border: 2px solid var(--border); border-radius: 12px; padding: 15px; margin-bottom: 25px; align-items: center; } .result-input { width: 100%; background: transparent; border: none; outline: none; font-family: monospace; font-size: 18px; font-weight: 600; letter-spacing: 1px; color: var(--text); padding-right: 50px; } .copy-btn { position: absolute; right: 10px; background: var(--primary); color: white; border: none; padding: 8px 14px; border-radius: 8px; cursor: pointer; font-size: 13px; font-weight: 500; transition: background 0.2s; } .copy-btn:hover { background: var(--primary-hover); } .setting-item { display: flex; justify-content: space-between; align-items: center; margin-bottom: 18px; font-size: 15px; } .slider-container { flex-direction: column; align-items: flex-start; gap: 8px; } .slider-header { display: flex; width: 100%; justify-content: space-between; } input[type="range"] { width: 100%; height: 6px; background: var(--border); border-radius: 5px; outline: none; -webkit-appearance: none; } input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 18px; height: 18px; background: var(--primary); border-radius: 50%; cursor: pointer; } input[type="checkbox"] { width: 18px; height: 18px; cursor: pointer; accent-color: var(--primary); } .gen-btn { width: 100%; background: var(--primary); color: white; border: none; padding: 14px; border-radius: 12px; font-size: 16px; font-weight: 600; cursor: pointer; margin-top: 10px; transition: background 0.2s; } .gen-btn:hover { background: var(--primary-hover); } .security-badge { text-align: center; margin-top: 20px; font-size: 12px; color: var(--success); background: #f0fdf4; padding: 8px; border-radius: 8px; display: flex; align-items: center; justify-content: center; gap: 5px; } </style> </head> <body> <div class="wrapper"> <div class="lang-switch"> <button class="lang-btn" onclick="switchLang('en')">English</button> <span style="color:var(--border)">|</span> <button class="lang-btn" onclick="switchLang('zh')">繁體中文</button> </div> <h1 id="title">安全密碼生成器</h1> <div class="subtitle" id="subtitle">100% 瀏覽器本地安全生成,隱私絕不上傳</div> <div class="result-container"> <input type="text" id="password-display" class="result-input" readonly> <button id="copy-btn" class="copy-btn" onclick="copyPassword()">複製 / Copy</button> </div> <div class="setting-item slider-container"> <div class="slider-header"> <span id="label-length">密碼長度</span> <span id="length-val" style="font-weight:bold; color:var(--primary);">16</span> </div> <input type="range" id="length-slider" min="6" max="64" value="16" oninput="updateLengthLabel()"> </div> <div class="setting-item"> <label for="include-uppercase" id="label-uppercase">包含大寫字母 (A-Z)</label> <input type="checkbox" id="include-uppercase" checked> </div> <div class="setting-item"> <label for="include-lowercase" id="label-lowercase">包含小寫字母 (a-z)</label> <input type="checkbox" id="include-lowercase" checked> </div> <div class="setting-item"> <label for="include-numbers" id="label-numbers">包含數字 (0-9)</label> <input type="checkbox" id="include-numbers" checked> </div> <div class="setting-item"> <label for="include-symbols" id="label-symbols">包含特殊符號 (!@#$%^*)</label> <input type="checkbox" id="include-symbols" checked> </div> <button id="gen-btn" class="gen-btn" onclick="generatePassword()">產生隨機密碼</button> <div class="security-badge" id="security-badge"> 🔒 密碼於本地瀏覽器生成,100% 保密 </div> </div> <script> const langPack = { zh: { title: "安全密碼生成器", subtitle: "100% 瀏覽器本地安全生成,隱私絕不上傳", btnCopy: "複製", btnCopied: "已複製!", lblLength: "密碼長度", lblUpper: "包含大寫字母 (A-Z)", lblLower: "包含小寫字母 (a-z)", lblNum: "包含數字 (0-9)", lblSym: "包含特殊符號 (!@#$%^*)", btnGen: "產生隨機密碼", badge: "🔒 密碼於本地瀏覽器生成,100% 保密", alertAlert: "請至少勾選一個字元編組!" }, en: { title: "Secure Password Generator", subtitle: "100% client-side secure generation, privacy guaranteed", btnCopy: "Copy", btnCopied: "Copied!", lblLength: "Password Length", lblUpper: "Include Uppercase (A-Z)", lblLower: "Include Lowercase (a-z)", lblNum: "Include Numbers (0-9)", lblSym: "Include Symbols (!@#$%^*)", btnGen: "Generate Password", badge: "🔒 Generated locally in-browser. Secure & private.", alertAlert: "Please select at least one character set!" } }; let currentLang = 'zh'; function switchLang(lang) { currentLang = lang; const pack = langPack[lang]; document.getElementById('title').innerText = pack.title; document.getElementById('subtitle').innerText = pack.subtitle; document.getElementById('copy-btn').innerText = pack.btnCopy; document.getElementById('label-length').innerText = pack.lblLength; document.getElementById('label-uppercase').innerText = pack.lblUpper; document.getElementById('label-lowercase').innerText = pack.lblLower; document.getElementById('label-numbers').innerText = pack.lblNum; document.getElementById('label-symbols').innerText = pack.lblSym; document.getElementById('gen-btn').innerText = pack.btnGen; document.getElementById('security-badge').innerText = pack.badge; } function updateLengthLabel() { document.getElementById('length-val').innerText = document.getElementById('length-slider').value; } function generatePassword() { const length = parseInt(document.getElementById('length-slider').value); const hasUpper = document.getElementById('include-uppercase').checked; const hasLower = document.getElementById('include-lowercase').checked; const hasNum = document.getElementById('include-numbers').checked; const hasSym = document.getElementById('include-symbols').checked; const upperChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const lowerChars = "abcdefghijklmnopqrstuvwxyz"; const numChars = "0123456789"; const symChars = "!@#$%^&*()_+~`|}{[]:;?><,./-="; let charPool = ""; if (hasUpper) charPool += upperChars; if (hasLower) charPool += lowerChars; if (hasNum) charPool += numChars; if (hasSym) charPool += symChars; if (charPool === "") { alert(langPack[currentLang].alertAlert); return; } let password = ""; // Use cryptographically secure pseudorandom number generator (CSPRNG) const randomValues = new Uint32Array(length); window.crypto.getRandomValues(randomValues); for (let i = 0; i < length; i++) { password += charPool.charAt(randomValues[i] % charPool.length); } document.getElementById('password-display').value = password; document.getElementById('copy-btn').innerText = currentLang === 'zh' ? langPack.zh.btnCopy : langPack.en.btnCopy; } function copyPassword() { const passInput = document.getElementById('password-display'); if (!passInput.value) return; passInput.select(); passInput.setSelectionRange(0, 99999); navigator.clipboard.writeText(passInput.value); const copyBtn = document.getElementById('copy-btn'); copyBtn.innerText = langPack[currentLang].btnCopied; setTimeout(() => { copyBtn.innerText = currentLang === 'zh' ? langPack.zh.btnCopy : langPack.en.btnCopy; }, 2000); } // Auto-generate on load window.onload = function() { generatePassword(); }; </script> </body> </html>