-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
150 lines (130 loc) · 5.86 KB
/
index.html
File metadata and controls
150 lines (130 loc) · 5.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Password Generator — Secure & Memorable</title>
<!-- Content Security Policy: only allow self for scripts/styles, no connections -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self' data:; connect-src 'self'; font-src 'self';">
<link rel="stylesheet" href="style.css">
<meta name="description" content="Client-only secure password generator (passphrase & character modes) — entropy & crack time estimates." />
</head>
<body>
<header class="site-header">
<div class="container">
<h1>Password Generator</h1>
<p class="subtitle">Memorable · Unpredictable · Secure — all client-side</p>
</div>
</header>
<main class="container main-grid" id="app">
<section class="panel options" aria-labelledby="optionsTitle">
<h2 id="optionsTitle">Options</h2>
<div class="row">
<label for="modeSelect">Mode</label>
<select id="modeSelect" aria-label="Mode select">
<option value="passphrase">Passphrase (memorable)</option>
<option value="character">Character (random chars)</option>
</select>
</div>
<fieldset class="fieldset">
<legend>Presets</legend>
<div class="preset-row">
<button id="presetEasy" class="btn-preset">Easy</button>
<button id="presetMedium" class="btn-preset">Medium</button>
<button id="presetHard" class="btn-preset">Hard</button>
</div>
</fieldset>
<div id="passphraseOptions">
<div class="row">
<label for="numWords">Words</label>
<input id="numWords" type="number" min="2" max="8" value="4" />
</div>
<div class="row">
<label for="separator">Separator</label>
<select id="separator">
<option value="-">hyphen (-)</option>
<option value="_">underscore (_)</option>
<option value=".">dot (.)</option>
<option value="">none</option>
<option value=" ">space</option>
</select>
</div>
<div class="row">
<label for="personalInput">Seed / Personal hint (optional)</label>
<input id="personalInput" type="text" placeholder="e.g., nick or pet name" maxlength="20">
</div>
<div class="checkbox-grid">
<label><input type="checkbox" id="enableCap" checked> Random capitalisation</label>
<label><input type="checkbox" id="enableLeet"> Leet substitutions</label>
<label><input type="checkbox" id="enableInsertExtras" checked> Insert digits/symbols</label>
</div>
</div>
<div id="characterOptions" style="display:none;">
<div class="row">
<label for="charLength">Length</label>
<input id="charLength" type="number" min="6" max="64" value="16" />
</div>
<div class="checkbox-grid">
<label><input type="checkbox" id="includeLower" checked> a–z</label>
<label><input type="checkbox" id="includeUpper" checked> A–Z</label>
<label><input type="checkbox" id="includeDigits" checked> 0–9</label>
<label><input type="checkbox" id="includeSymbols" checked> Symbols</label>
</div>
</div>
<fieldset class="fieldset">
<legend>Attacker model</legend>
<div class="row">
<label for="guessRate">Guesses / sec</label>
<input id="guessRate" type="number" min="1e3" step="1" value="10000000000" />
</div>
<p class="muted small">Default: 10,000,000,000 guesses/sec (10 billion). Modify to compare attacker strength.</p>
</fieldset>
<div class="action-row">
<button id="estimateBtn" class="btn primary">Show Estimate</button>
<button id="generateBtn" class="btn primary">Generate</button>
<button id="regenBtn" class="btn" disabled>Regenerate</button>
</div>
<details class="notes">
<summary>Security notes</summary>
<ul>
<li>All generation is client-side. No network, no storage.</li>
<li>Uses secure RNG: <code>crypto.getRandomValues</code>.</li>
<li>Clipboard access is user-initiated only.</li>
</ul>
</details>
</section>
<section class="panel preview" aria-labelledby="previewTitle">
<h2 id="previewTitle">Preview & Estimates</h2>
<div class="estimate pre-estimate" id="preEstimate" aria-live="polite">
<h3>Pre-generation estimate</h3>
<p id="preBits">Bits of entropy: —</p>
<p id="preCrack">Estimated time to crack: —</p>
</div>
<div class="generated" id="generated" aria-live="polite">
<h3>Generated password</h3>
<div class="password-row">
<input id="passwordOutput" readonly aria-label="Generated password">
<div class="pw-actions">
<button id="copyBtn" class="btn" disabled>Copy</button>
<button id="downloadBtn" class="btn" disabled>Download</button>
<button id="showHideBtn" class="btn" disabled>Show</button>
</div>
</div>
<div class="post-estimate" id="postEstimate">
<p id="postBits">Bits of entropy: —</p>
<p id="postCrack">Estimated time to crack: —</p>
</div>
<div class="history" id="history">
<h4>Last actions</h4>
<ul id="historyList"></ul>
</div>
</div>
</section>
</main>
<footer class="container footer">
<p>Single-file static app (scripts/styles external). Good for portfolio — see README for notes.</p>
</footer>
<script src="script.js" defer></script>
</body>
</html>