Skip to content

Extension submission: Bitwarden v0.2.0#263

Open
edmogeor wants to merge 1 commit into
vicinaehq:mainfrom
edmogeor:main
Open

Extension submission: Bitwarden v0.2.0#263
edmogeor wants to merge 1 commit into
vicinaehq:mainfrom
edmogeor:main

Conversation

@edmogeor
Copy link
Copy Markdown

@edmogeor edmogeor commented May 4, 2026

Release v0.1.0

Initial release.

Added

  • Search Vault command - browse items grouped by Folder, filter by name, and copy credentials (password, username, TOTP, etc.) with a keystroke
  • Create Item command - add new Login, Card, Identity, or Secure Note entries to the vault
  • Log Out command - clear stored Session and API key
  • Unlock gate with masked master password input and Session caching via LocalStorage
  • Automatic vault Sync after Unlock
  • Preference-based configuration for server region (US cloud, EU cloud, or self-hosted), API key (client ID + client secret), and password generation options
  • Item type-specific actions: copy password/username/TOTP/URL for Logins, copy number/code for Cards, copy name/email/phone for Identities, view notes for Secure Notes
  • Item Detail view with full field inspection and show/hide password toggle
  • Edit item with dynamic custom field support
  • Generate password action with configurable length and character sets
  • Delete item from vault list
  • Create new folder from the search view
  • Cached vault items and favicons for instant loading on subsequent opens

@asm0dey
Copy link
Copy Markdown

asm0dey commented May 5, 2026

Hey, I've also submitted a pr with bitwarden extension: #258

But I built it around rbw because bw is kinda stateless and requires deciphering of the vault every time, on my vault it's roughly 4 seconds every time.
Were you able to work this issue around?

@edmogeor
Copy link
Copy Markdown
Author

edmogeor commented May 5, 2026

v0.1.1 Changelog

Changed

  • Session tokens are now stored in the system keyring via libsecret-tools instead of plaintext LocalStorage, providing encrypted at-rest storage
  • Removed Lock Vault action from the vault list - Log Out achieves the same behaviour

Added

  • Generate Password command (no-view) - copies a random password to clipboard using the configured generation preferences
  • Not-installed gate for libsecret-tools with OS-specific install instructions

Fixed

  • Negative secret-tool availability check no longer caches failures, so installing the package and re-opening the command works without restarting Vicinae
  • Use secret-tool lookup instead of unsupported --version flag for the install check
  • Stripped sensitive fields from vault cache (passwords, card numbers, TOTP seeds, notes, custom fields)

@edmogeor edmogeor changed the title Extension submission: Bitwarden v0.1.0 Extension submission: Bitwarden v0.1.1 May 5, 2026
@edmogeor
Copy link
Copy Markdown
Author

edmogeor commented May 5, 2026

Hey, I've also submitted a pr with bitwarden extension: #258

But I built it around rbw because bw is kinda stateless and requires deciphering of the vault every time, on my vault it's roughly 4 seconds every time. Were you able to work this issue around?

Hey! Apologies for the duplicate effort, been chipping away at this for a couple of weeks and didn't check the other PRs before submitting. I was just hitting the CLI every launch too, and yeah, it was slow!

Two things got it fast. First, the item list is cached in LocalStorage with a 24h TTL so the list renders instantly after the first sync (updated in background so fresh). Sensitive fields are stripped before caching, no passwords on disk. When you open details I fetch the full item fresh via bw get item. Second, the session token is stored in the system keychain via libsecret, so once unlocked you skip the unlock form across Vicinae restarts as long as the session hasn't expired.

Net result: the decryption delay only hits on the first unlock after a session expires. Day to day it's snappy.

@asm0dey
Copy link
Copy Markdown

asm0dey commented May 5, 2026

@edmogeor nice! But you don't cache passwords, right? It was my fear to accidentally cache TOTP key/pass/something else protected, so I had to anyways decrypt before reading an actual password

@edmogeor
Copy link
Copy Markdown
Author

edmogeor commented May 6, 2026

@edmogeor nice! But you don't cache passwords, right? It was my fear to accidentally cache TOTP key/pass/something else protected, so I had to anyways decrypt before reading an actual password

I did work on this last night inspired by your message 😂 I'm stripping the sensitive data before saving the list but storing which fields they have, and then calling bw get item on copy / view details to avoid any sensitive data being saved to disk.

@asm0dey
Copy link
Copy Markdown

asm0dey commented May 6, 2026

I hope you'll have an "authenticator" too - to open the full list of items with top, where they will autoupdate the codes :)

@edmogeor
Copy link
Copy Markdown
Author

