Skip to content

Commit 92a57bc

Browse files
committed
lib: security password
1 parent d1782f4 commit 92a57bc

File tree

1 file changed

+111
-53
lines changed

1 file changed

+111
-53
lines changed

lib/security/password.rb

Lines changed: 111 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,58 +2,116 @@
22

33
module Security
44

5-
class Password
6-
attr_reader :keychain, :attributes, :password
7-
8-
private_class_method :new
9-
10-
def initialize(keychain, attributes, password)
11-
@keychain = Keychain.new(keychain)
12-
@attributes = attributes
13-
@password = password
14-
end
15-
16-
class << self
17-
private
18-
19-
def password_from_output(output)
20-
return nil if output.match?(/^security: /)
21-
22-
keychain = nil
23-
attributes = {}
24-
password = nil
25-
output.split(/\n/).each do |line|
26-
case line
27-
when /^keychain: "(.+)"/
28-
keychain = Regexp.last_match(1)
29-
when /"(\w{4})".+="(.+)"/
30-
attributes[Regexp.last_match(1)] = Regexp.last_match(2)
31-
when /"(\w{4})"<blob>=0x([[:xdigit:]]+)/
32-
attributes[Regexp.last_match(1)] = decode_hex_blob(Regexp.last_match(2))
33-
when /^password: "(.+)"/
34-
password = Regexp.last_match(1)
35-
when /^password: 0x([[:xdigit:]]+)/
36-
password = decode_hex_blob(Regexp.last_match(1))
37-
end
38-
end
39-
40-
new(keychain, attributes, password)
41-
end
42-
43-
def flags_for_options(options = {})
44-
flags = options.dup
45-
flags[:a] ||= flags.delete(:account)
46-
flags[:c] ||= flags.delete(:creator)
47-
flags[:C] ||= flags.delete(:type)
48-
flags[:D] ||= flags.delete(:kind)
49-
flags[:G] ||= flags.delete(:value)
50-
flags[:j] ||= flags.delete(:comment)
51-
52-
flags.delete_if { |_k, v| v.nil? }.collect { |k, v| "-#{k} #{v.shellescape}".strip }.join(' ')
53-
end
54-
55-
def decode_hex_blob(string)
56-
[string].pack('H*').force_encoding('UTF-8')
5+
class Password
6+
attr_reader :keychain, :attributes, :password
7+
8+
private_class_method :new
9+
10+
def initialize(keychain, attributes, password)
11+
@keychain = Keychain.new(keychain)
12+
@attributes = attributes
13+
@password = password
14+
end
15+
16+
class << self
17+
private
18+
19+
def password_from_output(output)
20+
return nil if output.match?(/^security: /)
21+
22+
keychain = nil
23+
attributes = {}
24+
password = nil
25+
output.split(/\n/).each do |line|
26+
case line
27+
when /^keychain: "(.+)"/
28+
keychain = Regexp.last_match(1)
29+
when /"(\w{4})".+="(.+)"/
30+
attributes[Regexp.last_match(1)] = Regexp.last_match(2)
31+
when /"(\w{4})"<blob>=0x([[:xdigit:]]+)/
32+
attributes[Regexp.last_match(1)] = decode_hex_blob(Regexp.last_match(2))
33+
when /^password: "(.+)"/
34+
password = Regexp.last_match(1)
35+
when /^password: 0x([[:xdigit:]]+)/
36+
password = decode_hex_blob(Regexp.last_match(1))
5737
end
5838
end
59-
end
39+
40+
new(keychain, attributes, password)
41+
end
42+
43+
def flags_for_options(options = {})
44+
flags = options.dup
45+
flags[:a] ||= flags.delete(:account)
46+
flags[:c] ||= flags.delete(:creator)
47+
flags[:C] ||= flags.delete(:type)
48+
flags[:D] ||= flags.delete(:kind)
49+
flags[:G] ||= flags.delete(:value)
50+
flags[:j] ||= flags.delete(:comment)
51+
52+
flags.delete_if { |_k, v| v.nil? }.collect { |k, v| "-#{k} #{v.shellescape}".strip }.join(' ')
53+
end
54+
55+
def decode_hex_blob(string)
56+
[string].pack('H*').force_encoding('UTF-8')
57+
end
58+
end
59+
end
60+
61+
class GenericPassword < Password
62+
class << self
63+
def add(service, account, password, options = {})
64+
options[:a] = account
65+
options[:s] = service
66+
options[:w] = password
67+
68+
system "security add-generic-password #{flags_for_options(options)}"
69+
end
70+
71+
def find(options)
72+
password_from_output(`security 2>&1 find-generic-password -g #{flags_for_options(options)}`)
73+
end
74+
75+
def delete(options)
76+
system "security delete-generic-password #{flags_for_options(options)}"
77+
end
78+
79+
private
80+
81+
def flags_for_options(options = {})
82+
options[:s] ||= options.delete(:service)
83+
super(options)
84+
end
85+
end
86+
end
87+
88+
class InternetPassword < Password
89+
class << self
90+
def add(server, account, password, options = {})
91+
options[:a] = account
92+
options[:s] = server
93+
options[:w] = password
94+
95+
system "security add-internet-password #{flags_for_options(options)}"
96+
end
97+
98+
def find(options)
99+
password_from_output(`security 2>&1 find-internet-password -g #{flags_for_options(options)}`)
100+
end
101+
102+
def delete(options)
103+
system "security delete-internet-password #{flags_for_options(options)}"
104+
end
105+
106+
private
107+
108+
def flags_for_options(options = {})
109+
options[:s] ||= options.delete(:server)
110+
options[:p] ||= options.delete(:path)
111+
options[:P] ||= options.delete(:port)
112+
options[:r] ||= options.delete(:protocol)
113+
super(options)
114+
end
115+
end
116+
end
117+
end

0 commit comments

Comments
 (0)