htauth 2.2.0 → 3.0.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 +4 -4
- data/HISTORY.md +21 -1
- data/Manifest.txt +5 -27
- data/README.md +51 -31
- data/exe/htdigest-ruby +14 -0
- data/exe/htpasswd-ruby +14 -0
- data/htauth.gemspec +33 -0
- data/lib/htauth/algorithm.rb +42 -29
- data/lib/htauth/argon2.rb +86 -0
- data/lib/htauth/bcrypt.rb +17 -11
- data/lib/htauth/cli/digest.rb +42 -49
- data/lib/htauth/cli/passwd.rb +127 -114
- data/lib/htauth/cli.rb +5 -4
- data/lib/htauth/console.rb +9 -6
- data/lib/htauth/crypt.rb +11 -9
- data/lib/htauth/descendant_tracker.rb +11 -9
- data/lib/htauth/digest_entry.rb +22 -19
- data/lib/htauth/digest_file.rb +25 -18
- data/lib/htauth/entry.rb +3 -1
- data/lib/htauth/error.rb +6 -5
- data/lib/htauth/file.rb +35 -39
- data/lib/htauth/md5.rb +35 -34
- data/lib/htauth/passwd_entry.rb +29 -38
- data/lib/htauth/passwd_file.rb +32 -27
- data/lib/htauth/plaintext.rb +7 -5
- data/lib/htauth/sha1.rb +9 -7
- data/lib/htauth/version.rb +3 -1
- data/lib/htauth.rb +29 -28
- metadata +24 -113
- data/Rakefile +0 -27
- data/bin/htdigest-ruby +0 -12
- data/bin/htpasswd-ruby +0 -12
- data/spec/algorithm_spec.rb +0 -8
- data/spec/bcrypt_spec.rb +0 -33
- data/spec/cli/digest_spec.rb +0 -149
- data/spec/cli/passwd_spec.rb +0 -330
- data/spec/crypt_spec.rb +0 -12
- data/spec/digest_entry_spec.rb +0 -60
- data/spec/digest_file_spec.rb +0 -65
- data/spec/md5_spec.rb +0 -13
- data/spec/passwd_entry_spec.rb +0 -159
- data/spec/passwd_file_spec.rb +0 -84
- data/spec/plaintext_spec.rb +0 -11
- data/spec/sha1_spec.rb +0 -11
- data/spec/spec_helper.rb +0 -28
- data/spec/test.add.digest +0 -3
- data/spec/test.add.passwd +0 -3
- data/spec/test.delete.digest +0 -1
- data/spec/test.delete.passwd +0 -1
- data/spec/test.original.digest +0 -2
- data/spec/test.original.passwd +0 -2
- data/spec/test.update.digest +0 -2
- data/spec/test.update.passwd +0 -2
- data/tasks/default.rake +0 -242
- data/tasks/this.rb +0 -208
- /data/{LICENSE → LICENSE.txt} +0 -0
data/lib/htauth/cli/digest.rb
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
require 'htauth/error'
|
|
3
|
-
require 'htauth/digest_file'
|
|
4
|
-
require 'htauth/console'
|
|
1
|
+
# frozen_string_literal: true
|
|
5
2
|
|
|
6
|
-
require
|
|
7
|
-
|
|
3
|
+
require "htauth/cli"
|
|
4
|
+
|
|
5
|
+
require "ostruct"
|
|
6
|
+
require "optparse"
|
|
8
7
|
|
|
9
8
|
module HTAuth
|
|
10
9
|
module CLI
|
|
11
10
|
# Internal: Implemenation of the commandline htdigest-ruby
|
|
12
11
|
class Digest
|
|
13
|
-
|
|
14
12
|
MAX_PASSWD_LENGTH = 255
|
|
15
13
|
|
|
16
14
|
attr_accessor :digest_file
|
|
@@ -22,7 +20,7 @@ module HTAuth
|
|
|
22
20
|
end
|
|
23
21
|
|
|
24
22
|
def options
|
|
25
|
-
if @options.nil?
|
|
23
|
+
if @options.nil?
|
|
26
24
|
@options = ::OpenStruct.new
|
|
27
25
|
@options.show_version = false
|
|
28
26
|
@options.show_help = false
|
|
@@ -36,24 +34,22 @@ module HTAuth
|
|
|
36
34
|
end
|
|
37
35
|
|
|
38
36
|
def option_parser
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
options.show_version = v
|
|
56
|
-
end
|
|
37
|
+
@option_parser ||= OptionParser.new(nil, 14) do |op|
|
|
38
|
+
op.banner = "Usage: #{op.program_name} [options] passwordfile realm username"
|
|
39
|
+
op.on("-c", "--create", "Create a new digest password file; this overwrites an existing file.") do |_c|
|
|
40
|
+
options.file_mode = DigestFile::CREATE
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
op.on("-D", "--delete", "Delete the specified user.") do |d|
|
|
44
|
+
options.delete_entry = d
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
op.on("-h", "--help", "Display this help.") do |h|
|
|
48
|
+
options.show_help = h
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
op.on("-v", "--version", "Show version info.") do |v|
|
|
52
|
+
options.show_version = v
|
|
57
53
|
end
|
|
58
54
|
end
|
|
59
55
|
@option_parser
|
|
@@ -70,27 +66,25 @@ module HTAuth
|
|
|
70
66
|
end
|
|
71
67
|
|
|
72
68
|
def parse_options(argv)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
exit 1
|
|
85
|
-
end
|
|
69
|
+
option_parser.parse!(argv)
|
|
70
|
+
show_version if options.show_version
|
|
71
|
+
show_help if options.show_help || (argv.size < 3)
|
|
72
|
+
|
|
73
|
+
options.passwdfile = argv.shift
|
|
74
|
+
options.realm = argv.shift
|
|
75
|
+
options.username = argv.shift
|
|
76
|
+
rescue ::OptionParser::ParseError => e
|
|
77
|
+
warn "ERROR: #{option_parser.program_name} - #{e}"
|
|
78
|
+
warn "Try `#{option_parser.program_name} --help` for more information"
|
|
79
|
+
exit 1
|
|
86
80
|
end
|
|
87
81
|
|
|
88
|
-
def run(argv,
|
|
82
|
+
def run(argv, _env = ENV)
|
|
89
83
|
begin
|
|
90
84
|
parse_options(argv)
|
|
91
85
|
digest_file = DigestFile.new(options.passwdfile, options.file_mode)
|
|
92
86
|
|
|
93
|
-
if options.delete_entry
|
|
87
|
+
if options.delete_entry
|
|
94
88
|
digest_file.delete(options.username, options.realm)
|
|
95
89
|
else
|
|
96
90
|
console = Console.new
|
|
@@ -109,18 +103,17 @@ module HTAuth
|
|
|
109
103
|
end
|
|
110
104
|
|
|
111
105
|
digest_file.save!
|
|
112
|
-
|
|
113
|
-
rescue HTAuth::FileAccessError => fae
|
|
106
|
+
rescue HTAuth::FileAccessError => e
|
|
114
107
|
msg = "Could not open password file #{options.passwdfile} "
|
|
115
|
-
|
|
116
|
-
|
|
108
|
+
warn "#{msg}: #{e.message}"
|
|
109
|
+
warn e.backtrace.join("\n")
|
|
117
110
|
exit 1
|
|
118
|
-
rescue HTAuth::Error =>
|
|
119
|
-
|
|
111
|
+
rescue HTAuth::Error => e
|
|
112
|
+
warn e.message
|
|
120
113
|
exit 1
|
|
121
|
-
rescue SignalException =>
|
|
114
|
+
rescue SignalException => e
|
|
122
115
|
$stderr.puts
|
|
123
|
-
|
|
116
|
+
warn "Interrupted #{e}"
|
|
124
117
|
exit 1
|
|
125
118
|
end
|
|
126
119
|
exit 0
|
data/lib/htauth/cli/passwd.rb
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
require 'htauth/passwd_file'
|
|
3
|
-
require 'htauth/console'
|
|
1
|
+
# frozen_string_literal: true
|
|
4
2
|
|
|
5
|
-
require
|
|
6
|
-
|
|
3
|
+
require "htauth/cli"
|
|
4
|
+
|
|
5
|
+
require "ostruct"
|
|
6
|
+
require "optparse"
|
|
7
7
|
|
|
8
8
|
module HTAuth
|
|
9
9
|
module CLI
|
|
10
10
|
# Internal: Implemenation of the commandline htpasswd-ruby
|
|
11
11
|
class Passwd
|
|
12
|
-
|
|
13
12
|
MAX_PASSWD_LENGTH = 255
|
|
14
13
|
|
|
15
14
|
attr_accessor :passwd_file
|
|
@@ -21,14 +20,14 @@ module HTAuth
|
|
|
21
20
|
end
|
|
22
21
|
|
|
23
22
|
def options
|
|
24
|
-
if @options.nil?
|
|
23
|
+
if @options.nil?
|
|
25
24
|
@options = ::OpenStruct.new
|
|
26
25
|
@options.batch_mode = false
|
|
27
26
|
@options.file_mode = File::ALTER
|
|
28
27
|
@options.passwdfile = nil
|
|
29
28
|
@options.algorithm = Algorithm::EXISTING
|
|
30
29
|
@options.algorithm_args = {}
|
|
31
|
-
@options.read_stdin_once= false
|
|
30
|
+
@options.read_stdin_once = false
|
|
32
31
|
@options.send_to_stdout = false
|
|
33
32
|
@options.show_version = false
|
|
34
33
|
@options.show_help = false
|
|
@@ -40,92 +39,94 @@ module HTAuth
|
|
|
40
39
|
end
|
|
41
40
|
|
|
42
41
|
def option_parser
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
#{op.program_name} -b[cmBdpsD] [-C cost] passwordfile username password
|
|
42
|
+
@option_parser ||= OptionParser.new(nil, 16) do |op|
|
|
43
|
+
op.banner = <<~BANNER
|
|
44
|
+
Usage:
|
|
45
|
+
#{op.program_name} [-acimBdpsD] [--verify] [-C cost] passwordfile username
|
|
46
|
+
#{op.program_name} -b[acmBdpsD] [--verify] [-C cost] passwordfile username password
|
|
49
47
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
#{op.program_name} -n[imBdps] [-C cost] username
|
|
49
|
+
#{op.program_name} -nb[mBdps] [-C cost] username password
|
|
50
|
+
BANNER
|
|
53
51
|
|
|
54
|
-
|
|
52
|
+
op.separator ""
|
|
55
53
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
op.on("--argon2", "Force argon2 encryption of the password.") do |_a|
|
|
55
|
+
options.algorithm = Algorithm::ARGON2
|
|
56
|
+
end
|
|
59
57
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
op.on("-b", "--batch", "Batch mode, get the password from the command line, rather than prompt.") do |b|
|
|
59
|
+
options.batch_mode = b
|
|
60
|
+
end
|
|
63
61
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
raise ::OptionParser::ParseError, "the bcrypt cost must be an integer from 4 to 31, `#{c}` is invalid"
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
cost = c.to_i
|
|
71
|
-
if (4..31).include?(cost)
|
|
72
|
-
options.algorithm_args = { :cost => cost }
|
|
73
|
-
else
|
|
74
|
-
raise ::OptionParser::ParseError, "the bcrypt cost must be an integer from 4 to 31, `#{c}` is invalid"
|
|
75
|
-
end
|
|
76
|
-
end
|
|
62
|
+
op.on("-B", "--bcrypt", "Force bcrypt encryption of the password.") do |_b|
|
|
63
|
+
options.algorithm = Algorithm::BCRYPT
|
|
64
|
+
end
|
|
77
65
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
66
|
+
op.on("-CCOST", "--cost COST", "Set the computing time used for the bcrypt algorithm",
|
|
67
|
+
"(higher is more secure but slower, default: 5, valid: 4 to 31).") do |c|
|
|
68
|
+
unless /\A\d+\z/.match?(c)
|
|
69
|
+
raise ::OptionParser::ParseError, "the bcrypt cost must be an integer from 4 to 31, `#{c}` is invalid"
|
|
81
70
|
end
|
|
82
71
|
|
|
83
|
-
|
|
84
|
-
|
|
72
|
+
cost = c.to_i
|
|
73
|
+
unless (4..31).cover?(cost)
|
|
74
|
+
raise ::OptionParser::ParseError, "the bcrypt cost must be an integer from 4 to 31, `#{c}` is invalid"
|
|
85
75
|
end
|
|
86
76
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
end
|
|
77
|
+
options.algorithm_args = { cost: cost }
|
|
78
|
+
end
|
|
90
79
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
80
|
+
op.on("-c", "--create", "Create a new file; this overwrites an existing file.") do |_c|
|
|
81
|
+
options.file_mode = HTAuth::File::CREATE
|
|
82
|
+
options.operation << :add_or_update
|
|
83
|
+
end
|
|
94
84
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
85
|
+
op.on("-d", "--crypt", "Force CRYPT encryption of the password.") do |_c|
|
|
86
|
+
options.algorithm = Algorithm::CRYPT
|
|
87
|
+
end
|
|
98
88
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
89
|
+
op.on("-D", "--delete", "Delete the specified user.") do |_d|
|
|
90
|
+
options.operation << :delete
|
|
91
|
+
end
|
|
102
92
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
options.operation << :stdout
|
|
107
|
-
end
|
|
93
|
+
op.on("-h", "--help", "Display this help.") do |h|
|
|
94
|
+
options.show_help = h
|
|
95
|
+
end
|
|
108
96
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
97
|
+
op.on("-i", "--stdin", "Read the passwod from stdin without verivication (for script usage).") do |_i|
|
|
98
|
+
options.read_stdin_once = true
|
|
99
|
+
end
|
|
112
100
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
101
|
+
op.on("-m", "--md5", "Force MD5 encryption of the password (default).") do |_m|
|
|
102
|
+
options.algorithm = Algorithm::MD5
|
|
103
|
+
end
|
|
116
104
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
105
|
+
op.on("-n", "--stdout", "Do not update the file; Display the results on stdout instead.") do |_n|
|
|
106
|
+
options.send_to_stdout = true
|
|
107
|
+
options.passwdfile = HTAuth::File::STDOUT_FLAG
|
|
108
|
+
options.operation << :stdout
|
|
109
|
+
end
|
|
120
110
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
111
|
+
op.on("-p", "--plaintext", "Do not encrypt the password (plaintext).") do |_p|
|
|
112
|
+
options.algorithm = Algorithm::PLAINTEXT
|
|
113
|
+
end
|
|
124
114
|
|
|
125
|
-
|
|
115
|
+
op.on("-s", "--sha1", "Force SHA encryption of the password.") do |_s|
|
|
116
|
+
options.algorithm = Algorithm::SHA1
|
|
117
|
+
end
|
|
126
118
|
|
|
127
|
-
|
|
119
|
+
op.on("-v", "--version", "Show version info.") do |v|
|
|
120
|
+
options.show_version = v
|
|
128
121
|
end
|
|
122
|
+
|
|
123
|
+
op.on("--verify", "Verify password for the specified user.") do |_v|
|
|
124
|
+
options.operation << :verify
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
op.separator ""
|
|
128
|
+
|
|
129
|
+
op.separator "The SHA algorihtm does not use a salt and is less secure than the MD5 algorithm."
|
|
129
130
|
end
|
|
130
131
|
@option_parser
|
|
131
132
|
end
|
|
@@ -141,35 +142,48 @@ Usage:
|
|
|
141
142
|
end
|
|
142
143
|
|
|
143
144
|
def parse_options(argv)
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
raise ::OptionParser::ParseError,
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
raise ::OptionParser::ParseError,
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
options.password = argv.shift if options.batch_mode
|
|
161
|
-
|
|
162
|
-
rescue ::OptionParser::ParseError => pe
|
|
163
|
-
$stderr.puts "ERROR: #{option_parser.program_name} - #{pe}"
|
|
164
|
-
show_help
|
|
165
|
-
exit 1
|
|
145
|
+
option_parser.parse!(argv)
|
|
146
|
+
show_version if options.show_version
|
|
147
|
+
show_help if options.show_help
|
|
148
|
+
|
|
149
|
+
if options.operation.size > 1
|
|
150
|
+
raise ::OptionParser::ParseError,
|
|
151
|
+
"only one of --create, --stdout, --verify, --delete may be specified"
|
|
152
|
+
end
|
|
153
|
+
if options.send_to_stdout && (options.file_mode == File::CREATE)
|
|
154
|
+
raise ::OptionParser::ParseError,
|
|
155
|
+
"Unable to send to stdout AND create a new file"
|
|
156
|
+
end
|
|
157
|
+
raise ::OptionParser::ParseError, "a username is needed" if options.send_to_stdout && argv.empty?
|
|
158
|
+
if options.send_to_stdout && options.batch_mode && (argv.size < 2)
|
|
159
|
+
raise ::OptionParser::ParseError,
|
|
160
|
+
"a username and password are needed"
|
|
166
161
|
end
|
|
162
|
+
if !options.send_to_stdout && options.batch_mode && (argv.size < 3)
|
|
163
|
+
raise ::OptionParser::ParseError,
|
|
164
|
+
"a passwordfile, username and password are needed "
|
|
165
|
+
end
|
|
166
|
+
raise ::OptionParser::ParseError, "a passwordfile and username are needed" if argv.size < 2
|
|
167
|
+
if options.batch_mode && options.read_stdin_once
|
|
168
|
+
raise ::OptionParser::ParseError,
|
|
169
|
+
"options -i and -b are mutually exclusive"
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
options.operation = options.operation.shift || :add_or_update
|
|
173
|
+
options.passwdfile = argv.shift unless options.send_to_stdout
|
|
174
|
+
options.username = argv.shift
|
|
175
|
+
options.password = argv.shift if options.batch_mode
|
|
176
|
+
rescue ::OptionParser::ParseError => e
|
|
177
|
+
warn "ERROR: #{option_parser.program_name} - #{e}"
|
|
178
|
+
show_help
|
|
179
|
+
exit 1
|
|
167
180
|
end
|
|
168
181
|
|
|
169
|
-
def fetch_password(width=20)
|
|
182
|
+
def fetch_password(width = 20)
|
|
170
183
|
return options.password if options.batch_mode
|
|
184
|
+
|
|
171
185
|
console = Console.new
|
|
172
|
-
if options.read_stdin_once
|
|
186
|
+
if options.read_stdin_once
|
|
173
187
|
pw_in = console.read_answer
|
|
174
188
|
return pw_in
|
|
175
189
|
end
|
|
@@ -186,10 +200,10 @@ Usage:
|
|
|
186
200
|
raise PasswordError, "They don't match, sorry." unless pw_in == pw_validate
|
|
187
201
|
end
|
|
188
202
|
|
|
189
|
-
|
|
203
|
+
pw_in
|
|
190
204
|
end
|
|
191
205
|
|
|
192
|
-
def run(argv,
|
|
206
|
+
def run(argv, _env = ENV)
|
|
193
207
|
begin
|
|
194
208
|
parse_options(argv)
|
|
195
209
|
console = Console.new
|
|
@@ -199,16 +213,15 @@ Usage:
|
|
|
199
213
|
passwd_file.delete(options.username)
|
|
200
214
|
passwd_file.save!
|
|
201
215
|
when :verify
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
raise HTAuth::Error, "Password verification for user #{options.username} failed."
|
|
208
|
-
end
|
|
209
|
-
else
|
|
210
|
-
raise HTAuth::Error, "User #{options.username} not found"
|
|
216
|
+
raise HTAuth::Error, "User #{options.username} not found" unless passwd_file.has_entry?(options.username)
|
|
217
|
+
|
|
218
|
+
pw_in = fetch_password
|
|
219
|
+
unless passwd_file.authenticated?(options.username, pw_in)
|
|
220
|
+
raise HTAuth::Error, "Password verification for user #{options.username} failed."
|
|
211
221
|
end
|
|
222
|
+
|
|
223
|
+
warn "Password for user #{options.username} correct."
|
|
224
|
+
|
|
212
225
|
when :add_or_update
|
|
213
226
|
options.password = fetch_password
|
|
214
227
|
action = passwd_file.has_entry?(options.username) ? "Changing" : "Adding"
|
|
@@ -220,16 +233,16 @@ Usage:
|
|
|
220
233
|
passwd_file.add_or_update(options.username, options.password, options.algorithm, options.algorithm_args)
|
|
221
234
|
passwd_file.save!
|
|
222
235
|
end
|
|
223
|
-
rescue HTAuth::FileAccessError =>
|
|
236
|
+
rescue HTAuth::FileAccessError => e
|
|
224
237
|
msg = "Password file failure (#{options.passwdfile}) "
|
|
225
|
-
|
|
238
|
+
warn "#{msg}: #{e.message}"
|
|
226
239
|
exit 1
|
|
227
|
-
rescue HTAuth::Error =>
|
|
228
|
-
|
|
240
|
+
rescue HTAuth::Error => e
|
|
241
|
+
warn e.message
|
|
229
242
|
exit 1
|
|
230
|
-
rescue SignalException =>
|
|
243
|
+
rescue SignalException => e
|
|
231
244
|
$stderr.puts
|
|
232
|
-
|
|
245
|
+
warn "Interrupted #{e}"
|
|
233
246
|
exit 1
|
|
234
247
|
end
|
|
235
248
|
exit 0
|
data/lib/htauth/cli.rb
CHANGED
data/lib/htauth/console.rb
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "io/console"
|
|
4
|
+
require "htauth/error"
|
|
3
5
|
|
|
4
6
|
# With many thanks to JEG2 - http://graysoftinc.com/terminal-tricks/random-access-terminal
|
|
5
7
|
#
|
|
6
8
|
module HTAuth
|
|
7
9
|
# Internal: Utility class for managing console input/output
|
|
8
10
|
class Console
|
|
9
|
-
attr_reader :input
|
|
10
|
-
attr_reader :output
|
|
11
|
+
attr_reader :input, :output
|
|
11
12
|
|
|
12
13
|
def initialize(input = $stdin, output = $stdout)
|
|
13
14
|
@input = input
|
|
@@ -23,9 +24,11 @@ module HTAuth
|
|
|
23
24
|
answer = read_answer
|
|
24
25
|
output.puts
|
|
25
26
|
raise ConsoleError, "No input given" if answer.nil?
|
|
27
|
+
|
|
26
28
|
answer.strip!
|
|
27
|
-
raise ConsoleError, "No input given" if answer.
|
|
28
|
-
|
|
29
|
+
raise ConsoleError, "No input given" if answer.empty?
|
|
30
|
+
|
|
31
|
+
answer
|
|
29
32
|
end
|
|
30
33
|
|
|
31
34
|
def read_answer
|
data/lib/htauth/crypt.rb
CHANGED
|
@@ -1,26 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "htauth/algorithm"
|
|
2
4
|
|
|
3
5
|
module HTAuth
|
|
4
6
|
# Internal: The basic crypt algorithm
|
|
5
7
|
class Crypt < Algorithm
|
|
6
|
-
|
|
7
8
|
ENTRY_LENGTH = 13
|
|
8
|
-
ENTRY_REGEX =
|
|
9
|
+
ENTRY_REGEX = /\A[^$:\s]{#{ENTRY_LENGTH}}\z/
|
|
9
10
|
|
|
10
11
|
def self.handles?(password_entry)
|
|
11
12
|
ENTRY_REGEX.match?(password_entry)
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def self.extract_salt_from_existing_password_field(existing)
|
|
15
|
-
existing[0,2]
|
|
16
|
+
existing[0, 2]
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
def initialize(params = {})
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
super()
|
|
21
|
+
@salt = if (existing = params["existing"] || params[:existing])
|
|
22
|
+
self.class.extract_salt_from_existing_password_field(existing)
|
|
23
|
+
else
|
|
24
|
+
params[:salt] || params["salt"] || gen_salt
|
|
25
|
+
end
|
|
24
26
|
end
|
|
25
27
|
|
|
26
28
|
def encode(password)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module HTAuth
|
|
2
4
|
#
|
|
3
5
|
# Use by either
|
|
@@ -18,28 +20,28 @@ module HTAuth
|
|
|
18
20
|
# them in a Set that is available via the 'children' method.
|
|
19
21
|
#
|
|
20
22
|
module DescendantTracker
|
|
21
|
-
def inherited(
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
def inherited(klass)
|
|
24
|
+
super
|
|
25
|
+
return unless klass.instance_of?(Class)
|
|
26
|
+
|
|
27
|
+
children << klass
|
|
24
28
|
end
|
|
25
29
|
|
|
26
30
|
#
|
|
27
31
|
# The list of children that are registered
|
|
28
32
|
#
|
|
29
33
|
def children
|
|
30
|
-
unless defined? @children
|
|
31
|
-
|
|
32
|
-
end
|
|
33
|
-
return @children
|
|
34
|
+
@children = [] unless defined? @children
|
|
35
|
+
@children
|
|
34
36
|
end
|
|
35
37
|
|
|
36
38
|
#
|
|
37
39
|
# find the child that returns truthy for then given method and
|
|
38
40
|
# parameters
|
|
39
41
|
#
|
|
40
|
-
def find_child(
|
|
42
|
+
def find_child(method, *args)
|
|
41
43
|
children.find do |child|
|
|
42
|
-
child.send(
|
|
44
|
+
child.send(method, *args)
|
|
43
45
|
end
|
|
44
46
|
end
|
|
45
47
|
end
|