edmogeor commented May 6, 2026

Bitwarden v0.1.2

Added

  • Custom CA certificate path preference for self-hosted servers using a private CA — sets NODE_EXTRA_CA_CERTS in the bw process environment

Fixed

  • Login failures are now surfaced as a dedicated error screen with a Retry button, instead of showing the Unlock form
  • Logout no longer throws when the CLI is already logged out — handles the "not logged in" response gracefully

Changed

  • Startup time reduced by running CLI checks (bw status, secret-tool, bw --version) in parallel via Promise.allSettled
  • Cached vault favicons and item list load synchronously on mount for instant display; sync runs in the background
  • getErrorMessage now filters Node.js deprecation warnings from bw stderr output
  • Logout now clears the cached vault in addition to the session
  • De-duplicated gate error rendering pattern into a shared renderGate function
  • Extracted shared test mock utilities to reduce test boilerplate

@edmogeor edmogeor changed the title Extension submission: Bitwarden v0.1.1 Extension submission: Bitwarden v0.1.3 May 6, 2026
@edmogeor
Copy link
Copy Markdown
Author

edmogeor commented May 6, 2026

v0.1.3 changelog

Added

  • Themed placeholder icons for each item type — white symbol on a coloured rounded rectangle matching Vicinae's native icon style (Login=Blue, Card=Green, Identity=Orange, SecureNote=Purple), with light/dark mode support
  • iOS-style rounded favicon corners, pre-rendered into the PNG bytes at fetch time

Fixed

  • Favicons are now stored on disk (supportPath/favicons/) with a 7-day TTL, surviving extension restarts with correct timestamps
  • Concurrent favicon fetches capped at 8 to prevent Google's favicon service timing out on large vaults
  • Search bar now disabled during gate states (loading, unlock, login) to prevent crashes when the List unmounts
  • Race condition removed: favicons are no longer cleared on Sync, so stale entries drop out when the vault item is deleted rather than on every refresh
  • Login favicon fallback now uses the themed Login placeholder icon instead of a bare key string

Changed

  • Favicons cached as base64 data URIs for direct rendering instead of file paths that required a separate disk read
  • Favicon cache prunes entries for domains no longer in the vault on each Sync

@edmogeor edmogeor force-pushed the main branch 3 times, most recently from 932f1cd to fca41e9 Compare May 6, 2026 18:56
@asm0dey
Copy link
Copy Markdown

asm0dey commented May 7, 2026

Hey, following my paranoia, I decided to read the code of your app and I have several ideas:

  1. you pass cleartext password to bw, /proc/<pid>/cmdline is readable to all users on the machine, so if you're in an unlucky environment — someone can read it. setting env BW_PASSWORD is slightly safer: it is readable only by you and root
  2. you're creating items with bw create (also edit) with plaintext json. It is also potentially readable by anyone. The better pattern is:
    bw encode ← stdin: raw JSON, stdout: base64
    bw create item ← stdin: that base64 (no positional arg)
    And this stdin can come straight from node, probably something like
const enc = spawn('bw', ['encode'], { stdio: ['pipe', 'pipe', 'ignore'] });
enc.stdin.end(json);
const encoded = await collectStdout(enc);
const create = spawn('bw', ['create', 'item'], {
  stdio: ['pipe', 'ignore', 'pipe'],
  env: sessionEnv(session),
});
create.stdin.end(encoded);
await waitExit(create);

but I'm not a node expert, so it might be I don't understand something. The good thing here is no one can "just read" from an anonymous pipe

  1. apiClientId / apiClientSecret are stored in cleartext and this one is probably the most dangerous. Any malicious software that has access to your home folder will just send them where they definitely should not go and you won't even know about it to rotate them.
    I would say they should write them to libsecret as custom accounts or something.

  2. There is no auto-lockout. It might be your choice to never logout, but I would prefer to be logged out automatically every, say. 6 hours. Probably should be a setting for this.

@edmogeor
Copy link
Copy Markdown
Author

edmogeor commented May 8, 2026

Hey, following my paranoia, I decided to read the code of your app and I have several ideas:

  1. you pass cleartext password to bw, /proc/<pid>/cmdline is readable to all users on the machine, so if you're in an unlucky environment — someone can read it. setting env BW_PASSWORD is slightly safer: it is readable only by you and root
  2. you're creating items with bw create (also edit) with plaintext json. It is also potentially readable by anyone. The better pattern is:
    bw encode ← stdin: raw JSON, stdout: base64
    bw create item ← stdin: that base64 (no positional arg)
    And this stdin can come straight from node, probably something like
