password-portraits 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,198 @@
1
+ # password-portraits
2
+
3
+ > AI-powered visual password strength analyzer. Generates unique warrior portraits driven by entropy. **Zero-knowledge — the password never leaves the browser.**
4
+
5
+ [![npm](https://img.shields.io/npm/v/password-portraits)](https://www.npmjs.com/package/password-portraits)
6
+ [![license](https://img.shields.io/npm/l/password-portraits)](./LICENSE)
7
+ [![CDN](https://img.shields.io/badge/CDN-jsDelivr-orange)](https://cdn.jsdelivr.net/npm/password-portraits/)
8
+
9
+ ---
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install password-portraits
15
+ # peer deps (required in your project)
16
+ npm install react react-dom
17
+ # optional — only if you use 3D portrait components
18
+ npm install three
19
+ ```
20
+
21
+ ---
22
+
23
+ ## CDN (no build tool needed)
24
+
25
+ ```html
26
+ <!-- UMD bundle -->
27
+ <script src="https://cdn.jsdelivr.net/npm/password-portraits/dist/lib/index.umd.js"></script>
28
+ <!-- Styles -->
29
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/password-portraits/dist/lib/style.css">
30
+
31
+ <!-- unpkg alternative -->
32
+ <script src="https://unpkg.com/password-portraits/dist/lib/index.umd.js"></script>
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Quick Start — React (ESM)
38
+
39
+ ```tsx
40
+ import { PasswordField, SecurityDashboard, ThreatSimulator, Portrait } from 'password-portraits';
41
+ import 'password-portraits/style.css';
42
+
43
+ export default function SignupPage() {
44
+ return (
45
+ <div>
46
+ <PasswordField />
47
+ <SecurityDashboard />
48
+ <ThreatSimulator buttonLabel="Test your password" />
49
+ </div>
50
+ );
51
+ }
52
+ ```
53
+
54
+ ---
55
+
56
+ ## Quick Start — Login / Signup Page
57
+
58
+ You can add password-portraits to any **signup or login form**:
59
+
60
+ ```tsx
61
+ import {
62
+ UsernameField,
63
+ PasswordField,
64
+ SubmitButton,
65
+ SecurityDashboard,
66
+ PasswordChecklist,
67
+ StrengthBadges,
68
+ } from 'password-portraits';
69
+ import 'password-portraits/style.css';
70
+
71
+ export default function SignupPage() {
72
+ return (
73
+ <form>
74
+ <h1>Create Account</h1>
75
+
76
+ {/* Drop-in username + password fields with built-in state */}
77
+ <UsernameField />
78
+ <PasswordField />
79
+
80
+ {/* Real-time visual strength feedback */}
81
+ <StrengthBadges />
82
+ <PasswordChecklist minLength={12} />
83
+ <SecurityDashboard />
84
+
85
+ {/* Submit button — disabled until password meets minScore */}
86
+ <SubmitButton successLabel="Create Account" minScore={45} />
87
+ </form>
88
+ );
89
+ }
90
+ ```
91
+
92
+ ---
93
+
94
+ ## Quick Start — CDN (Vanilla HTML)
95
+
96
+ ```html
97
+ <!DOCTYPE html>
98
+ <html>
99
+ <head>
100
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/password-portraits/dist/lib/style.css">
101
+ </head>
102
+ <body>
103
+ <!-- Required React + ReactDOM first -->
104
+ <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
105
+ <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
106
+
107
+ <!-- Then password-portraits UMD -->
108
+ <script src="https://cdn.jsdelivr.net/npm/password-portraits/dist/lib/index.umd.js"></script>
109
+
110
+ <div id="pp-root"></div>
111
+ <script>
112
+ const { PasswordField, SecurityDashboard } = PasswordPortraits;
113
+ const { createElement } = React;
114
+ const root = ReactDOM.createRoot(document.getElementById('pp-root'));
115
+ root.render(
116
+ createElement('div', null,
117
+ createElement(PasswordField),
118
+ createElement(SecurityDashboard)
119
+ )
120
+ );
121
+ </script>
122
+ </body>
123
+ </html>
124
+ ```
125
+
126
+ ---
127
+
128
+ ## Engine API (framework-agnostic)
129
+
130
+ ```ts
131
+ import {
132
+ extractFeatures,
133
+ calculateEntropy,
134
+ calculateScore,
135
+ generateArtData,
136
+ simulateAttacks,
137
+ } from 'password-portraits';
138
+
139
+ const pw = 'MyStr0ng!Pass#99';
140
+ const features = extractFeatures(pw);
141
+ const entropy = calculateEntropy(pw, features.hasLower, features.hasUpper, features.hasDigits, features.hasSymbols);
142
+ const score = calculateScore(features.length, features.charTypeCount, entropy.bits, 0, false, 0);
143
+ const art = generateArtData({ password: pw, score: score.score, grade: score.grade, ...features });
144
+ const attacks = simulateAttacks(score.score, features, [], false, false);
145
+
146
+ console.log(`Grade: ${score.grade} | Score: ${score.score}/100`);
147
+ console.log(`Crack time: ${entropy.crackLabel}`);
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Component Reference
153
+
154
+ | Component | Description | Key Props |
155
+ |-----------|-------------|-----------|
156
+ | `<PasswordField />` | Password input with show/hide toggle | `len`, `placeholder`, `onPasswordChange` |
157
+ | `<UsernameField />` | Username input (used for name-in-password detection) | `placeholder`, `onUsernameChange` |
158
+ | `<SecurityDashboard />` | Full HUD: score gauge, crack risk, entropy, crack time | — |
159
+ | `<StrengthBadges />` | XP bar + badge chips (Symbol Master, Cosmic Guard…) | `analysis`, `className` |
160
+ | `<PasswordChecklist />` | ✓/✗ requirement rows | `minLength`, `analysis` |
161
+ | `<ThreatSimulator />` | 9-attack-vector modal | `buttonLabel`, `buttonClassName` |
162
+ | `<Portrait />` | SVG generative art portrait | `artData`, `size`, `animate` |
163
+ | `<ThreeJsPortrait />` | 3D plant/warrior animation | `grade`, `score`, `size`, `animate` |
164
+ | `<GradeDisplay />` | Grade badge + crack time label | `grade`, `score`, `crackLabel` |
165
+ | `<SubmitButton />` | Enforces minimum score before allowing submit | `minScore`, `successLabel`, `onClick` |
166
+ | `<PasswordGenerator />` | Suggest & apply a strong random password | `onApply` |
167
+ | `<SecurityBadge />` | Compact or premium grade badge | `variant` (`compact` \| `premium`) |
168
+
169
+ ---
170
+
171
+ ## State Store (Zustand)
172
+
173
+ All components share a built-in Zustand store. Access it anywhere:
174
+
175
+ ```ts
176
+ import { useAppStore } from 'password-portraits';
177
+
178
+ function MyComponent() {
179
+ const { analysis, password, setPassword } = useAppStore();
180
+ return <div>Score: {analysis?.score.score ?? 0}</div>;
181
+ }
182
+ ```
183
+
184
+ ---
185
+
186
+ ## Security Principles
187
+
188
+ - ✅ **Zero-knowledge** — password never sent to any server
189
+ - ✅ **Bloom filter** — 500 most-breached passwords checked locally
190
+ - ✅ **Breach API** — SHA-1 k-anonymity (only 5 chars of hash sent to HIBP)
191
+ - ✅ **Name detection** — cross-references username locally to catch personal-info passwords
192
+ - ✅ **9 AI attack vectors** — brute force, dictionary, passgan, shoulder surfing, and more
193
+
194
+ ---
195
+
196
+ ## License
197
+
198
+ MIT © Password Portraits Team
@@ -0,0 +1,328 @@
1
+ import { CSSProperties } from 'react';
2
+ import { JSX as JSX_2 } from 'react/jsx-runtime';
3
+ import { PersistOptions } from 'zustand/middleware';
4
+ import { StoreApi } from 'zustand';
5
+ import { UseBoundStore } from 'zustand';
6
+
7
+ export declare interface Achievement {
8
+ id: string;
9
+ title: string;
10
+ description: string;
11
+ unlockedAt: number;
12
+ icon: string;
13
+ }
14
+
15
+ export declare function AchievementToast(): JSX_2.Element | null;
16
+
17
+ declare interface AppState {
18
+ password: string;
19
+ username: string;
20
+ analysis: FullAnalysis | null;
21
+ isAnalysing: boolean;
22
+ breachStatus: 'idle' | 'checking' | 'done';
23
+ vault: VaultEntry[];
24
+ achievements: Achievement[];
25
+ pendingAchievement: Achievement | null;
26
+ storedPortraitHash: Record<string, number>;
27
+ phishingAlert: boolean;
28
+ activeTab: 'check' | 'vault' | 'how' | 'embed';
29
+ setPassword: (pw: string) => void;
30
+ setUsername: (u: string) => void;
31
+ runAnalysis: (pw: string, username: string) => void;
32
+ saveToVault: (label: string) => void;
33
+ removeFromVault: (id: string) => void;
34
+ dismissAchievement: () => void;
35
+ setActiveTab: (tab: AppState['activeTab']) => void;
36
+ dismissPhishing: () => void;
37
+ }
38
+
39
+ export declare interface ArtData {
40
+ seed: number;
41
+ palette: [string, string, string];
42
+ ringLayers: number;
43
+ petalCount: number;
44
+ petalWidth: number;
45
+ sparkParticles: number;
46
+ fractalArms: number;
47
+ coreRadius: number;
48
+ hasCracks: boolean;
49
+ hasScar: boolean;
50
+ isDimmed: boolean;
51
+ score: number;
52
+ grade: Grade;
53
+ rngValues: number[];
54
+ }
55
+
56
+ export declare type ArtEffect = "crack" | "scar" | "dim" | "none";
57
+
58
+ declare interface ArtParams {
59
+ password: string;
60
+ score: number;
61
+ grade: Grade;
62
+ entropyBits: number;
63
+ length: number;
64
+ charTypes: number;
65
+ hasSymbols: boolean;
66
+ isCommon: boolean;
67
+ isPersonalName: boolean;
68
+ activeEffects: ArtEffect[];
69
+ }
70
+
71
+ export declare interface AttackResult {
72
+ attackerConfidence: number;
73
+ defenderScore: number;
74
+ log: string[];
75
+ retreated: boolean;
76
+ threats: ThreatVector[];
77
+ }
78
+
79
+ export declare function BattleEngine({ attack }: Props_3): JSX_2.Element | null;
80
+
81
+ export declare interface BreachResult {
82
+ breached: boolean;
83
+ count: number;
84
+ checked: boolean;
85
+ }
86
+
87
+ export declare function calculateEntropy(password: string, hasLower: boolean, hasUpper: boolean, hasDigits: boolean, hasSymbols: boolean): EntropyResult;
88
+
89
+ export declare function calculateScore(length: number, charTypes: number, entropyBits: number, patternPenalty: number, isCommon: boolean, namePenalty: number): ScoreResult;
90
+
91
+ export declare interface EntropyResult {
92
+ bits: number;
93
+ charsetSize: number;
94
+ crackSeconds: number;
95
+ crackLabel: string;
96
+ }
97
+
98
+ export declare function extractFeatures(password: string): PasswordFeatures;
99
+
100
+ export declare function FeedbackPanel({ patterns, nameResult, breach, grade, hasUpper, hasDigits, hasSymbols, length, charTypes }: Props_2): JSX_2.Element;
101
+
102
+ export declare interface FullAnalysis {
103
+ features: PasswordFeatures;
104
+ patterns: PatternResult[];
105
+ entropy: EntropyResult;
106
+ nameResult: NameResult;
107
+ score: ScoreResult;
108
+ art: ArtData;
109
+ attack: AttackResult;
110
+ breach: BreachResult | null;
111
+ isCommon: boolean;
112
+ }
113
+
114
+ export declare function generateArtData(p: ArtParams): ArtData;
115
+
116
+ export declare type Grade = "seed" | "sprout" | "bloom" | "fractal" | "cosmic";
117
+
118
+ export declare function GradeDisplay({ grade, score, crackLabel }: Props): JSX_2.Element;
119
+
120
+ export declare function initBloom(): void;
121
+
122
+ export declare function isLikelyCommon(password: string): boolean;
123
+
124
+ export declare interface NameResult {
125
+ isPersonalName: boolean;
126
+ penalty: number;
127
+ feedback: string;
128
+ matchedSegment?: string;
129
+ }
130
+
131
+ export declare function Navbar(): JSX_2.Element;
132
+
133
+ export declare function PasswordChecklist({ analysis, minLength, className, showNoWeakPatterns, }: PasswordChecklistProps): JSX_2.Element;
134
+
135
+ declare interface PasswordChecklistProps {
136
+ analysis: FullAnalysis | null;
137
+ minLength?: number;
138
+ className?: string;
139
+ showNoWeakPatterns?: boolean;
140
+ }
141
+
142
+ export declare interface PasswordFeatures {
143
+ length: number;
144
+ hasLower: boolean;
145
+ hasUpper: boolean;
146
+ hasDigits: boolean;
147
+ hasSymbols: boolean;
148
+ charTypeCount: number;
149
+ uniqueChars: number;
150
+ normalised: string;
151
+ }
152
+
153
+ export declare function PasswordField({ len, className, style, placeholder, onPasswordChange, showToggle }: PasswordFieldProps): JSX_2.Element;
154
+
155
+ declare interface PasswordFieldProps {
156
+ len?: number;
157
+ className?: string;
158
+ style?: CSSProperties;
159
+ placeholder?: string;
160
+ onPasswordChange?: (password: string, analysis: any) => void;
161
+ showToggle?: boolean;
162
+ }
163
+
164
+ export declare function PasswordGenerator({ className, onApply }: PasswordGeneratorProps): JSX_2.Element;
165
+
166
+ declare interface PasswordGeneratorProps {
167
+ className?: string;
168
+ onApply?: (password: string) => void;
169
+ }
170
+
171
+ export declare function PasswordInput(): JSX_2.Element;
172
+
173
+ export declare interface PatternResult {
174
+ detected: boolean;
175
+ penalty: number;
176
+ label: string;
177
+ effect: ArtEffect;
178
+ }
179
+
180
+ export declare function Portrait({ artData, size, animate }: PortraitProps): JSX_2.Element;
181
+
182
+ declare interface PortraitProps {
183
+ artData: ArtData | null;
184
+ size?: number;
185
+ animate?: boolean;
186
+ }
187
+
188
+ declare interface Props {
189
+ grade: Grade;
190
+ score: number;
191
+ crackLabel: string;
192
+ }
193
+
194
+ declare interface Props_2 {
195
+ patterns: PatternResult[];
196
+ nameResult: NameResult;
197
+ breach: BreachResult | null;
198
+ grade: Grade;
199
+ hasUpper: boolean;
200
+ hasDigits: boolean;
201
+ hasSymbols: boolean;
202
+ length: number;
203
+ charTypes: number;
204
+ }
205
+
206
+ declare interface Props_3 {
207
+ attack: AttackResult;
208
+ }
209
+
210
+ declare interface Props_4 {
211
+ score: ScoreResult;
212
+ }
213
+
214
+ export declare function ScoreBreakdown({ score }: Props_4): JSX_2.Element;
215
+
216
+ export declare interface ScoreResult {
217
+ raw: number;
218
+ score: number;
219
+ grade: Grade;
220
+ lengthBonus: number;
221
+ varietyBonus: number;
222
+ entropyBonus: number;
223
+ patternPenalty: number;
224
+ bloomPenalty: number;
225
+ namePenalty: number;
226
+ }
227
+
228
+ export declare function SecurityBadge({ className, variant }: SecurityBadgeProps): JSX_2.Element | null;
229
+
230
+ declare interface SecurityBadgeProps {
231
+ className?: string;
232
+ variant?: 'compact' | 'premium';
233
+ }
234
+
235
+ export declare function simulateAttacks(score: number, features: PasswordFeatures, patterns: PatternResult[], isCommon: boolean, isPersonalName: boolean): AttackResult;
236
+
237
+ export declare function StrengthBadges({ analysis, className }: StrengthBadgesProps): JSX_2.Element;
238
+
239
+ declare interface StrengthBadgesProps {
240
+ analysis: FullAnalysis | null;
241
+ className?: string;
242
+ }
243
+
244
+ export declare function SubmitButton({ successLabel, errorLabel, minScore, className, onClick }: SubmitButtonProps): JSX_2.Element;
245
+
246
+ declare interface SubmitButtonProps {
247
+ successLabel?: string;
248
+ errorLabel?: string;
249
+ minScore?: number;
250
+ className?: string;
251
+ onClick?: () => void;
252
+ }
253
+
254
+ export declare function ThreatSimulator({ className, buttonClassName, buttonLabel }: ThreatSimulatorProps): JSX_2.Element;
255
+
256
+ declare interface ThreatSimulatorProps {
257
+ className?: string;
258
+ buttonClassName?: string;
259
+ buttonLabel?: string;
260
+ }
261
+
262
+ export declare interface ThreatVector {
263
+ id: string;
264
+ name: string;
265
+ icon: string;
266
+ risk: number;
267
+ color: 'red' | 'orange' | 'green';
268
+ description: string;
269
+ }
270
+
271
+ /**
272
+ * ThreeJsPortrait v2.0 - Realistic Procedural Tree
273
+ * Features organic branching, MeshPhysicalMaterial bark/leaves,
274
+ * and high-fidelity growth sequences (Seed -> Sprout -> Bloom -> Fractal -> Cosmic).
275
+ */
276
+ export declare function ThreeJsPortrait({ grade, score, size, animate, className, onSave }: ThreeJsPortraitProps): JSX_2.Element;
277
+
278
+ declare interface ThreeJsPortraitProps {
279
+ grade: Grade;
280
+ score: number;
281
+ size?: number;
282
+ animate?: boolean;
283
+ className?: string;
284
+ onSave?: (dataUrl: string) => void;
285
+ }
286
+
287
+ export declare const useAppStore: UseBoundStore<Omit<StoreApi<AppState>, "persist"> & {
288
+ persist: {
289
+ setOptions: (options: Partial<PersistOptions<AppState, {
290
+ vault: VaultEntry[];
291
+ achievements: Achievement[];
292
+ storedPortraitHash: Record<string, number>;
293
+ }>>) => void;
294
+ clearStorage: () => void;
295
+ rehydrate: () => Promise<void> | void;
296
+ hasHydrated: () => boolean;
297
+ onHydrate: (fn: (state: AppState) => void) => () => void;
298
+ onFinishHydration: (fn: (state: AppState) => void) => () => void;
299
+ getOptions: () => Partial<PersistOptions<AppState, {
300
+ vault: VaultEntry[];
301
+ achievements: Achievement[];
302
+ storedPortraitHash: Record<string, number>;
303
+ }>>;
304
+ };
305
+ }>;
306
+
307
+ export declare function UsernameField({ className, style, placeholder, onUsernameChange }: UsernameFieldProps): JSX_2.Element;
308
+
309
+ declare interface UsernameFieldProps {
310
+ className?: string;
311
+ style?: CSSProperties;
312
+ placeholder?: string;
313
+ onUsernameChange?: (username: string) => void;
314
+ }
315
+
316
+ export declare interface VaultEntry {
317
+ id: string;
318
+ label: string;
319
+ grade: Grade;
320
+ score: number;
321
+ artSeed: number;
322
+ savedAt: number;
323
+ artData: ArtData;
324
+ }
325
+
326
+ export declare function VaultGallery(): JSX_2.Element;
327
+
328
+ export { }