localvault 1.3.1 → 1.3.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b105245bc108c66fb889a043714a464b0d6c17c31b3546842c1b2e887c83898
4
- data.tar.gz: c2d881d51515e62c29879bbc6dbee27c14bb7e19bb003c399ea5edd801931add
3
+ metadata.gz: ca1ee7041877b10f5964e4fc74e7edf9365f4a7e34d283c624c15bd45ab32c98
4
+ data.tar.gz: 59a54ac2d1591cbc6d5910f9222c3c89039edc4d89e45f50dc3fd09aa7720a29
5
5
  SHA512:
6
- metadata.gz: da9d072b2bfd8633f687838590636a9982056d086bf8e95e0d085c8974e24e7b6edb8fca2ddca79612bfa3eabbd9fa3edeaadc5f86f96d9b31364cb36410f1bb
7
- data.tar.gz: 66cc50037f18fd47f84d4e6f387904d066eddb0914ba438894c16c5974dd937fa67a729be59bee6df2bd002876c71c17e0a3a8bc7c96d09dfb05dab2f59fbf1f
6
+ metadata.gz: db6ebd7b3e0371faa96ea772f28f8fb6447e03fe7184a596bccccdc8251d32ab9ee7a777ae1d772d985f9ed68f991fb6c2eaba988aded97fc710f2994f6aab7f
7
+ data.tar.gz: 93286e65a351b4995a438870782c147ae86c227bbe2f307080b76c39eeaa96dfa852f133821dfdc28466329529a2e540d1a0c8738ef26f421b22e1e156361797
@@ -32,7 +32,7 @@ module LocalVault
32
32
  # Publish your X25519 public key to InventList.
33
33
  #
34
34
  # Requires a keypair (run +localvault keys generate+ first) and an active
35
- # connection (run +localvault connect+ first). Once published, other users
35
+ # login session (run +localvault login+ first). Once published, other users
36
36
  # can share vaults with you.
37
37
  def publish
38
38
  unless Identity.exists?
@@ -41,7 +41,7 @@ module LocalVault
41
41
  end
42
42
 
43
43
  unless Config.token
44
- $stderr.puts "Error: Not connected. Run: localvault connect --token TOKEN --handle HANDLE"
44
+ $stderr.puts "Error: Not logged in. Run: localvault login"
45
45
  return
46
46
  end
47
47
 
@@ -31,11 +31,8 @@ module LocalVault
31
31
  vault_name ||= options[:vault] || Config.default_vault
32
32
  handle = Config.inventlist_handle
33
33
 
34
- master_key = SessionCache.get(vault_name)
35
- unless master_key
36
- $stderr.puts "Error: Vault '#{vault_name}' is not unlocked. Run: localvault unlock -v #{vault_name}"
37
- return
38
- end
34
+ master_key = ensure_master_key(vault_name)
35
+ return unless master_key
39
36
 
40
37
  client = ApiClient.new(token: Config.token)
41
38
  begin
@@ -171,11 +168,8 @@ module LocalVault
171
168
  key_slots = team_data[:key_slots]
172
169
  vault_owner = team_data[:owner]
173
170
 
174
- master_key = SessionCache.get(vault_name)
175
- unless master_key
176
- $stderr.puts "Error: Vault '#{vault_name}' is not unlocked."
177
- return
178
- end
171
+ master_key = ensure_master_key(vault_name)
172
+ return unless master_key
179
173
 
180
174
  passphrase = prompt_passphrase("New passphrase for vault '#{vault_name}': ")
181
175
  if passphrase.nil? || passphrase.empty?
@@ -10,6 +10,37 @@ module LocalVault
10
10
  module TeamHelpers
11
11
  private
12
12
 
13
+ # Return the master key for +vault_name+, prompting for the passphrase
14
+ # if the vault isn't already cached in the session. Returns +nil+ and
15
+ # emits an error if the vault doesn't exist or the passphrase is wrong.
16
+ #
17
+ # This is what lets team init / rotate / add / remove "just work"
18
+ # without a separate `localvault unlock` step. Delegates to
19
+ # +Vault.open+ (the canonical passphrase-to-vault constructor) and
20
+ # verifies the passphrase by calling +vault.all+ — +Vault.open+ alone
21
+ # doesn't verify, it just derives the key.
22
+ def ensure_master_key(vault_name)
23
+ if (cached = SessionCache.get(vault_name))
24
+ return cached
25
+ end
26
+
27
+ unless Store.new(vault_name).exists?
28
+ $stderr.puts "Error: Vault '#{vault_name}' does not exist. Run: localvault init #{vault_name}"
29
+ return nil
30
+ end
31
+
32
+ passphrase = prompt_passphrase("Passphrase for '#{vault_name}': ")
33
+ return nil if passphrase.nil? || passphrase.empty?
34
+
35
+ vault = Vault.open(name: vault_name, passphrase: passphrase)
36
+ vault.all # raises Crypto::DecryptionError on wrong passphrase
37
+ SessionCache.set(vault_name, vault.master_key)
38
+ vault.master_key
39
+ rescue Crypto::DecryptionError
40
+ $stderr.puts "Error: Wrong passphrase for vault '#{vault_name}'."
41
+ nil
42
+ end
43
+
13
44
  def load_key_slots(client, vault_name)
