Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
f60dc81
feat(ux): cluster 5 — toasts, auto-lock, validation, activity log + GATE
pexatar May 25, 2026
e6e2c43
feat(shortcuts): FU2 — implement Ctrl+N to create a new item on list …
pexatar May 30, 2026
f7982e7
feat(identity): FU1 — non-blocking email format warning
pexatar May 30, 2026
7e25a52
feat(settings): FU8 — restore scroll position after Activity Log roun…
pexatar May 30, 2026
f0c9eb0
feat(import): FU6 — CsvImporter title fallback + header alias coverage
pexatar May 30, 2026
1232008
fix(settings): FU9 — stop dialogs/file pickers multiplying on the Set…
pexatar May 30, 2026
4c6b0a5
fix(import): FU7 — OnePuxImporter email-object crash + locale-indepen…
pexatar May 30, 2026
b599940
feat(import): FU3 — handle encrypted/ZIP/unsupported files + import U…
pexatar May 30, 2026
f3c944a
feat(identity): FU5 — add Middle name, Company and Username fields
pexatar May 30, 2026
bb5c5c6
fix(identity): FU11 — refresh identity card immediately after an in-p…
pexatar May 30, 2026
38e4400
perf(watchtower): FU12 — parallel vault audit + live progress ring
pexatar May 30, 2026
ab3045a
fix(import): FU4 — stop dropping Bitwarden identity fields on import
pexatar May 30, 2026
f1d363b
fix(i18n): LOC-01 static batch — localize page titles, Help, placehol…
pexatar Jun 1, 2026
a7c9644
fix(ui): UI-01 — stable widths for Generator & Verifier hero cards
pexatar Jun 1, 2026
dbe12fc
fix(i18n): C-a1 — localize delete-confirmation dialogs (name-based)
pexatar Jun 1, 2026
f4e9559
fix(i18n): C-a2 — localize standalone dialogs (tray, close, 2FA, OK)
pexatar Jun 1, 2026
91821f0
fix(i18n): C-b1 — localize note categories & relative dates
pexatar Jun 1, 2026
6b7431d
fix(i18n): remove stray '+' from Identities add-button label
pexatar Jun 1, 2026
eac4b62
feat(notes): C-b2 — localize remaining strings + redesign header layout
pexatar Jun 1, 2026
a658e51
feat(notes,ui): note editor Cancel button + harmonize add-button labels
pexatar Jun 1, 2026
63c1a36
fix(ui): UI-03 search width harmonization + UI-04 per-category nav in…
pexatar Jun 1, 2026
4814a14
fix(i18n): C-c1 — localize Generator crack-time labels & a11y announces
pexatar Jun 1, 2026
f251cd5
fix(generator): dark-theme colours, copy toast, crack-time bucketing
pexatar Jun 1, 2026
8f29d47
fix(i18n): C-c2 — localize Verifier (crack-time, strength, headers, s…
pexatar Jun 1, 2026
ea62c4f
fix(i18n): C-d — localize import error messages & file-picker descrip…
pexatar Jun 1, 2026
89aaa42
fix(i18n): C-f — final runtime strings + visible TOTP feedback + QUAL…
pexatar Jun 2, 2026
8cff73e
feat(ui): center the main window on screen at startup
pexatar Jun 2, 2026
cfb69d4
fix(quality): QUAL-01a — log silent catches + correct TOTP ring accen…
pexatar Jun 2, 2026
78e3d38
fix(quality): QUAL-01b — generic localized error instead of raw ex.Me…
pexatar Jun 2, 2026
7b2d169
refactor(quality): QUAL-01c — remove dead code
pexatar Jun 2, 2026
a971ab0
fix(ui): UI-05 — stable, consistent search box width on list pages
pexatar Jun 2, 2026
e57ff19
fix(i18n): LOC-02 pilot — localize ActivityLog tooltips/automation vi…
pexatar Jun 2, 2026
c4606e3
fix(ui): prevent COMException when closing with a dialog already open
pexatar Jun 2, 2026
7b670e5
feat(i18n,ux): v2.0.0 localization rollout + Gate cluster fixes
pexatar Jun 3, 2026
d745a15
fix(ui): theme-aware brushes in code-behind — readable dark-theme Ver…
pexatar Jun 3, 2026
245291b
docs: refresh app screenshots for v2.0.0 (English UI)
pexatar Jun 3, 2026
1db5806
chore(release): bump version to 2.0.0 (app/installer) and 1.0.1 (exte…
pexatar Jun 3, 2026
d8a19a5
landing: refresh app screenshots for v2.0.0 (English UI)
pexatar Jun 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,9 @@ web-ext-artifacts/

# ─── Publish output ──────────────────────────────────────────────────────────
publish/

# ─── claude-code workspace artefacts (per-developer, never commit) ───────────
.claude/

# ─── Password-manager export files (real plaintext credentials — test only) ──
pm-export/
4 changes: 2 additions & 2 deletions Installer/PassKey.iss
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
[Setup]
AppId={{A7F3C2D1-8E4B-4F9A-B6D5-3C1E7A2F0D84}
AppName=PassKey
AppVersion=1.0.17
AppVerName=PassKey 1.0.17
AppVersion=2.0.0
AppVerName=PassKey 2.0.0
AppPublisher=Giuseppe Imperato
AppPublisherURL=https://github.com/pexatar/PassKey
AppSupportURL=https://github.com/pexatar/PassKey/issues
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ PassKey stores your passwords, credit cards, identities, and secure notes in a l

| Version | Platform | Type |
|---------|----------|------|
| [v1.0.17](https://github.com/pexatar/PassKey/releases/tag/v1.0.17) | Windows x64 | Installer EXE |
| [v1.0.17](https://github.com/pexatar/PassKey/releases/tag/v1.0.17) | Windows x64 | Portable ZIP |
| [v2.0.0](https://github.com/pexatar/PassKey/releases/tag/v2.0.0) | Windows x64 | Installer EXE |
| [v2.0.0](https://github.com/pexatar/PassKey/releases/tag/v2.0.0) | Windows x64 | Portable ZIP |

> **Requirements:** Windows 10 version 1809 (build 17763) or later, x64 processor.
> No .NET runtime required — PassKey is fully self-contained.
Expand Down
Binary file modified docs/assets/img/passkey/00 - welcome page.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/img/passkey/01 - dashboard.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/img/passkey/02 - password.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/img/passkey/03 - add password.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/img/passkey/04 - card.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/img/passkey/05 - card list view.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/img/passkey/06 - edit card.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/img/passkey/07 - identità.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/img/passkey/08 - edit identità.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/img/passkey/09 - note sicure.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/img/passkey/10 - edit note sicure.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/img/passkey/11 - generatore password.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/img/passkey/12 - verifica password.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/img/passkey/13 - test verifica password.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/img/passkey/14 - audit vault.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/img/passkey/15 - guida 01.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/assets/img/passkey/16 - guida 02.png
Binary file not shown.
Binary file modified docs/assets/img/passkey/17 - impostazioni.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file removed docs/assets/img/passkey/19 - impostazioni tema.png
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Diff not rendered.
2 changes: 1 addition & 1 deletion extensions/chrome/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "PassKey",
"version": "1.0.0",
"version": "1.0.1",
"author": "Giuseppe Imperato",
"homepage_url": "https://github.com/pexatar/PassKey",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjdNrt0WikUv9qMTjwXhpg5jIYvCLS0WYu8lRlUCzcvdB/aEuHOEqaQ4ByEES+eISVoOo4Vmdr4u3Zo1+IyPwE1zGqwX1agNMsZbctr3Ur8esnHp/gMaLkrONFHDrOXhaVdUJy5BDqa5yXuTN5jsZWhk3cmqxpxlfWu70piFWN4bsPPwdKNXuDYPSBQCcdUFlUxUz3GXX8zkm1GsXQONg1vMSYE9E5GHD4ORk5oSWlRDccsTHtnWVlfaNzlBLmuiXTbmrCBRO2zfKU+8T3byMZTWGf/0ygD7+XuNbHvMAxQgFFwdAeP9RX/kXnBej2KwXxlVE65rd/kSwfa5hFLcubQIDAQAB",
Expand Down
27 changes: 7 additions & 20 deletions extensions/chrome/popup/popup.css
Original file line number Diff line number Diff line change
Expand Up @@ -358,31 +358,15 @@ body {
text-overflow: ellipsis;
}

/* Password presence indicator (visible at rest, hidden on hover) */
.pk-pw-indicator {
color: var(--pk-text-3);
display: flex;
align-items: center;
flex-shrink: 0;
transition: opacity 0.12s;
margin-right: 2px;
}
.pk-cred-item:hover .pk-pw-indicator,
.pk-cred-item:focus-within .pk-pw-indicator { opacity: 0; pointer-events: none; }
/* Password presence indicator — hidden: the always-visible copy-password action
now conveys password presence, so the separate dot would be redundant. */
.pk-pw-indicator { display: none; }

/* Action buttons — hidden at rest, revealed on hover/focus */
/* Action buttons — always visible for discoverability (Bitwarden/1Password pattern) */
.pk-cred-actions {
display: flex;
gap: 3px;
flex-shrink: 0;
opacity: 0;
pointer-events: none;
transition: opacity 0.15s;
}
.pk-cred-item:hover .pk-cred-actions,
.pk-cred-item:focus-within .pk-cred-actions {
opacity: 1;
pointer-events: auto;
}

/* Labeled action buttons (icon + text) */
Expand Down Expand Up @@ -422,7 +406,10 @@ body {
height: 28px;
padding: 0;
justify-content: center;
color: var(--pk-text-1);
background: var(--pk-fill-hover);
}
.pk-action-btn:not([data-action="fill"]):hover { background: var(--pk-fill-active); }
.pk-action-btn:not([data-action="fill"]) .pk-action-label { display: none; }

/* Legacy icon-only buttons (kept for other potential uses) */
Expand Down
9 changes: 7 additions & 2 deletions extensions/chrome/popup/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,13 @@ const SPIN_SVG = `<svg class="pk-spin" width="15" height="15" viewBox="0 0 15 15
* @param {string} svgString - Raw SVG markup string.
*/
function setSvgIcon(element, svgString) {
const doc = new DOMParser().parseFromString(svgString, 'image/svg+xml');
element.replaceChildren(doc.documentElement);
// Parse as text/html (not image/svg+xml): the HTML parser places <svg> in the
// SVG namespace automatically, so the inline icon strings render even without an
// explicit xmlns. Strict XML parsing left them in the null namespace → invisible.
// DOMParser stays CSP-safe (it never executes scripts).
const doc = new DOMParser().parseFromString(svgString, 'text/html');
const svg = doc.body.firstElementChild;
if (svg) element.replaceChildren(svg);
}

// ─── State ────────────────────────────────────────────────────────────────────
Expand Down
2 changes: 1 addition & 1 deletion extensions/firefox/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "PassKey",
"version": "1.0.0",
"version": "1.0.1",
"author": "Giuseppe Imperato",
"homepage_url": "https://github.com/pexatar/PassKey",
"description": "Local password manager integration for PassKey desktop app. Autofill credentials, credit cards and identities stored securely on your PC — no cloud, no subscription.",
Expand Down
27 changes: 7 additions & 20 deletions extensions/firefox/popup/popup.css
Original file line number Diff line number Diff line change
Expand Up @@ -358,31 +358,15 @@ body {
text-overflow: ellipsis;
}

/* Password presence indicator (visible at rest, hidden on hover) */
.pk-pw-indicator {
color: var(--pk-text-3);
display: flex;
align-items: center;
flex-shrink: 0;
transition: opacity 0.12s;
margin-right: 2px;
}
.pk-cred-item:hover .pk-pw-indicator,
.pk-cred-item:focus-within .pk-pw-indicator { opacity: 0; pointer-events: none; }
/* Password presence indicator — hidden: the always-visible copy-password action
now conveys password presence, so the separate dot would be redundant. */
.pk-pw-indicator { display: none; }

/* Action buttons — hidden at rest, revealed on hover/focus */
/* Action buttons — always visible for discoverability (Bitwarden/1Password pattern) */
.pk-cred-actions {
display: flex;
gap: 3px;
flex-shrink: 0;
opacity: 0;
pointer-events: none;
transition: opacity 0.15s;
}
.pk-cred-item:hover .pk-cred-actions,
.pk-cred-item:focus-within .pk-cred-actions {
opacity: 1;
pointer-events: auto;
}

/* Labeled action buttons (icon + text) */
Expand Down Expand Up @@ -422,7 +406,10 @@ body {
height: 28px;
padding: 0;
justify-content: center;
color: var(--pk-text-1);
background: var(--pk-fill-hover);
}
.pk-action-btn:not([data-action="fill"]):hover { background: var(--pk-fill-active); }
.pk-action-btn:not([data-action="fill"]) .pk-action-label { display: none; }

/* Legacy icon-only buttons (kept for other potential uses) */
Expand Down
9 changes: 7 additions & 2 deletions extensions/firefox/popup/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,13 @@ const SPIN_SVG = `<svg class="pk-spin" width="15" height="15" viewBox="0 0 15 15
* @param {string} svgString - SVG markup string.
*/
function setSvgIcon(element, svgString) {
const doc = new DOMParser().parseFromString(svgString, 'image/svg+xml');
element.replaceChildren(doc.documentElement);
// Parse as text/html (not image/svg+xml): the HTML parser places <svg> in the
// SVG namespace automatically, so the inline icon strings render even without an
// explicit xmlns. Strict XML parsing left them in the null namespace → invisible.
// DOMParser stays CSP-safe (it never executes scripts).
const doc = new DOMParser().parseFromString(svgString, 'text/html');
const svg = doc.body.firstElementChild;
if (svg) element.replaceChildren(svg);
}

// ─── State ────────────────────────────────────────────────────────────────────
Expand Down
Binary file added landing/assets/screenshot/passkey/04 - card.png
13 changes: 13 additions & 0 deletions src/PassKey.Core/Models/CreditCardEntry.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using PassKey.Core.Constants;
using PassKey.Core.Services;

namespace PassKey.Core.Models;

Expand Down Expand Up @@ -27,6 +28,18 @@ public sealed class CreditCardEntry : IVaultEntry
/// <summary>Gets or sets the Primary Account Number (PAN) of the card.</summary>
public string CardNumber { get; set; } = string.Empty;

/// <summary>
/// Gets the card number masked for display (e.g., "•••• •••• •••• 1234"). Returns
/// a fully-masked placeholder if the card number is empty. Used by the list view
/// so the raw PAN is never shown alongside the rest of the entry — only the last
/// digits are visible, matching the skeuomorphic card view. Mirrors the
/// <see cref="ExpiryFormatted"/> pattern of exposing a display-ready computed value
/// directly on the model.
/// </summary>
public string MaskedCardNumber => string.IsNullOrWhiteSpace(CardNumber)
? "•••• •••• •••• ••••"
: CardTypeDetector.MaskCardNumber(CardNumber, CardType);

/// <summary>Gets or sets the expiry month (1–12).</summary>
public int ExpiryMonth { get; set; }

Expand Down
9 changes: 9 additions & 0 deletions src/PassKey.Core/Models/IdentityEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public sealed class IdentityEntry : IVaultEntry
/// <summary>Gets or sets the person's first name.</summary>
public string FirstName { get; set; } = string.Empty;

/// <summary>Gets or sets the person's middle name (FU5).</summary>
public string MiddleName { get; set; } = string.Empty;

/// <summary>Gets or sets the person's last name (surname).</summary>
public string LastName { get; set; } = string.Empty;

Expand All @@ -28,6 +31,12 @@ public sealed class IdentityEntry : IVaultEntry
/// <summary>Gets or sets the primary phone number (including country code if applicable).</summary>
public string Phone { get; set; } = string.Empty;

/// <summary>Gets or sets the company / organisation name (FU5).</summary>
public string Company { get; set; } = string.Empty;

/// <summary>Gets or sets a generic username associated with this identity (FU5).</summary>
public string Username { get; set; } = string.Empty;

/// <summary>Gets or sets the street address (number and street name).</summary>
public string Street { get; set; } = string.Empty;

Expand Down
25 changes: 20 additions & 5 deletions src/PassKey.Core/Services/BitwardenImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ public Vault ParseBitwarden(string jsonContent)
var vault = new Vault();
var export = JsonSerializer.Deserialize(jsonContent, BitwardenJsonContext.Default.BitwardenExport);

// FU3: an encrypted export has no plaintext items — surface a clear message
// instead of silently importing an empty vault. Throws an error CODE; the Desktop
// layer maps it to a localized message (Core stays UI/i18n-free).
if (export?.Encrypted == true)
throw new ImportFileException("IMPORT_BW_ENCRYPTED");

if (export?.Items is null) return vault;

foreach (var item in export.Items)
Expand Down Expand Up @@ -163,24 +169,33 @@ private static IdentityEntry MapIdentity(BitwardenItem item)
Id = Guid.NewGuid(),
Label = item.Name ?? string.Empty,
FirstName = id?.FirstName ?? string.Empty,
MiddleName = id?.MiddleName ?? string.Empty,
LastName = id?.LastName ?? string.Empty,
Email = id?.Email ?? string.Empty,
Phone = id?.Phone ?? string.Empty,
Street = CombineAddress(id?.Address1, id?.Address2),
Company = id?.Company ?? string.Empty,
Username = id?.Username ?? string.Empty,
Street = CombineAddress(id?.Address1, id?.Address2, id?.Address3),
City = id?.City ?? string.Empty,
Province = id?.State ?? string.Empty,
PostalCode = id?.PostalCode ?? string.Empty,
Country = id?.Country ?? string.Empty,
// For Italian users Codice Fiscale and Tessera Sanitaria coincide in common use,
// so Bitwarden's "ssn" maps onto the existing HealthCardNumber field (FU4/FU5).
HealthCardNumber = id?.Ssn ?? string.Empty,
PassportNumber = id?.PassportNumber ?? string.Empty,
DrivingLicenseNumber = id?.LicenseNumber ?? string.Empty,
Notes = item.Notes ?? string.Empty,
CreatedAt = DateTime.UtcNow,
ModifiedAt = DateTime.UtcNow
};
}

private static string CombineAddress(string? address1, string? address2)
private static string CombineAddress(string? address1, string? address2, string? address3)
{
if (string.IsNullOrEmpty(address2)) return address1 ?? string.Empty;
if (string.IsNullOrEmpty(address1)) return address2;
return $"{address1}, {address2}";
var parts = new[] { address1, address2, address3 }
.Where(a => !string.IsNullOrWhiteSpace(a))
.Select(a => a!.Trim());
return string.Join(", ", parts);
}
}
16 changes: 16 additions & 0 deletions src/PassKey.Core/Services/BitwardenJsonContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ namespace PassKey.Core.Services;

public sealed class BitwardenExport
{
/// <summary>True for an encrypted Bitwarden export (account-restricted or
/// password-protected). Such files have no plaintext <see cref="Items"/> and cannot
/// be imported — detected so the user gets a clear message (FU3).</summary>
public bool Encrypted { get; set; }

/// <summary>True when the encrypted export is protected by a file password (as
/// opposed to the account key). Informational companion to <see cref="Encrypted"/>.</summary>
public bool PasswordProtected { get; set; }

public BitwardenItem[]? Items { get; set; }
}

Expand Down Expand Up @@ -45,11 +54,18 @@ public sealed class BitwardenCard
public sealed class BitwardenIdentity
{
public string? FirstName { get; set; }
public string? MiddleName { get; set; }
public string? LastName { get; set; }
public string? Username { get; set; }
public string? Company { get; set; }
public string? Ssn { get; set; }
public string? PassportNumber { get; set; }
public string? LicenseNumber { get; set; }
public string? Email { get; set; }
public string? Phone { get; set; }
public string? Address1 { get; set; }
public string? Address2 { get; set; }
public string? Address3 { get; set; }
public string? City { get; set; }
public string? State { get; set; }
public string? PostalCode { get; set; }
Expand Down
Loading
Loading