htauth 2.0.0 → 2.1.0
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 +5 -5
- data/HISTORY.md +7 -0
- data/Manifest.txt +4 -0
- data/README.md +36 -22
- data/Rakefile +8 -4
- data/lib/htauth.rb +1 -0
- data/lib/htauth/algorithm.rb +32 -29
- data/lib/htauth/bcrypt.rb +35 -0
- data/lib/htauth/cli/digest.rb +1 -1
- data/lib/htauth/cli/passwd.rb +90 -30
- data/lib/htauth/console.rb +5 -1
- data/lib/htauth/crypt.rb +15 -4
- data/lib/htauth/descendant_tracker.rb +46 -0
- data/lib/htauth/md5.rb +27 -7
- data/lib/htauth/passwd_entry.rb +22 -17
- data/lib/htauth/passwd_file.rb +46 -12
- data/lib/htauth/plaintext.rb +11 -4
- data/lib/htauth/sha1.rb +8 -5
- data/lib/htauth/version.rb +1 -1
- data/spec/algorithm_spec.rb +8 -0
- data/spec/bcrypt_spec.rb +33 -0
- data/spec/cli/digest_spec.rb +22 -23
- data/spec/cli/passwd_spec.rb +160 -36
- data/spec/crypt_spec.rb +1 -5
- data/spec/digest_entry_spec.rb +19 -19
- data/spec/digest_file_spec.rb +10 -10
- data/spec/md5_spec.rb +1 -5
- data/spec/passwd_entry_spec.rb +63 -42
- data/spec/passwd_file_spec.rb +31 -13
- data/spec/plaintext_spec.rb +1 -5
- data/spec/sha1_spec.rb +1 -5
- data/tasks/default.rake +3 -3
- data/tasks/this.rb +2 -2
- metadata +32 -13
data/lib/htauth/console.rb
CHANGED
@@ -20,12 +20,16 @@ module HTAuth
|
|
20
20
|
|
21
21
|
def ask(prompt)
|
22
22
|
output.print prompt
|
23
|
-
answer =
|
23
|
+
answer = read_answer
|
24
24
|
output.puts
|
25
25
|
raise ConsoleError, "No input given" if answer.nil?
|
26
26
|
answer.strip!
|
27
27
|
raise ConsoleError, "No input given" if answer.length == 0
|
28
28
|
return answer
|
29
29
|
end
|
30
|
+
|
31
|
+
def read_answer
|
32
|
+
input.noecho(&:gets)
|
33
|
+
end
|
30
34
|
end
|
31
35
|
end
|
data/lib/htauth/crypt.rb
CHANGED
@@ -4,12 +4,23 @@ module HTAuth
|
|
4
4
|
# Internal: The basic crypt algorithm
|
5
5
|
class Crypt < Algorithm
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
ENTRY_LENGTH = 13
|
8
|
+
ENTRY_REGEX = %r{\A[^$:\s]{#{ENTRY_LENGTH}}\z}
|
9
|
+
|
10
|
+
def self.handles?(password_entry)
|
11
|
+
ENTRY_REGEX.match?(password_entry)
|
9
12
|
end
|
10
13
|
|
11
|
-
def
|
12
|
-
|
14
|
+
def self.extract_salt_from_existing_password_field(existing)
|
15
|
+
existing[0,2]
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(params = {})
|
19
|
+
if existing = (params['existing'] || params[:existing]) then
|
20
|
+
@salt = self.class.extract_salt_from_existing_password_field(existing)
|
21
|
+
else
|
22
|
+
@salt = params[:salt] || params['salt'] || gen_salt
|
23
|
+
end
|
13
24
|
end
|
14
25
|
|
15
26
|
def encode(password)
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module HTAuth
|
2
|
+
#
|
3
|
+
# Use by either
|
4
|
+
#
|
5
|
+
# class Foo
|
6
|
+
# extend DescendantTracker
|
7
|
+
# end
|
8
|
+
#
|
9
|
+
# or
|
10
|
+
#
|
11
|
+
# class Foo
|
12
|
+
# class << self
|
13
|
+
# include DescendantTracker
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# It will track all the classes that inherit from the extended class and keep
|
18
|
+
# them in a Set that is available via the 'children' method.
|
19
|
+
#
|
20
|
+
module DescendantTracker
|
21
|
+
def inherited( klass )
|
22
|
+
return unless klass.instance_of?( Class )
|
23
|
+
self.children << klass
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# The list of children that are registered
|
28
|
+
#
|
29
|
+
def children
|
30
|
+
unless defined? @children
|
31
|
+
@children = Array.new
|
32
|
+
end
|
33
|
+
return @children
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# find the child that returns truthy for then given method and
|
38
|
+
# parameters
|
39
|
+
#
|
40
|
+
def find_child( method, *args )
|
41
|
+
children.find do |child|
|
42
|
+
child.send( method, *args )
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/htauth/md5.rb
CHANGED
@@ -6,21 +6,41 @@ module HTAuth
|
|
6
6
|
# as used in the apache htpasswd -m option
|
7
7
|
class Md5 < Algorithm
|
8
8
|
|
9
|
-
DIGEST_LENGTH
|
9
|
+
DIGEST_LENGTH = 16
|
10
|
+
PAD_LENGTH = 6
|
11
|
+
PREFIX = "$apr1$".freeze
|
12
|
+
SALT_CHARS_STR = SALT_CHARS.join('')
|
13
|
+
ENTRY_REGEX = %r[
|
14
|
+
\A
|
15
|
+
#{Regexp.escape(PREFIX)}
|
16
|
+
[#{SALT_CHARS_STR}]{#{SALT_LENGTH}}
|
17
|
+
#{Regexp.escape("$")}
|
18
|
+
[#{SALT_CHARS_STR}]{#{DIGEST_LENGTH + PAD_LENGTH}}
|
19
|
+
\z
|
20
|
+
]x
|
21
|
+
|
22
|
+
def self.handles?(password_entry)
|
23
|
+
ENTRY_REGEX.match?(password_entry)
|
24
|
+
end
|
10
25
|
|
11
|
-
def
|
12
|
-
|
26
|
+
def self.extract_salt_from_existing_password_field(existing)
|
27
|
+
p = existing.split("$")
|
28
|
+
return p[2]
|
13
29
|
end
|
14
30
|
|
15
|
-
def
|
16
|
-
|
31
|
+
def initialize(params = {})
|
32
|
+
if existing = (params['existing'] || params[:existing]) then
|
33
|
+
@salt = self.class.extract_salt_from_existing_password_field(existing)
|
34
|
+
else
|
35
|
+
@salt = params[:salt] || params['salt'] || gen_salt
|
36
|
+
end
|
17
37
|
end
|
18
38
|
|
19
39
|
# this algorigthm pulled straight from apr_md5_encode() and converted to ruby syntax
|
20
40
|
def encode(password)
|
21
41
|
primary = ::Digest::MD5.new
|
22
42
|
primary << password
|
23
|
-
primary <<
|
43
|
+
primary << PREFIX
|
24
44
|
primary << @salt
|
25
45
|
|
26
46
|
md5_t = ::Digest::MD5.digest("#{password}#{@salt}#{password}")
|
@@ -46,7 +66,7 @@ module HTAuth
|
|
46
66
|
|
47
67
|
pd = primary.digest
|
48
68
|
|
49
|
-
encoded_password = "#{
|
69
|
+
encoded_password = "#{PREFIX}#{@salt}$"
|
50
70
|
|
51
71
|
# apr_md5_encode has this comment about a 60Mhz Pentium above this loop.
|
52
72
|
1000.times do |x|
|
data/lib/htauth/passwd_entry.rb
CHANGED
@@ -12,6 +12,8 @@ module HTAuth
|
|
12
12
|
attr_accessor :digest
|
13
13
|
# Internal: the algorithm used to create the digest of this entry
|
14
14
|
attr_reader :algorithm
|
15
|
+
# Internal: the algorithm arguments used to create the digest of this entry
|
16
|
+
attr_reader :algorithm_args
|
15
17
|
|
16
18
|
class << self
|
17
19
|
# Internal: Create an instance of this class from a line of text
|
@@ -23,7 +25,7 @@ module HTAuth
|
|
23
25
|
parts = is_entry!(line)
|
24
26
|
d = PasswdEntry.new(parts[0])
|
25
27
|
d.digest = parts[1]
|
26
|
-
d.algorithm = Algorithm.
|
28
|
+
d.algorithm = Algorithm.algorithm_from_field(parts[1])
|
27
29
|
return d
|
28
30
|
end
|
29
31
|
|
@@ -67,23 +69,31 @@ module HTAuth
|
|
67
69
|
|
68
70
|
# Internal: set the algorithm for the entry
|
69
71
|
def algorithm=(alg)
|
70
|
-
if alg
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
72
|
+
return @algorithm if Algorithm::EXISTING == alg
|
73
|
+
case alg
|
74
|
+
when String
|
75
|
+
@algorithm = Algorithm.algorithm_from_name(alg)
|
76
|
+
when ::HTAuth::Algorithm
|
77
|
+
@algorithm = alg
|
76
78
|
else
|
77
|
-
|
79
|
+
raise InvalidAlgorithmError, "Unable to assign #{alg} to algorithm"
|
78
80
|
end
|
79
81
|
return @algorithm
|
80
82
|
end
|
81
83
|
|
84
|
+
# Internal: set fields on the algorithm
|
85
|
+
def algorithm_args=(args)
|
86
|
+
args.each do |key, value|
|
87
|
+
method = "#{key}="
|
88
|
+
@algorithm.send(method, value) if @algorithm.respond_to?(method)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
82
92
|
# Internal: Update the password of the entry with its new value
|
83
93
|
#
|
84
94
|
# If we have an array of algorithms, then we set it to CRYPT
|
85
95
|
def password=(new_password)
|
86
|
-
if algorithm.kind_of?(
|
96
|
+
if algorithm.kind_of?(HTAuth::Plaintext) then
|
87
97
|
@algorithm = Algorithm.algorithm_from_name(Algorithm::CRYPT)
|
88
98
|
end
|
89
99
|
@digest = calc_digest(new_password)
|
@@ -102,14 +112,9 @@ module HTAuth
|
|
102
112
|
# circuiting
|
103
113
|
def authenticated?(check_password)
|
104
114
|
authed = false
|
105
|
-
if algorithm.kind_of?(
|
106
|
-
|
107
|
-
|
108
|
-
if Algorithm.secure_compare(encoded, digest) then
|
109
|
-
@algorithm = alg
|
110
|
-
authed = true
|
111
|
-
end
|
112
|
-
end
|
115
|
+
if algorithm.kind_of?(Bcrypt) then
|
116
|
+
bc = ::BCrypt::Password.new(digest)
|
117
|
+
authed = bc.is_password?(check_password)
|
113
118
|
else
|
114
119
|
encoded = algorithm.encode(check_password)
|
115
120
|
authed = Algorithm.secure_compare(encoded, digest)
|
data/lib/htauth/passwd_file.rb
CHANGED
@@ -66,9 +66,13 @@ module HTAuth
|
|
66
66
|
# The file is not written to disk until #save! is called.
|
67
67
|
#
|
68
68
|
# username - the username of the entry
|
69
|
-
# password - the
|
69
|
+
# password - the password of the entry
|
70
70
|
# algorithm - the algorithm to use (default: "md5"). Valid options are:
|
71
|
-
# "md5", "sha1", "plaintext", or "crypt"
|
71
|
+
# "md5", "bcrypt", "sha1", "plaintext", or "crypt"
|
72
|
+
# algorithm_args - key-value pairs of arguments that are passed to the
|
73
|
+
# algorithm, currently this is only used to pass the cost
|
74
|
+
# to the bcrypt algorithm
|
75
|
+
#
|
72
76
|
#
|
73
77
|
# Examples
|
74
78
|
#
|
@@ -79,20 +83,23 @@ module HTAuth
|
|
79
83
|
# passwd_file.save!
|
80
84
|
#
|
81
85
|
# Returns nothing.
|
82
|
-
def add_or_update(username, password, algorithm = Algorithm::DEFAULT)
|
86
|
+
def add_or_update(username, password, algorithm = Algorithm::DEFAULT, algorithm_args = {})
|
83
87
|
if has_entry?(username) then
|
84
|
-
update(username, password, algorithm)
|
88
|
+
update(username, password, algorithm, algorithm_args)
|
85
89
|
else
|
86
|
-
add(username, password, algorithm)
|
90
|
+
add(username, password, algorithm, algorithm_args)
|
87
91
|
end
|
88
92
|
end
|
89
93
|
|
90
94
|
# Public: Add a new record to the file.
|
91
95
|
#
|
92
96
|
# username - the username of the entry
|
93
|
-
# password - the
|
97
|
+
# password - the password of the entry
|
94
98
|
# algorithm - the algorithm to use (default: "md5"). Valid options are:
|
95
|
-
# "md5", "sha1", "plaintext", or "crypt"
|
99
|
+
# "md5", "bcrypt", "sha1", "plaintext", or "crypt"
|
100
|
+
# algorithm_args - key-value pairs of arguments that are passed to the
|
101
|
+
# algorithm, currently this is only used to pass the cost
|
102
|
+
# to the bcrypt algorithm
|
96
103
|
#
|
97
104
|
# Examples
|
98
105
|
#
|
@@ -102,11 +109,14 @@ module HTAuth
|
|
102
109
|
# passwd_file.add("newuser", "password", "sha1")
|
103
110
|
# passwd_file.save!
|
104
111
|
#
|
112
|
+
# passwd_file.add("newuser", "password", "bcrypt", { cost: 12 })
|
113
|
+
# passwd_file.save!
|
114
|
+
#
|
105
115
|
# Returns nothing.
|
106
116
|
# Raises PasswdFileError if the give username already exists.
|
107
|
-
def add(username, password, algorithm = Algorithm::DEFAULT)
|
117
|
+
def add(username, password, algorithm = Algorithm::DEFAULT, algorithm_args = {})
|
108
118
|
raise PasswdFileError, "Unable to add already existing user #{username}" if has_entry?(username)
|
109
|
-
new_entry = PasswdEntry.new(username, password, algorithm)
|
119
|
+
new_entry = PasswdEntry.new(username, password, algorithm, algorithm_args)
|
110
120
|
new_index = @lines.size
|
111
121
|
@lines << new_entry.to_s
|
112
122
|
@entries[new_entry.key] = { 'entry' => new_entry, 'line_index' => new_index }
|
@@ -121,9 +131,12 @@ module HTAuth
|
|
121
131
|
# setting the `algorithm` parameter.
|
122
132
|
#
|
123
133
|
# username - the username of the entry
|
124
|
-
# password - the
|
134
|
+
# password - the password of the entry
|
125
135
|
# algorithm - the algorithm to use (default: "existing"). Valid options are:
|
126
|
-
# "existing", "md5", "sha1", "plaintext", or "crypt"
|
136
|
+
# "existing", "md5", "bcrypt", "sha1", "plaintext", or "crypt"
|
137
|
+
# algorithm_args - key-value pairs of arguments that are passed to the
|
138
|
+
# algorithm, currently this is only used to pass the cost
|
139
|
+
# to the bcrypt algorithm
|
127
140
|
#
|
128
141
|
# Examples
|
129
142
|
#
|
@@ -133,12 +146,16 @@ module HTAuth
|
|
133
146
|
# passwd_file.update("newuser", "password", "sha1")
|
134
147
|
# passwd_file.save!
|
135
148
|
#
|
149
|
+
# passwd_file.update("newuser", "password", "bcrypt", { cost: 12 })
|
150
|
+
# passwd_file.save!
|
151
|
+
#
|
136
152
|
# Returns nothing.
|
137
153
|
# Raises PasswdFileError if the give username does not exist.
|
138
|
-
def update(username, password, algorithm = Algorithm::EXISTING)
|
154
|
+
def update(username, password, algorithm = Algorithm::EXISTING, algorithm_args = {})
|
139
155
|
raise PasswdFileError, "Unable to update non-existent user #{username}" unless has_entry?(username)
|
140
156
|
ir = internal_record(username)
|
141
157
|
ir['entry'].algorithm = algorithm
|
158
|
+
ir['entry'].algorithm_args = algorithm_args.dup
|
142
159
|
ir['entry'].password = password
|
143
160
|
@lines[ir['line_index']] = ir['entry'].to_s
|
144
161
|
dirty!
|
@@ -164,6 +181,23 @@ module HTAuth
|
|
164
181
|
return ir['entry'].dup
|
165
182
|
end
|
166
183
|
|
184
|
+
# Public: authenticates the password of a given username
|
185
|
+
#
|
186
|
+
# Check the password file for the given user, and check the input password
|
187
|
+
# against the existing one.
|
188
|
+
#
|
189
|
+
# Examples
|
190
|
+
#
|
191
|
+
# authenticated = password_file.authenticated?("alice", "a secret")
|
192
|
+
#
|
193
|
+
# Returns true or false if the user exists
|
194
|
+
# Raises PasswordFileErrorif the given username does not exist
|
195
|
+
def authenticated?(username, password)
|
196
|
+
raise PasswdFileError, "Unable to authenticate a non-existent user #{username}" unless has_entry?(username)
|
197
|
+
ir = internal_record(username)
|
198
|
+
return ir['entry'].authenticated?(password)
|
199
|
+
end
|
200
|
+
|
167
201
|
# Internal: returns the class used for each entry
|
168
202
|
#
|
169
203
|
# Returns a Class
|
data/lib/htauth/plaintext.rb
CHANGED
@@ -3,12 +3,19 @@ require 'htauth/algorithm'
|
|
3
3
|
module HTAuth
|
4
4
|
# Internal: the plaintext algorithm, which does absolutly nothing
|
5
5
|
class Plaintext < Algorithm
|
6
|
-
|
7
|
-
|
6
|
+
|
7
|
+
ENTRY_REGEX = /\A[^$:]*\Z/
|
8
|
+
|
9
|
+
def self.entry_matches?(entry)
|
10
|
+
ENTRY_REGEX.match?(entry)
|
8
11
|
end
|
9
12
|
|
10
|
-
def
|
11
|
-
|
13
|
+
def self.handles?(password_entry)
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
# ignore parameters
|
18
|
+
def initialize(params = {})
|
12
19
|
end
|
13
20
|
|
14
21
|
def encode(password)
|
data/lib/htauth/sha1.rb
CHANGED
@@ -8,16 +8,19 @@ module HTAuth
|
|
8
8
|
#
|
9
9
|
class Sha1 < Algorithm
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
PREFIX = '{SHA}'.freeze
|
12
|
+
ENTRY_REGEX = %r[\A#{Regexp.escape(PREFIX)}[A-Za-z0-9+\/=]{28}\z].freeze
|
13
|
+
|
14
|
+
def self.handles?(password_entry)
|
15
|
+
ENTRY_REGEX.match?(password_entry)
|
13
16
|
end
|
14
17
|
|
15
|
-
|
16
|
-
|
18
|
+
# ignore the params
|
19
|
+
def initialize(params = {})
|
17
20
|
end
|
18
21
|
|
19
22
|
def encode(password)
|
20
|
-
"#{
|
23
|
+
"#{PREFIX}#{Base64.encode64(::Digest::SHA1.digest(password)).strip}"
|
21
24
|
end
|
22
25
|
end
|
23
26
|
end
|
data/lib/htauth/version.rb
CHANGED
data/spec/bcrypt_spec.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'htauth/bcrypt'
|
3
|
+
|
4
|
+
describe HTAuth::Bcrypt do
|
5
|
+
it "encrypts the same way that apache does by default" do
|
6
|
+
apache_hash = '$2y$05$X7XeXxp0uAO92AGG2P4/fu0mj7MrRDQnlBTkwZLd9rKiH2OUBb9/K'
|
7
|
+
reparsed = ::BCrypt::Password.new(apache_hash)
|
8
|
+
cost = reparsed.cost
|
9
|
+
|
10
|
+
_(cost).must_equal HTAuth::Bcrypt::DEFAULT_APACHE_COST
|
11
|
+
_(reparsed.is_password?("a secret")).must_equal true
|
12
|
+
|
13
|
+
bcrypt = HTAuth::Bcrypt.new(:cost => cost)
|
14
|
+
local_hash = bcrypt.encode("a secret")
|
15
|
+
|
16
|
+
_(local_hash.is_password?("a secret")).must_equal true
|
17
|
+
_(local_hash.cost).must_equal cost
|
18
|
+
end
|
19
|
+
|
20
|
+
it "encrypts the same way that apache does with different cost" do
|
21
|
+
apache_hash = '$2y$12$O3mBah33UilOkwXrS0kXuOPFBKLBCIp7V.AVvEZQcbnAM5SJLQnfq'
|
22
|
+
reparsed = ::BCrypt::Password.new(apache_hash)
|
23
|
+
cost = reparsed.cost
|
24
|
+
|
25
|
+
_(reparsed.is_password?("a secret")).must_equal true
|
26
|
+
|
27
|
+
bcrypt = HTAuth::Bcrypt.new(:cost => cost)
|
28
|
+
local_hash = bcrypt.encode("a secret")
|
29
|
+
|
30
|
+
_(local_hash.is_password?("a secret")).must_equal true
|
31
|
+
_(local_hash.cost).must_equal cost
|
32
|
+
end
|
33
|
+
end
|
data/spec/cli/digest_spec.rb
CHANGED
@@ -41,8 +41,8 @@ describe HTAuth::CLI::Digest do
|
|
41
41
|
begin
|
42
42
|
@rdigest.run([ "-h" ])
|
43
43
|
rescue SystemExit => se
|
44
|
-
se.status.must_equal 1
|
45
|
-
@stdout.string.must_match( /passwordfile realm username/m )
|
44
|
+
_(se.status).must_equal 1
|
45
|
+
_(@stdout.string).must_match( /passwordfile realm username/m )
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -50,8 +50,8 @@ describe HTAuth::CLI::Digest do
|
|
50
50
|
begin
|
51
51
|
@rdigest.run([ "--version" ])
|
52
52
|
rescue SystemExit => se
|
53
|
-
se.status.must_equal 1
|
54
|
-
@stdout.string.must_match( /version #{HTAuth::VERSION}/ )
|
53
|
+
_(se.status).must_equal 1
|
54
|
+
_(@stdout.string).must_match( /version #{HTAuth::VERSION}/ )
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -62,8 +62,8 @@ describe HTAuth::CLI::Digest do
|
|
62
62
|
@stdin.rewind
|
63
63
|
@rdigest.run([ "-c", @new_file, "htauth", "bob" ])
|
64
64
|
rescue SystemExit => se
|
65
|
-
se.status.must_equal 0
|
66
|
-
IO.read(@new_file).must_equal IO.readlines(DIGEST_ORIGINAL_TEST_FILE).first
|
65
|
+
_(se.status).must_equal 0
|
66
|
+
_(IO.read(@new_file)).must_equal IO.readlines(DIGEST_ORIGINAL_TEST_FILE).first
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
@@ -74,8 +74,8 @@ describe HTAuth::CLI::Digest do
|
|
74
74
|
@stdin.rewind
|
75
75
|
@rdigest.run([ "-c", @tf.path, "htauth", "bob"])
|
76
76
|
rescue SystemExit => se
|
77
|
-
se.status.must_equal 0
|
78
|
-
IO.read(@tf.path).must_equal IO.read(DIGEST_DELETE_TEST_FILE)
|
77
|
+
_(se.status).must_equal 0
|
78
|
+
_(IO.read(@tf.path)).must_equal IO.read(DIGEST_DELETE_TEST_FILE)
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
@@ -86,8 +86,8 @@ describe HTAuth::CLI::Digest do
|
|
86
86
|
@stdin.rewind
|
87
87
|
@rdigest.run([ @tf.path, "htauth-new", "charlie" ])
|
88
88
|
rescue SystemExit => se
|
89
|
-
se.status.must_equal 0
|
90
|
-
IO.read(@tf.path).must_equal IO.read(DIGEST_ADD_TEST_FILE)
|
89
|
+
_(se.status).must_equal 0
|
90
|
+
_(IO.read(@tf.path)).must_equal IO.read(DIGEST_ADD_TEST_FILE)
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
@@ -98,9 +98,9 @@ describe HTAuth::CLI::Digest do
|
|
98
98
|
@stdin.rewind
|
99
99
|
@rdigest.run([ @tf.path, "htauth", "alice" ])
|
100
100
|
rescue SystemExit => se
|
101
|
-
@stderr.string.must_equal ""
|
102
|
-
se.status.must_equal 0
|
103
|
-
IO.read(@tf.path).must_equal IO.read(DIGEST_UPDATE_TEST_FILE)
|
101
|
+
_(@stderr.string).must_equal ""
|
102
|
+
_(se.status).must_equal 0
|
103
|
+
_(IO.read(@tf.path)).must_equal IO.read(DIGEST_UPDATE_TEST_FILE)
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
@@ -108,9 +108,9 @@ describe HTAuth::CLI::Digest do
|
|
108
108
|
begin
|
109
109
|
@rdigest.run([ "-d", @tf.path, "htauth", "alice" ])
|
110
110
|
rescue SystemExit => se
|
111
|
-
@stderr.string.must_equal ""
|
112
|
-
se.status.must_equal 0
|
113
|
-
IO.read(@tf.path).must_equal IO.read(DIGEST_DELETE_TEST_FILE)
|
111
|
+
_(@stderr.string).must_equal ""
|
112
|
+
_(se.status).must_equal 0
|
113
|
+
_(IO.read(@tf.path)).must_equal IO.read(DIGEST_DELETE_TEST_FILE)
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
@@ -121,8 +121,8 @@ describe HTAuth::CLI::Digest do
|
|
121
121
|
@stdin.rewind
|
122
122
|
@rdigest.run([ "-c", "/etc/you-cannot-create-me", "htauth", "alice"])
|
123
123
|
rescue SystemExit => se
|
124
|
-
@stderr.string.must_match( %r{Could not open password file /etc/you-cannot-create-me}m )
|
125
|
-
se.status.must_equal 1
|
124
|
+
_(@stderr.string).must_match( %r{Could not open password file /etc/you-cannot-create-me}m )
|
125
|
+
_(se.status).must_equal 1
|
126
126
|
end
|
127
127
|
end
|
128
128
|
|
@@ -133,8 +133,8 @@ describe HTAuth::CLI::Digest do
|
|
133
133
|
@stdin.rewind
|
134
134
|
@rdigest.run([ @tf.path, "htauth", "alice"])
|
135
135
|
rescue SystemExit => se
|
136
|
-
@stderr.string.must_match( /They don't match, sorry./m )
|
137
|
-
se.status.must_equal 1
|
136
|
+
_(@stderr.string).must_match( /They don't match, sorry./m )
|
137
|
+
_(se.status).must_equal 1
|
138
138
|
end
|
139
139
|
end
|
140
140
|
|
@@ -142,9 +142,8 @@ describe HTAuth::CLI::Digest do
|
|
142
142
|
begin
|
143
143
|
@rdigest.run(["--blah"])
|
144
144
|
rescue SystemExit => se
|
145
|
-
@stderr.string.must_match( /ERROR:/m )
|
146
|
-
se.status.must_equal 1
|
145
|
+
_(@stderr.string).must_match( /ERROR:/m )
|
146
|
+
_(se.status).must_equal 1
|
147
147
|
end
|
148
148
|
end
|
149
|
-
|
150
149
|
end
|