htauth 1.2.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|