-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
173 lines (151 loc) · 5.8 KB
/
Copy pathscript.js
File metadata and controls
173 lines (151 loc) · 5.8 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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
const pwInput = document.getElementById('pw');
const dialFill = document.getElementById('dialFill');
const dialWrap = document.getElementById('dialWrap');
const scoreNum = document.getElementById('scoreNum');
const scoreLabel = document.getElementById('scoreLabel');
const strengthTag = document.getElementById('strengthTag');
const strengthText = document.getElementById('strengthText');
const crackTimeEl = document.getElementById('crackTime');
const hint = document.getElementById('hint');
const hintText = document.getElementById('hintText');
const CIRC = 2 * Math.PI * 90; // 565.48
const COMMON = new Set(["123456","password","123456789","12345678","12345","qwerty",
"abc123","111111","123123","admin","letmein","welcome","monkey","football",
"iloveyou","000000","password1","1234567","dragon","master","login"]);
function evaluate(pw){
const checks = {
len: pw.length >= 8,
upper: /[A-Z]/.test(pw),
lower: /[a-z]/.test(pw),
num: /[0-9]/.test(pw),
sym: /[^A-Za-z0-9]/.test(pw),
common: !COMMON.has(pw.toLowerCase())
};
let score = 0;
if (pw.length >= 8) score += 20;
if (pw.length >= 12) score += 15;
if (pw.length >= 16) score += 10;
if (checks.lower) score += 10;
if (checks.upper) score += 15;
if (checks.num) score += 15;
if (checks.sym) score += 15;
if (!checks.common) score = Math.min(score, 20);
if (pw.length === 0) score = 0;
return { checks, score: Math.max(0, Math.min(100, score)) };
}
function crackTimeEstimate(pw){
if (!pw.length) return "—";
let charset = 0;
if (/[a-z]/.test(pw)) charset += 26;
if (/[A-Z]/.test(pw)) charset += 26;
if (/[0-9]/.test(pw)) charset += 10;
if (/[^A-Za-z0-9]/.test(pw)) charset += 32;
if (charset === 0) return "—";
const combos = Math.pow(charset, pw.length);
const guessesPerSecond = 1e10; // offline attack estimate
let seconds = combos / guessesPerSecond / 2;
if (COMMON.has(pw.toLowerCase())) return "Instantly";
const units = [
["century", 60*60*24*365*100],
["year", 60*60*24*365],
["day", 60*60*24],
["hour", 60*60],
["minute", 60],
["second", 1]
];
for (const [name, size] of units){
if (seconds >= size){
const val = Math.floor(seconds / size);
return val > 999 ? "Centuries" : `${val.toLocaleString()} ${name}${val===1?'':'s'}`;
}
}
return "Instantly";
}
function setChecklistItem(id, met){
document.getElementById(id).classList.toggle('met', met);
}
function update(){
const pw = pwInput.value;
const { checks, score } = evaluate(pw);
setChecklistItem('chk-len', checks.len);
setChecklistItem('chk-upper', checks.upper);
setChecklistItem('chk-lower', checks.lower);
setChecklistItem('chk-num', checks.num);
setChecklistItem('chk-sym', checks.sym);
setChecklistItem('chk-common', checks.common);
const offset = CIRC - (CIRC * score / 100);
dialFill.style.strokeDashoffset = offset;
let color, label, tagText;
if (pw.length === 0){
color = 'rgba(22,35,58,0.15)'; label = 'Empty'; tagText = 'Enter a password';
} else if (score < 40){
color = 'var(--danger)'; label='Weak'; tagText='Weak — easy to guess';
} else if (score < 70){
color = 'var(--amber)'; label='Medium'; tagText='Medium — getting there';
} else if (score < 90){
color = 'var(--good)'; label='Strong'; tagText='Strong — nicely done';
} else {
color = 'var(--great)'; label='Very Strong'; tagText='Very strong — vault secured';
}
dialFill.style.stroke = color;
scoreNum.innerHTML = score + '<span style="font-size:15px;">/100</span>';
scoreLabel.textContent = label;
strengthTag.style.color = color;
strengthTag.style.background = pw.length ? color + '20' : 'rgba(22,35,58,0.08)';
strengthText.textContent = tagText;
dialWrap.classList.toggle('unlocked', score >= 70);
crackTimeEl.textContent = crackTimeEstimate(pw);
if (pw.length > 0 && score < 70){
let tip = "";
if (!checks.common) tip = "This is a widely used password — attackers try these first.";
else if (!checks.len) tip = "Add more characters — length matters more than complexity.";
else if (!checks.upper) tip = "Mix in an uppercase letter.";
else if (!checks.num) tip = "Add at least one number.";
else if (!checks.sym) tip = "Add a symbol like ! @ # or %.";
else tip = "Try combining a longer phrase with a number and symbol.";
hintText.textContent = tip;
hint.classList.add('show');
} else {
hint.classList.remove('show');
}
}
pwInput.addEventListener('input', update);
document.getElementById('toggleVis').addEventListener('click', () => {
pwInput.type = pwInput.type === 'password' ? 'text' : 'password';
});
document.getElementById('copyBtn').addEventListener('click', async (e) => {
if (!pwInput.value) return;
try {
await navigator.clipboard.writeText(pwInput.value);
const btn = e.currentTarget;
btn.classList.add('copied');
const original = btn.innerHTML;
btn.innerHTML = 'Copied ✓';
setTimeout(() => { btn.classList.remove('copied'); btn.innerHTML = original; }, 1400);
} catch(err){ /* clipboard not available */ }
});
document.getElementById('generateBtn').addEventListener('click', () => {
const lower = "abcdefghijkmnpqrstuvwxyz";
const upper = "ABCDEFGHJKLMNPQRSTUVWXYZ";
const nums = "23456789";
const syms = "!@#$%^&*?-_";
const all = lower + upper + nums + syms;
let pw = [
lower[Math.floor(Math.random()*lower.length)],
upper[Math.floor(Math.random()*upper.length)],
nums[Math.floor(Math.random()*nums.length)],
syms[Math.floor(Math.random()*syms.length)]
];
for (let i = 0; i < 10; i++){
pw.push(all[Math.floor(Math.random()*all.length)]);
}
// shuffle
for (let i = pw.length -1; i>0; i--){
const j = Math.floor(Math.random()*(i+1));
[pw[i], pw[j]] = [pw[j], pw[i]];
}
pwInput.value = pw.join('');
pwInput.type = 'text';
update();
});
update();