const enc = spawn('bw', ['encode'], { stdio: ['pipe', 'pipe', 'ignore'] });
enc.stdin.end(json);
const encoded = await collectStdout(enc);
const create = spawn('bw', ['create', 'item'], {
  stdio: ['pipe', 'ignore', 'pipe'],
  env: sessionEnv(session),
});
create.stdin.end(encoded);
await waitExit(create);

but I'm not a node expert, so it might be I don't understand something. The good thing here is no one can "just read" from an anonymous pipe

  1. apiClientId / apiClientSecret are stored in cleartext and this one is probably the most dangerous. Any malicious software that has access to your home folder will just send them where they definitely should not go and you won't even know about it to rotate them.
    I would say they should write them to libsecret as custom accounts or something.
  2. There is no auto-lockout. It might be your choice to never logout, but I would prefer to be logged out automatically every, say. 6 hours. Probably should be a setting for this.

Thanks for the feedback, I'll make sure to review and fix these oversights next week.

@asm0dey
Copy link
Copy Markdown

asm0dey commented May 8, 2026

Also, may I ask about a couple of feature requests?

  1. Could you please add an authenticator (like a separate thing with only totp-enabled accounts and a countdown)?
  2. Could you please add "sends" support?
  3. Could you please add support for saving attached files?

@edmogeor edmogeor changed the title Extension submission: Bitwarden v0.1.3 Extension submission: Bitwarden v0.2.0 May 11, 2026
@edmogeor
Copy link
Copy Markdown
Author

[0.2.0] - 2026-05-11

Added

  • Search TOTP Codes command — browse accounts with TOTP 2FA enabled, view live verification codes with 30-second countdown timers, and copy codes with a keystroke
  • TOTP countdown progress bar on the item detail view showing remaining code validity
  • File attachment support — upload files when creating or editing items; download attachments to a configurable directory (new Download Directory preference)
  • Per-field copy and show/hide actions for custom fields in the item detail view
  • Auto-Lock Timeout preference — automatically lock the vault after a configurable period of inactivity (15 min to 24 h, or Never)

Fixed

  • Detail view actions now disabled during loading, preventing a stuck-loader bug when no session is active; shows a Loading indicator with only the Back action available
  • Security hardening — master password passed via environment variable instead of command-line arguments; sensitive payloads written through stdin; API credentials stored in system keyring
  • API credentials cleared from disk after every login, while the libsecret-stored session is preserved on logout
  • FilePicker control added to the edit form for selecting file attachments
  • Custom fields no longer duplicated in the markdown body — rendered only in the metadata sidebar

Changed

  • Custom field actions now appear before Open URL in the action panel

@edmogeor
Copy link
Copy Markdown
Author

Also, may I ask about a couple of feature requests?

  1. Could you please add an authenticator (like a separate thing with only totp-enabled accounts and a countdown)?
  2. Could you please add "sends" support?
  3. Could you please add support for saving attached files?

Hey, thanks for reviewing the code, every one of these was spot-on. Here's how I've addressed them in v0.2.0:

  1. Password in cmdline
    Fixed. I now use bw unlock --passwordenv BW_PASSWORD and set the env var on the child process. The password never touches the argument vector, so /proc//cmdline shows nothing.
  2. Plaintext JSON payloads
    Fixed. Item creation/edit now pipes JSON → bw encode → bw create item, all over stdin. No plaintext hits the command line. (src/bw-executor.ts:133)
  3. API creds in cleartext
    Fixed. clientId and clientSecret are stored in GNOME Keyring via secret-tool. On first migration the extension reads them from prefs, writes them to the keyring, then scrubs them from disk (both settings.json and the SQLite store). (src/api-credential-store.ts)
  4. Auto-lock
    Added. There's now an Auto-Lock Timeout preference (Never, or 15 min to 24 h). The session store timestamps each unlock; on next command invocation, if the timeout has passed the session is dropped and you see the unlock form again. (src/session-store.ts:68)

R.E. the features you've requested, the extension now supports file attachments and a seperate command that allows searching through accounts that just have TOTP enabled (with the code and countdown visible from the list view itself for quick access).

Not ruling out sends support, it feels slightly out of scope to me and perhaps less useful to have in vicinae. Let me investigate - i didn't want to include in this update as it would require more UX consideration. Did you support it in your extension? if so how did you manage the flow in the UI?

Really appreciate the thorough review!

@asm0dey
Copy link
Copy Markdown

asm0dey commented May 11, 2026

Thank you for all the work you do!

No, I didn't support them in my extension because rbw doesn't support them. But the original raycast extension supports them!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants