htauth 1.2.0 → 2.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 +7 -0
- data/Manifest.txt +7 -5
- data/README.md +0 -1
- data/Rakefile +0 -2
- data/bin/htdigest-ruby +2 -9
- data/bin/htpasswd-ruby +2 -9
- data/lib/htauth.rb +2 -3
- data/lib/htauth/algorithm.rb +54 -14
- data/lib/htauth/cli.rb +8 -0
- data/lib/htauth/cli/digest.rb +130 -0
- data/lib/htauth/cli/passwd.rb +179 -0
- data/lib/htauth/console.rb +31 -0
- data/lib/htauth/crypt.rb +1 -2
- data/lib/htauth/digest_entry.rb +31 -11
- data/lib/htauth/digest_file.rb +95 -9
- data/lib/htauth/entry.rb +2 -2
- data/lib/htauth/error.rb +18 -0
- data/lib/htauth/file.rb +87 -16
- data/lib/htauth/md5.rb +1 -2
- data/lib/htauth/passwd_entry.rb +47 -15
- data/lib/htauth/passwd_file.rb +108 -11
- data/lib/htauth/plaintext.rb +1 -2
- data/lib/htauth/sha1.rb +13 -13
- data/lib/htauth/version.rb +2 -19
- data/spec/cli/digest_spec.rb +150 -0
- data/spec/cli/passwd_spec.rb +206 -0
- data/spec/digest_entry_spec.rb +55 -55
- data/spec/digest_file_spec.rb +50 -50
- data/spec/md5_spec.rb +9 -9
- data/spec/passwd_entry_spec.rb +133 -133
- data/spec/passwd_file_spec.rb +50 -50
- data/spec/plaintext_spec.rb +8 -8
- data/spec/sha1_spec.rb +8 -8
- data/spec/spec_helper.rb +7 -0
- metadata +11 -23
- data/lib/htauth/digest.rb +0 -132
- data/lib/htauth/errors.rb +0 -10
- data/lib/htauth/passwd.rb +0 -181
- data/spec/digest_spec.rb +0 -150
- data/spec/passwd_spec.rb +0 -206
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64406e1178b07885f40df5db23c5962c040dff9a
|
4
|
+
data.tar.gz: a4d90738e83e05cfc38e857426be2e95ed4e8700
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 680bdc7d37adccad0a9358fdf391440abce27e8adc65e50dfeb394d0fbd884f3c3d951c2688590e33ef841a4bfb699035b167c2b57a764d93858b0dce1eb878e
|
7
|
+
data.tar.gz: 5c39dd6133939c4ce2eb3845fcac8135f355fc141930ade586bfeca16cc43d5fe4df556891cdb44be7de26ff862fd2aa8dd4b5ff22adb3bb5d10ba90eb61771b
|
data/HISTORY.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## Version 2.0.0 - 2015-09-13
|
4
|
+
|
5
|
+
* Remove highline dependency - [#9](https://github.com/copiousfreetime/htauth/pull/9)
|
6
|
+
* Tomdoc the public interface - [#10](https://github.com/copiousfreetime/htauth/issues/10)
|
7
|
+
* Extract the commandline objects to their own module - [#2](https://github.com/copiousfreetime/htauth/issues/2)
|
8
|
+
* Use a secure comparison when comparing digests - [#11](https://github.com/copiousfreetime/htauth/issues/11)
|
9
|
+
|
3
10
|
## Version 1.2.0 2015-07-18
|
4
11
|
|
5
12
|
* Clarify project license (its MIT) - [#7](https://github.com/copiousfreetime/htauth/issues/7)
|
data/Manifest.txt
CHANGED
@@ -8,28 +8,30 @@ bin/htdigest-ruby
|
|
8
8
|
bin/htpasswd-ruby
|
9
9
|
lib/htauth.rb
|
10
10
|
lib/htauth/algorithm.rb
|
11
|
+
lib/htauth/cli.rb
|
12
|
+
lib/htauth/cli/digest.rb
|
13
|
+
lib/htauth/cli/passwd.rb
|
14
|
+
lib/htauth/console.rb
|
11
15
|
lib/htauth/crypt.rb
|
12
|
-
lib/htauth/digest.rb
|
13
16
|
lib/htauth/digest_entry.rb
|
14
17
|
lib/htauth/digest_file.rb
|
15
18
|
lib/htauth/entry.rb
|
16
|
-
lib/htauth/
|
19
|
+
lib/htauth/error.rb
|
17
20
|
lib/htauth/file.rb
|
18
21
|
lib/htauth/md5.rb
|
19
|
-
lib/htauth/passwd.rb
|
20
22
|
lib/htauth/passwd_entry.rb
|
21
23
|
lib/htauth/passwd_file.rb
|
22
24
|
lib/htauth/plaintext.rb
|
23
25
|
lib/htauth/sha1.rb
|
24
26
|
lib/htauth/version.rb
|
27
|
+
spec/cli/digest_spec.rb
|
28
|
+
spec/cli/passwd_spec.rb
|
25
29
|
spec/crypt_spec.rb
|
26
30
|
spec/digest_entry_spec.rb
|
27
31
|
spec/digest_file_spec.rb
|
28
|
-
spec/digest_spec.rb
|
29
32
|
spec/md5_spec.rb
|
30
33
|
spec/passwd_entry_spec.rb
|
31
34
|
spec/passwd_file_spec.rb
|
32
|
-
spec/passwd_spec.rb
|
33
35
|
spec/plaintext_spec.rb
|
34
36
|
spec/sha1_spec.rb
|
35
37
|
spec/spec_helper.rb
|
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -11,8 +11,6 @@ This.ruby_gemspec do |spec|
|
|
11
11
|
spec.add_development_dependency( 'minitest' , '~> 5.0' )
|
12
12
|
spec.add_development_dependency( 'rdoc' , '~> 4.0' )
|
13
13
|
spec.add_development_dependency( 'simplecov', '~> 0.9' )
|
14
|
-
|
15
|
-
spec.add_dependency("highline", "~> 1.6")
|
16
14
|
end
|
17
15
|
|
18
16
|
load 'tasks/default.rake'
|
data/bin/htdigest-ruby
CHANGED
@@ -1,14 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
begin
|
4
|
-
require 'highline'
|
5
|
-
rescue LoadError
|
6
|
-
require 'rubygems'
|
7
|
-
require 'highline'
|
8
|
-
end
|
9
|
-
|
10
3
|
begin
|
11
|
-
require 'htauth'
|
4
|
+
require 'htauth/cli'
|
12
5
|
rescue LoadError
|
13
6
|
path = File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
|
14
7
|
raise if $:.include?(path)
|
@@ -16,4 +9,4 @@ rescue LoadError
|
|
16
9
|
retry
|
17
10
|
end
|
18
11
|
|
19
|
-
HTAuth::Digest.new.run(ARGV, ENV)
|
12
|
+
HTAuth::CLI::Digest.new.run(ARGV, ENV)
|
data/bin/htpasswd-ruby
CHANGED
@@ -1,14 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
begin
|
4
|
-
require '
|
5
|
-
rescue LoadError
|
6
|
-
require 'rubygems'
|
7
|
-
require 'highline'
|
8
|
-
end
|
9
|
-
|
10
|
-
begin
|
11
|
-
require 'htauth'
|
4
|
+
require 'htauth/cli'
|
12
5
|
rescue LoadError
|
13
6
|
path = File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
|
14
7
|
raise if $:.include?(path)
|
@@ -16,4 +9,4 @@ rescue LoadError
|
|
16
9
|
retry
|
17
10
|
end
|
18
11
|
|
19
|
-
HTAuth::Passwd.new.run(ARGV, ENV)
|
12
|
+
HTAuth::CLI::Passwd.new.run(ARGV, ENV)
|
data/lib/htauth.rb
CHANGED
@@ -30,15 +30,14 @@ end
|
|
30
30
|
|
31
31
|
require 'htauth/version'
|
32
32
|
require 'htauth/algorithm'
|
33
|
+
require 'htauth/console'
|
33
34
|
require 'htauth/crypt'
|
34
|
-
require 'htauth/digest'
|
35
35
|
require 'htauth/digest_entry'
|
36
36
|
require 'htauth/digest_file'
|
37
37
|
require 'htauth/entry'
|
38
|
-
require 'htauth/
|
38
|
+
require 'htauth/error'
|
39
39
|
require 'htauth/file'
|
40
40
|
require 'htauth/md5'
|
41
|
-
require 'htauth/passwd'
|
42
41
|
require 'htauth/passwd_entry'
|
43
42
|
require 'htauth/passwd_file'
|
44
43
|
require 'htauth/plaintext'
|
data/lib/htauth/algorithm.rb
CHANGED
@@ -1,11 +1,29 @@
|
|
1
|
+
require 'htauth/error'
|
2
|
+
require 'securerandom'
|
1
3
|
module HTAuth
|
2
|
-
class InvalidAlgorithmError <
|
3
|
-
|
4
|
+
class InvalidAlgorithmError < Error; end
|
5
|
+
|
6
|
+
# Internal: Base class all the password algorithms derive from
|
7
|
+
#
|
4
8
|
class Algorithm
|
5
9
|
|
6
10
|
SALT_CHARS = (%w[ . / ] + ("0".."9").to_a + ('A'..'Z').to_a + ('a'..'z').to_a).freeze
|
7
|
-
|
8
|
-
|
11
|
+
|
12
|
+
# Public: flag for the md5 algorithm
|
13
|
+
MD5 = "md5".freeze
|
14
|
+
# Public: flag for the sha1 algorithm
|
15
|
+
SHA1 = "sha1".freeze
|
16
|
+
# Public: flag for the plaintext algorithm
|
17
|
+
PLAINTEXT = "plaintext".freeze
|
18
|
+
# Public: flag for the crypt algorithm
|
19
|
+
CRYPT = "crypt".freeze
|
20
|
+
|
21
|
+
# Public: flag for the default algorithm
|
22
|
+
DEFAULT = MD5
|
23
|
+
|
24
|
+
# Public: flag to indicate using the existing algorithm of the entry
|
25
|
+
EXISTING = "existing".freeze
|
26
|
+
|
9
27
|
|
10
28
|
class << self
|
11
29
|
def algorithm_from_name(a_name, params = {})
|
@@ -16,14 +34,14 @@ module HTAuth
|
|
16
34
|
def algorithms_from_field(password_field)
|
17
35
|
matches = []
|
18
36
|
|
19
|
-
if password_field.index(sub_klasses[
|
20
|
-
matches << sub_klasses[
|
21
|
-
elsif password_field.index(sub_klasses[
|
37
|
+
if password_field.index(sub_klasses[SHA1].new.prefix) then
|
38
|
+
matches << sub_klasses[SHA1].new
|
39
|
+
elsif password_field.index(sub_klasses[MD5].new.prefix) then
|
22
40
|
p = password_field.split("$")
|
23
|
-
matches << sub_klasses[
|
41
|
+
matches << sub_klasses[MD5].new( :salt => p[2] )
|
24
42
|
else
|
25
|
-
matches << sub_klasses[
|
26
|
-
matches << sub_klasses[
|
43
|
+
matches << sub_klasses[PLAINTEXT].new
|
44
|
+
matches << sub_klasses[CRYPT].new( :salt => password_field[0,2] )
|
27
45
|
end
|
28
46
|
|
29
47
|
return matches
|
@@ -37,19 +55,41 @@ module HTAuth
|
|
37
55
|
def sub_klasses
|
38
56
|
@sub_klasses ||= {}
|
39
57
|
end
|
58
|
+
|
59
|
+
# Internal: Constant time string comparison.
|
60
|
+
#
|
61
|
+
# From https://github.com/rack/rack/blob/master/lib/rack/utils.rb
|
62
|
+
#
|
63
|
+
# NOTE: the values compared should be of fixed length, such as strings
|
64
|
+
# that have already been processed by HMAC. This should not be used
|
65
|
+
# on variable length plaintext strings because it could leak length info
|
66
|
+
# via timing attacks.
|
67
|
+
def secure_compare(a, b)
|
68
|
+
return false unless a.bytesize == b.bytesize
|
69
|
+
|
70
|
+
l = a.unpack("C*")
|
71
|
+
|
72
|
+
r, i = 0, -1
|
73
|
+
b.each_byte { |v| r |= v ^ l[i+=1] }
|
74
|
+
r == 0
|
75
|
+
end
|
40
76
|
end
|
41
77
|
|
78
|
+
# Internal
|
42
79
|
def prefix ; end
|
80
|
+
|
81
|
+
# Internal
|
43
82
|
def encode(password) ; end
|
44
83
|
|
45
|
-
# 8 bytes of random items from SALT_CHARS
|
84
|
+
# Internal: 8 bytes of random items from SALT_CHARS
|
46
85
|
def gen_salt
|
47
86
|
chars = []
|
48
|
-
8.times { chars << SALT_CHARS[
|
49
|
-
chars.join('')
|
87
|
+
8.times { chars << SALT_CHARS[SecureRandom.random_number(SALT_CHARS.size)] }
|
88
|
+
chars.join('')
|
50
89
|
end
|
51
90
|
|
52
|
-
# this is not the Base64 encoding, this is the to64()
|
91
|
+
# Internal: this is not the Base64 encoding, this is the to64()
|
92
|
+
# method from the apache protable runtime library
|
53
93
|
def to_64(number, rounds)
|
54
94
|
r = StringIO.new
|
55
95
|
rounds.times do |x|
|
data/lib/htauth/cli.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'htauth/version'
|
2
|
+
require 'htauth/error'
|
3
|
+
require 'htauth/digest_file'
|
4
|
+
require 'htauth/console'
|
5
|
+
|
6
|
+
require 'ostruct'
|
7
|
+
require 'optparse'
|
8
|
+
|
9
|
+
module HTAuth
|
10
|
+
module CLI
|
11
|
+
# Internal: Implemenation of the commandline htdigest-ruby
|
12
|
+
class Digest
|
13
|
+
|
14
|
+
MAX_PASSWD_LENGTH = 255
|
15
|
+
|
16
|
+
attr_accessor :digest_file
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@digest_file = nil
|
20
|
+
@option_parser = nil
|
21
|
+
@options = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def options
|
25
|
+
if @options.nil? then
|
26
|
+
@options = ::OpenStruct.new
|
27
|
+
@options.show_version = false
|
28
|
+
@options.show_help = false
|
29
|
+
@options.file_mode = DigestFile::ALTER
|
30
|
+
@options.passwdfile = nil
|
31
|
+
@options.realm = nil
|
32
|
+
@options.username = nil
|
33
|
+
@options.delete_entry = false
|
34
|
+
end
|
35
|
+
@options
|
36
|
+
end
|
37
|
+
|
38
|
+
def option_parser
|
39
|
+
if not @option_parser then
|
40
|
+
@option_parser = OptionParser.new do |op|
|
41
|
+
op.banner = "Usage: #{op.program_name} [options] passwordfile realm username"
|
42
|
+
op.on("-c", "--create", "Create a new digest password file; this overwrites an existing file.") do |c|
|
43
|
+
options.file_mode = DigestFile::CREATE
|
44
|
+
end
|
45
|
+
|
46
|
+
op.on("-D", "--delete", "Delete the specified user.") do |d|
|
47
|
+
options.delete_entry = d
|
48
|
+
end
|
49
|
+
|
50
|
+
op.on("-h", "--help", "Display this help.") do |h|
|
51
|
+
options.show_help = h
|
52
|
+
end
|
53
|
+
|
54
|
+
op.on("-v", "--version", "Show version info.") do |v|
|
55
|
+
options.show_version = v
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
@option_parser
|
60
|
+
end
|
61
|
+
|
62
|
+
def show_help
|
63
|
+
$stdout.puts option_parser
|
64
|
+
exit 1
|
65
|
+
end
|
66
|
+
|
67
|
+
def show_version
|
68
|
+
$stdout.puts "#{option_parser.program_name}: version #{HTAuth::VERSION}"
|
69
|
+
exit 1
|
70
|
+
end
|
71
|
+
|
72
|
+
def parse_options(argv)
|
73
|
+
begin
|
74
|
+
option_parser.parse!(argv)
|
75
|
+
show_version if options.show_version
|
76
|
+
show_help if options.show_help or argv.size < 3
|
77
|
+
|
78
|
+
options.passwdfile = argv.shift
|
79
|
+
options.realm = argv.shift
|
80
|
+
options.username = argv.shift
|
81
|
+
rescue ::OptionParser::ParseError => pe
|
82
|
+
$stderr.puts "ERROR: #{option_parser.program_name} - #{pe}"
|
83
|
+
$stderr.puts "Try `#{option_parser.program_name} --help` for more information"
|
84
|
+
exit 1
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def run(argv, env = ENV)
|
89
|
+
begin
|
90
|
+
parse_options(argv)
|
91
|
+
digest_file = DigestFile.new(options.passwdfile, options.file_mode)
|
92
|
+
|
93
|
+
if options.delete_entry then
|
94
|
+
digest_file.delete(options.username, options.realm)
|
95
|
+
else
|
96
|
+
console = Console.new
|
97
|
+
|
98
|
+
action = digest_file.has_entry?(options.username, options.realm) ? "Changing" : "Adding"
|
99
|
+
|
100
|
+
console.say "#{action} password for #{options.username} in realm #{options.realm}."
|
101
|
+
|
102
|
+
pw_in = console.ask(" New password: ")
|
103
|
+
raise PasswordError, "password '#{pw_in}' too long" if pw_in.length >= MAX_PASSWD_LENGTH
|
104
|
+
|
105
|
+
pw_validate = console.ask("Re-type new password: ")
|
106
|
+
raise PasswordError, "They don't match, sorry." unless pw_in == pw_validate
|
107
|
+
|
108
|
+
digest_file.add_or_update(options.username, options.realm, pw_in)
|
109
|
+
end
|
110
|
+
|
111
|
+
digest_file.save!
|
112
|
+
|
113
|
+
rescue HTAuth::FileAccessError => fae
|
114
|
+
msg = "Could not open password file #{options.passwdfile} "
|
115
|
+
$stderr.puts "#{msg}: #{fae.message}"
|
116
|
+
$stderr.puts fae.backtrace.join("\n")
|
117
|
+
exit 1
|
118
|
+
rescue HTAuth::Error => pe
|
119
|
+
$stderr.puts "#{pe.message}"
|
120
|
+
exit 1
|
121
|
+
rescue SignalException => se
|
122
|
+
$stderr.puts
|
123
|
+
$stderr.puts "Interrupted #{se}"
|
124
|
+
exit 1
|
125
|
+
end
|
126
|
+
exit 0
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
require 'htauth/error'
|
2
|
+
require 'htauth/passwd_file'
|
3
|
+
require 'htauth/console'
|
4
|
+
|
5
|
+
require 'ostruct'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
module HTAuth
|
9
|
+
module CLI
|
10
|
+
# Internal: Implemenation of the commandline htpasswd-ruby
|
11
|
+
class Passwd
|
12
|
+
|
13
|
+
MAX_PASSWD_LENGTH = 255
|
14
|
+
|
15
|
+
attr_accessor :passwd_file
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@passwd_file = nil
|
19
|
+
@option_parser = nil
|
20
|
+
@options = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def options
|
24
|
+
if @options.nil? then
|
25
|
+
@options = ::OpenStruct.new
|
26
|
+
@options.batch_mode = false
|
27
|
+
@options.file_mode = File::ALTER
|
28
|
+
@options.passwdfile = nil
|
29
|
+
@options.algorithm = Algorithm::EXISTING
|
30
|
+
@options.send_to_stdout = false
|
31
|
+
@options.show_version = false
|
32
|
+
@options.show_help = false
|
33
|
+
@options.username = nil
|
34
|
+
@options.delete_entry = false
|
35
|
+
@options.password = ""
|
36
|
+
end
|
37
|
+
@options
|
38
|
+
end
|
39
|
+
|
40
|
+
def option_parser
|
41
|
+
if not @option_parser then
|
42
|
+
@option_parser = OptionParser.new do |op|
|
43
|
+
op.banner = <<-EOB
|
44
|
+
Usage:
|
45
|
+
#{op.program_name} [-cmdpsD] passwordfile username
|
46
|
+
#{op.program_name} -b[cmdpsD] passwordfile username password
|
47
|
+
|
48
|
+
#{op.program_name} -n[mdps] username
|
49
|
+
#{op.program_name} -nb[mdps] username password
|
50
|
+
EOB
|
51
|
+
|
52
|
+
op.separator ""
|
53
|
+
|
54
|
+
op.on("-b", "--batch", "Batch mode, get the password from the command line, rather than prompt") do |b|
|
55
|
+
options.batch_mode = b
|
56
|
+
end
|
57
|
+
|
58
|
+
op.on("-c", "--create", "Create a new file; this overwrites an existing file.") do |c|
|
59
|
+
options.file_mode = HTAuth::File::CREATE
|
60
|
+
end
|
61
|
+
|
62
|
+
op.on("-d", "--crypt", "Force CRYPT encryption of the password.") do |c|
|
63
|
+
options.algorithm = Algorithm::CRYPT
|
64
|
+
end
|
65
|
+
|
66
|
+
op.on("-D", "--delete", "Delete the specified user.") do |d|
|
67
|
+
options.delete_entry = d
|
68
|
+
end
|
69
|
+
|
70
|
+
op.on("-h", "--help", "Display this help.") do |h|
|
71
|
+
options.show_help = h
|
72
|
+
end
|
73
|
+
|
74
|
+
op.on("-m", "--md5", "Force MD5 encryption of the password (default).") do |m|
|
75
|
+
options.algorithm = Algorithm::MD5
|
76
|
+
end
|
77
|
+
|
78
|
+
op.on("-n", "--stdout", "Do not update the file; Display the results on stdout instead.") do |n|
|
79
|
+
options.send_to_stdout = true
|
80
|
+
options.passwdfile = HTAuth::File::STDOUT_FLAG
|
81
|
+
end
|
82
|
+
|
83
|
+
op.on("-p", "--plaintext", "Do not encrypt the password (plaintext).") do |p|
|
84
|
+
options.algorithm = Algorithm::PLAINTEXT
|
85
|
+
end
|
86
|
+
|
87
|
+
op.on("-s", "--sha1", "Force SHA encryption of the password.") do |s|
|
88
|
+
options.algorithm = Algorithm::SHA1
|
89
|
+
end
|
90
|
+
|
91
|
+
op.on("-v", "--version", "Show version info.") do |v|
|
92
|
+
options.show_version = v
|
93
|
+
end
|
94
|
+
|
95
|
+
op.separator ""
|
96
|
+
|
97
|
+
op.separator "The SHA algorihtm does not use a salt and is less secure than the MD5 algorithm"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
@option_parser
|
101
|
+
end
|
102
|
+
|
103
|
+
def show_help
|
104
|
+
$stdout.puts option_parser
|
105
|
+
exit 1
|
106
|
+
end
|
107
|
+
|
108
|
+
def show_version
|
109
|
+
$stdout.puts "#{option_parser.program_name}: version #{HTAuth::VERSION}"
|
110
|
+
exit 1
|
111
|
+
end
|
112
|
+
|
113
|
+
def parse_options(argv)
|
114
|
+
begin
|
115
|
+
option_parser.parse!(argv)
|
116
|
+
show_version if options.show_version
|
117
|
+
show_help if options.show_help
|
118
|
+
|
119
|
+
raise ::OptionParser::ParseError, "Unable to send to stdout AND create a new file" if options.send_to_stdout and (options.file_mode == File::CREATE)
|
120
|
+
raise ::OptionParser::ParseError, "a username is needed" if options.send_to_stdout and argv.size < 1
|
121
|
+
raise ::OptionParser::ParseError, "a username and password are needed" if options.send_to_stdout and options.batch_mode and ( argv.size < 2 )
|
122
|
+
raise ::OptionParser::ParseError, "a passwordfile, username and password are needed " if not options.send_to_stdout and options.batch_mode and ( argv.size < 3 )
|
123
|
+
raise ::OptionParser::ParseError, "a passwordfile and username are needed" if argv.size < 2
|
124
|
+
|
125
|
+
options.passwdfile = argv.shift unless options.send_to_stdout
|
126
|
+
options.username = argv.shift
|
127
|
+
options.password = argv.shift if options.batch_mode
|
128
|
+
|
129
|
+
rescue ::OptionParser::ParseError => pe
|
130
|
+
$stderr.puts "ERROR: #{option_parser.program_name} - #{pe}"
|
131
|
+
show_help
|
132
|
+
exit 1
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def run(argv, env = ENV)
|
137
|
+
begin
|
138
|
+
parse_options(argv)
|
139
|
+
passwd_file = PasswdFile.new(options.passwdfile, options.file_mode)
|
140
|
+
|
141
|
+
if options.delete_entry then
|
142
|
+
passwd_file.delete(options.username)
|
143
|
+
else
|
144
|
+
unless options.batch_mode
|
145
|
+
console = Console.new
|
146
|
+
|
147
|
+
action = passwd_file.has_entry?(options.username) ? "Changing" : "Adding"
|
148
|
+
|
149
|
+
console.say "#{action} password for #{options.username}."
|
150
|
+
|
151
|
+
pw_in = console.ask(" New password: ")
|
152
|
+
raise PasswordError, "password '#{pw_in}' too long" if pw_in.length >= MAX_PASSWD_LENGTH
|
153
|
+
|
154
|
+
pw_validate = console.ask("Re-type new password: ")
|
155
|
+
raise PasswordError, "They don't match, sorry." unless pw_in == pw_validate
|
156
|
+
options.password = pw_in
|
157
|
+
end
|
158
|
+
passwd_file.add_or_update(options.username, options.password, options.algorithm)
|
159
|
+
end
|
160
|
+
|
161
|
+
passwd_file.save!
|
162
|
+
|
163
|
+
rescue HTAuth::FileAccessError => fae
|
164
|
+
msg = "Password file failure (#{options.passwdfile}) "
|
165
|
+
$stderr.puts "#{msg}: #{fae.message}"
|
166
|
+
exit 1
|
167
|
+
rescue HTAuth::Error => pe
|
168
|
+
$stderr.puts "#{pe.message}"
|
169
|
+
exit 1
|
170
|
+
rescue SignalException => se
|
171
|
+
$stderr.puts
|
172
|
+
$stderr.puts "Interrupted #{se}"
|
173
|
+
exit 1
|
174
|
+
end
|
175
|
+
exit 0
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|