localvault 1.2.3 → 1.2.4
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 +4 -4
- data/lib/localvault/cli/team.rb +82 -47
- data/lib/localvault/version.rb +1 -1
- metadata +3 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 27e49afd2aae0e73dc4e78e00d81765f77f0c7870a643db8c3549a99b777f27c
|
|
4
|
+
data.tar.gz: 17cba7049d299d9581dceab6dd9c4a10a55214fafa7c08a51d793b05a39282e1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8b38a8ac1fc8774c0f505c65365e91db5a7ea2b7557a6bf437f43c807969be0c4521619f2eccdbc55c402c34e4f097342014c638d3691b5c5c265a2f6a1e0788
|
|
7
|
+
data.tar.gz: 5d35c1ad8fa8573dcec3f9d6a267dead9024cf72cf92faaba4700ac15238d1c72b08d4c746499d1abe23dab92fd19c17cc6c69fb0667e4e94fc75afd770953ba
|
data/lib/localvault/cli/team.rb
CHANGED
|
@@ -185,7 +185,7 @@ module LocalVault
|
|
|
185
185
|
return
|
|
186
186
|
end
|
|
187
187
|
|
|
188
|
-
|
|
188
|
+
target = handle
|
|
189
189
|
vault_name = options[:vault] || Config.default_vault
|
|
190
190
|
scope_list = options[:scope]
|
|
191
191
|
|
|
@@ -210,7 +210,6 @@ module LocalVault
|
|
|
210
210
|
return
|
|
211
211
|
end
|
|
212
212
|
|
|
213
|
-
# Only owner can add members
|
|
214
213
|
unless data[:owner] == Config.inventlist_handle
|
|
215
214
|
$stderr.puts "Error: Only the vault owner (@#{data[:owner]}) can manage team access."
|
|
216
215
|
return
|
|
@@ -218,67 +217,76 @@ module LocalVault
|
|
|
218
217
|
|
|
219
218
|
key_slots = data[:key_slots].is_a?(Hash) ? data[:key_slots] : {}
|
|
220
219
|
|
|
221
|
-
#
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
return
|
|
226
|
-
end
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
# Fetch recipient's public key
|
|
230
|
-
result = client.get_public_key(handle)
|
|
231
|
-
pub_key = result["public_key"]
|
|
232
|
-
unless pub_key && !pub_key.empty?
|
|
233
|
-
$stderr.puts "Error: @#{handle} has no public key published."
|
|
220
|
+
# Resolve recipients — single @handle, team:HANDLE, or crew:SLUG
|
|
221
|
+
recipients = resolve_add_recipients(client, target)
|
|
222
|
+
if recipients.empty?
|
|
223
|
+
$stderr.puts "Error: No recipients with public keys found for '#{target}'"
|
|
234
224
|
return
|
|
235
225
|
end
|
|
236
226
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
merged_scopes = (existing_scopes + scope_list).uniq
|
|
227
|
+
added = 0
|
|
228
|
+
recipients.each do |member_handle, pub_key|
|
|
229
|
+
next if member_handle == Config.inventlist_handle # skip self
|
|
241
230
|
|
|
242
|
-
#
|
|
243
|
-
|
|
244
|
-
|
|
231
|
+
# Skip if already has full access
|
|
232
|
+
if key_slots.key?(member_handle) && key_slots[member_handle].is_a?(Hash) && key_slots[member_handle]["scopes"].nil?
|
|
233
|
+
$stdout.puts "@#{member_handle} already has full vault access." if scope_list
|
|
234
|
+
next
|
|
235
|
+
end
|
|
245
236
|
|
|
246
|
-
|
|
247
|
-
|
|
237
|
+
if scope_list
|
|
238
|
+
existing_scopes = key_slots.dig(member_handle, "scopes") || []
|
|
239
|
+
merged_scopes = (existing_scopes + scope_list).uniq
|
|
248
240
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
rescue ArgumentError, KeySlot::DecryptionError => e
|
|
252
|
-
$stderr.puts "Error: @#{handle}'s public key is invalid: #{e.message}"
|
|
253
|
-
return
|
|
254
|
-
end
|
|
241
|
+
vault = Vault.new(name: vault_name, master_key: master_key)
|
|
242
|
+
filtered = vault.filter(merged_scopes)
|
|
255
243
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
244
|
+
member_key = RbNaCl::Random.random_bytes(32)
|
|
245
|
+
encrypted_blob = Crypto.encrypt(JSON.generate(filtered), member_key)
|
|
246
|
+
|
|
247
|
+
begin
|
|
248
|
+
enc_key = KeySlot.create(member_key, pub_key)
|
|
249
|
+
rescue ArgumentError, KeySlot::DecryptionError => e
|
|
250
|
+
$stderr.puts "Error: @#{member_handle}'s public key is invalid: #{e.message}"
|
|
251
|
+
next
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
key_slots[member_handle] = {
|
|
255
|
+
"pub" => pub_key, "enc_key" => enc_key,
|
|
256
|
+
"scopes" => merged_scopes,
|
|
257
|
+
"blob" => Base64.strict_encode64(encrypted_blob)
|
|
258
|
+
}
|
|
259
|
+
else
|
|
260
|
+
begin
|
|
261
|
+
enc_key = KeySlot.create(master_key, pub_key)
|
|
262
|
+
rescue ArgumentError, KeySlot::DecryptionError => e
|
|
263
|
+
$stderr.puts "Error: @#{member_handle}'s public key is invalid: #{e.message}"
|
|
264
|
+
next
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
key_slots[member_handle] = { "pub" => pub_key, "enc_key" => enc_key, "scopes" => nil, "blob" => nil }
|
|
269
268
|
end
|
|
269
|
+
added += 1
|
|
270
|
+
end
|
|
270
271
|
|
|
271
|
-
|
|
272
|
+
if added == 0
|
|
273
|
+
$stdout.puts "No new members added."
|
|
274
|
+
return
|
|
272
275
|
end
|
|
273
276
|
|
|
274
277
|
store = Store.new(vault_name)
|
|
275
278
|
blob = SyncBundle.pack_v3(store, owner: data[:owner], key_slots: key_slots)
|
|
276
279
|
client.push_vault(vault_name, blob)
|
|
277
280
|
|
|
278
|
-
if
|
|
279
|
-
|
|
281
|
+
if recipients.size == 1
|
|
282
|
+
h = recipients.first[0]
|
|
283
|
+
if scope_list
|
|
284
|
+
$stdout.puts "Added @#{h} to vault '#{vault_name}' (scopes: #{key_slots[h]["scopes"].join(", ")})."
|
|
285
|
+
else
|
|
286
|
+
$stdout.puts "Added @#{h} to vault '#{vault_name}'."
|
|
287
|
+
end
|
|
280
288
|
else
|
|
281
|
-
$stdout.puts "Added
|
|
289
|
+
$stdout.puts "Added #{added} member(s) to vault '#{vault_name}'."
|
|
282
290
|
end
|
|
283
291
|
rescue ApiClient::ApiError => e
|
|
284
292
|
if e.status == 404
|
|
@@ -456,6 +464,33 @@ module LocalVault
|
|
|
456
464
|
nil
|
|
457
465
|
end
|
|
458
466
|
|
|
467
|
+
# Resolve target into list of [handle, public_key] pairs.
|
|
468
|
+
# Supports @handle, team:HANDLE, and crew:SLUG.
|
|
469
|
+
def resolve_add_recipients(client, target)
|
|
470
|
+
if target.start_with?("team:")
|
|
471
|
+
team_handle = target.delete_prefix("team:")
|
|
472
|
+
result = client.team_public_keys(team_handle)
|
|
473
|
+
(result["members"] || [])
|
|
474
|
+
.select { |m| m["handle"] && m["public_key"] && !m["public_key"].empty? }
|
|
475
|
+
.map { |m| [m["handle"], m["public_key"]] }
|
|
476
|
+
elsif target.start_with?("crew:")
|
|
477
|
+
slug = target.delete_prefix("crew:")
|
|
478
|
+
result = client.crew_public_keys(slug)
|
|
479
|
+
(result["members"] || [])
|
|
480
|
+
.select { |m| m["handle"] && m["public_key"] && !m["public_key"].empty? }
|
|
481
|
+
.map { |m| [m["handle"], m["public_key"]] }
|
|
482
|
+
else
|
|
483
|
+
handle = target.delete_prefix("@")
|
|
484
|
+
result = client.get_public_key(handle)
|
|
485
|
+
pub_key = result["public_key"]
|
|
486
|
+
return [] unless pub_key && !pub_key.empty?
|
|
487
|
+
[[handle, pub_key]]
|
|
488
|
+
end
|
|
489
|
+
rescue ApiClient::ApiError => e
|
|
490
|
+
$stderr.puts "Warning: #{e.message}"
|
|
491
|
+
[]
|
|
492
|
+
end
|
|
493
|
+
|
|
459
494
|
# Remove a member's key slot, optionally rotating the vault master key.
|
|
460
495
|
# Supports partial scope removal via remove_scopes.
|
|
461
496
|
def remove_key_slot(handle, vault_name, key_slots, client, rotate: false, remove_scopes: nil, owner: nil)
|
data/lib/localvault/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: localvault
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.2.
|
|
4
|
+
version: 1.2.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nauman Tariq
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: thor
|
|
@@ -131,7 +130,6 @@ metadata:
|
|
|
131
130
|
homepage_uri: https://inventlist.com/tools/localvault
|
|
132
131
|
source_code_uri: https://github.com/inventlist/localvault
|
|
133
132
|
funding_uri: https://inventlist.com
|
|
134
|
-
post_install_message:
|
|
135
133
|
rdoc_options: []
|
|
136
134
|
require_paths:
|
|
137
135
|
- lib
|
|
@@ -146,8 +144,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
146
144
|
- !ruby/object:Gem::Version
|
|
147
145
|
version: '0'
|
|
148
146
|
requirements: []
|
|
149
|
-
rubygems_version: 3.
|
|
150
|
-
signing_key:
|
|
147
|
+
rubygems_version: 3.6.9
|
|
151
148
|
specification_version: 4
|
|
152
149
|
summary: Zero-infrastructure secrets manager
|
|
153
150
|
test_files: []
|