14
45
  data = load_team_data(client, vault_name)
15
46
  data ? data[:key_slots] : nil
@@ -107,11 +138,8 @@ module LocalVault
107
138
  key_slots.delete(handle)
108
139
 
109
140
  if rotate
110
- master_key = SessionCache.get(vault_name)
111
- unless master_key
112
- $stderr.puts "Error: Vault '#{vault_name}' is not unlocked. Run: localvault show -v #{vault_name}"
113
- return
114
- end
141
+ master_key = ensure_master_key(vault_name)
142
+ return unless master_key
115
143
 
116
144
  # Prompt for new passphrase
117
145
  passphrase = prompt_passphrase("New passphrase for vault '#{vault_name}': ")
@@ -59,6 +59,12 @@ module LocalVault
59
59
  shell.say " localvault install-mcp Configure MCP server in your AI tool"
60
60
  shell.say " localvault mcp Start MCP server (stdio)"
61
61
  shell.say ""
62
+ shell.say "LEGACY SHARING (pre-v1.2 direct share, still works as fallback)"
63
+ shell.say " localvault keygen Generate X25519 keypair (same as `keys generate`)"
64
+ shell.say " localvault share [VAULT] Share a vault with a user, team, or crew (one-shot copy)"
65
+ shell.say " localvault receive Fetch and import vaults shared with you"
66
+ shell.say " localvault revoke SHARE_ID Revoke a direct vault share"
67
+ shell.say ""
62
68
  shell.say "OTHER"
63
69
  shell.say " localvault login --status Show current login status"
64
70
  shell.say " localvault logout Log out"
@@ -280,9 +286,9 @@ module LocalVault
280
286
  $stdout.puts table
281
287
  end
282
288
 
283
- desc "unlock", "Output session token for passphrase-free access"
284
- def unlock
285
- vault_name = resolve_vault_name
289
+ desc "unlock [VAULT]", "Cache passphrase for session and output session token"
290
+ def unlock(vault_name = nil)
291
+ vault_name ||= resolve_vault_name
286
292
  store = Store.new(vault_name)
287
293
  unless store.exists?
288
294
  abort_with "Vault '#{vault_name}' does not exist. Run: localvault init #{vault_name}"
@@ -598,19 +604,6 @@ module LocalVault
598
604
  $stdout.puts "Logged out#{" @#{handle}" if handle}."
599
605
  end
600
606
 
601
- desc "connect", "Connect to InventList for vault sharing"
602
- method_option :token, required: true, type: :string, desc: "InventList API token"
603
- method_option :handle, required: true, type: :string, desc: "Your InventList handle"
604
- def connect
605
- Config.token = options[:token]
606
- Config.inventlist_handle = options[:handle]
607
- $stdout.puts "Connected as @#{options[:handle]}"
608
- $stdout.puts
609
- $stdout.puts "Next steps:"
610
- $stdout.puts " localvault keys generate # generate your X25519 keypair"
611
- $stdout.puts " localvault keys publish # upload your public key to InventList"
612
- end
613
-
614
607
  desc "share [VAULT]", "Share a vault with an InventList user, team, or crew"
615
608
  method_option :with, required: true, type: :string,
616
609
  desc: "Recipient: @handle, team:HANDLE, or crew:SLUG"
@@ -803,11 +796,8 @@ module LocalVault
803
796
  vault_name = options[:vault] || Config.default_vault
804
797
  scope_list = options[:scope]
805
798
 
806
- master_key = SessionCache.get(vault_name)
807
- unless master_key
808
- $stderr.puts "Error: Vault '#{vault_name}' is not unlocked. Run: localvault show -v #{vault_name}"
809
- return
810
- end
799
+ master_key = ensure_master_key(vault_name)
800
+ return unless master_key
811
801
 
812
802
  client = ApiClient.new(token: Config.token)
813
803
 
@@ -1,3 +1,3 @@
1
1
  module LocalVault
2
- VERSION = "1.3.1"
2
+ VERSION = "1.3.3"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: localvault
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nauman Tariq