From: Peter Palfrader Date: Thu, 18 Sep 2008 20:47:02 +0000 (+0200) Subject: Support editing stuff X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6b962009ff2dd6ed69ba39f24e5f82858a3187b0;p=pwstore Support editing stuff --- diff --git a/pws b/pws index 80e2baf..7cc1529 100755 --- a/pws +++ b/pws @@ -82,20 +82,26 @@ class GnuPG def GnuPG.init_keys() return if @@my_keys - (outtxt, stderrtxt, statustxt) = GnuPG.gpgcall('', %w{--fast-list-mode --with-colons --list-secret-keys}, true) + (outtxt, stderrtxt, statustxt) = GnuPG.gpgcall('', %w{--fast-list-mode --with-colons --with-fingerprint --list-secret-keys}, true) @@my_keys = [] + @@my_fprs = [] outtxt.split("\n").each do |line| parts = line.split(':') if (parts[0] == "ssb" or parts[0] == "sec") @@my_keys.push parts[4] + elsif (parts[0] == "fpr") + @@my_fprs.push parts[9] end end end - def GnuPG.get_my_keys() init_keys @@my_keys end + def GnuPG.get_my_fprs() + init_keys + @@my_fprs + end end def read_input(query, default_yes=true) @@ -118,8 +124,13 @@ def read_input(query, default_yes=true) end end -class Config +class GroupConfig def initialize + parse_file + expand_groups + end + + def parse_file begin f = File.open('.users') rescue Exception => e @@ -154,24 +165,32 @@ class Config @groups[group] = { "members" => members } end end + end + def is_group(name) + return (name =~ /^@/) + end + def check_exists(x, whence, fatal=true) + ok=true + if is_group(x) + ok=false unless (@groups.has_key?(x)) + else + ok=false unless @users.has_key?(x) + end + unless ok + STDERR.puts( (fatal ? "Error: " : "Warning: ") + "#{whence} contains unknown member #{x}") + exit(1) if fatal + end + return ok + end + def expand_groups @groups.each_pair do |groupname, group| group['members'].each do |member| - if (member =~ /^@/) - unless (@groups.has_key?(member)) - STDERR.puts "Group #{groupname} contains unknown member #{member}" - exit(1) - end - else - unless @users.has_key?(member) - STDERR.puts "Group #{groupname} contains unknown member #{member}" - exit(1) - end - end + check_exists(member, "Group #{groupname}") end group['members_to_do'] = group['members'].clone end - + while true had_progress = false all_expanded = true @@ -180,7 +199,7 @@ class Config still_contains_groups = false group['members_to_do'].each do |member| - if (member =~ /^@/) + if is_group(member) if @groups[member]['members_to_do'].size == 0 group['keys'].concat @groups[member]['keys'] group['members_to_do'].delete(member) @@ -204,6 +223,23 @@ class Config end end end + + def expand_targets(targets) + fprs = [] + ok = true + targets.each do |t| + unless check_exists(t, "access line", false) + ok = false + next + end + if is_group(t) + fprs.concat @groups[t]['keys'] + else + fprs.push @users[t] + end + end + return ok, fprs + end end class EncryptedFile @@ -230,11 +266,13 @@ class EncryptedFile metaline = text.split("\n").first m = /^access: (.*)/.match metaline return [] unless m - return m[1].strip.split(/\s+/) + return m[1].strip.split(/[\t ,]+/) end def initialize(filename) + @groupconfig = GroupConfig.new + @filename = filename unless FileTest.readable?(filename) @accessible = false @@ -263,6 +301,24 @@ class EncryptedFile return outtxt end + def encrypt(content, recipients) + args = recipients.collect{ |r| "--recipient=#{r}"} + args.push "--encrypt" + (outtxt, stderrtxt, statustxt, exitstatus) = GnuPG.gpgcall(content, args) + + if exitstatus != 0 + proceed = read_input("Warning: gpg returned non-zero exit status #{exitstatus} when decrypting #{@filename}. Proceed (or try again)?") + return false unless proceed + elsif outtxt.length == 0 + tryagain = read_input("Error: #{@filename} decrypted to an empty file. Edit again (or exit)?") + return false if tryagain + exit(0) + end + + return true, outtxt + end + + def write_back(content) targets = EncryptedFile.targets(content) if targets.size == 0 @@ -271,8 +327,21 @@ class EncryptedFile exit(0) end - Config.new - #expanded = GnuPG.expand_targets(targets) + ok, expanded = @groupconfig.expand_targets(targets) + if (expanded.size == 0) + tryagain = read_input("Errors in access header. Edit again (or exit)?", true) + return false if tryagain + exit(0) + elsif (not ok) + tryagain = read_input("Warnings in access header. Edit again (or continue)?", true) + return false if tryagain + end + + ok, encrypted = encrypt(content, expanded) + return false unless ok + + File.open(@filename,"w").write(encrypted) + return true end end