htauth 2.3.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/HISTORY.md +14 -0
  3. data/Manifest.txt +4 -28
  4. data/exe/htdigest-ruby +14 -0
  5. data/exe/htpasswd-ruby +14 -0
  6. data/htauth.gemspec +33 -0
  7. data/lib/htauth/algorithm.rb +30 -29
  8. data/lib/htauth/argon2.rb +45 -36
  9. data/lib/htauth/bcrypt.rb +12 -11
  10. data/lib/htauth/cli/digest.rb +42 -46
  11. data/lib/htauth/cli/passwd.rb +126 -115
  12. data/lib/htauth/cli.rb +5 -3
  13. data/lib/htauth/console.rb +9 -6
  14. data/lib/htauth/crypt.rb +11 -9
  15. data/lib/htauth/descendant_tracker.rb +11 -9
  16. data/lib/htauth/digest_entry.rb +22 -20
  17. data/lib/htauth/digest_file.rb +25 -18
  18. data/lib/htauth/entry.rb +3 -1
  19. data/lib/htauth/error.rb +6 -5
  20. data/lib/htauth/file.rb +35 -39
  21. data/lib/htauth/md5.rb +35 -34
  22. data/lib/htauth/passwd_entry.rb +26 -24
  23. data/lib/htauth/passwd_file.rb +26 -21
  24. data/lib/htauth/plaintext.rb +7 -5
  25. data/lib/htauth/sha1.rb +9 -7
  26. data/lib/htauth/version.rb +3 -1
  27. data/lib/htauth.rb +29 -28
  28. metadata +15 -133
  29. data/Rakefile +0 -29
  30. data/bin/htdigest-ruby +0 -12
  31. data/bin/htpasswd-ruby +0 -12
  32. data/spec/algorithm_spec.rb +0 -7
  33. data/spec/argon2_spec.rb +0 -28
  34. data/spec/bcrypt_spec.rb +0 -32
  35. data/spec/cli/digest_spec.rb +0 -149
  36. data/spec/cli/passwd_spec.rb +0 -346
  37. data/spec/crypt_spec.rb +0 -11
  38. data/spec/digest_entry_spec.rb +0 -59
  39. data/spec/digest_file_spec.rb +0 -64
  40. data/spec/md5_spec.rb +0 -11
  41. data/spec/passwd_entry_spec.rb +0 -172
  42. data/spec/passwd_file_spec.rb +0 -84
  43. data/spec/plaintext_spec.rb +0 -11
  44. data/spec/sha1_spec.rb +0 -10
  45. data/spec/spec_helper.rb +0 -25
  46. data/spec/test.add.digest +0 -3
  47. data/spec/test.add.passwd +0 -3
  48. data/spec/test.delete.digest +0 -1
  49. data/spec/test.delete.passwd +0 -1
  50. data/spec/test.original.digest +0 -2
  51. data/spec/test.original.passwd +0 -2
  52. data/spec/test.update.digest +0 -2
  53. data/spec/test.update.passwd +0 -2
  54. data/tasks/default.rake +0 -250
  55. data/tasks/this.rb +0 -208
  56. /data/{LICENSE → LICENSE.txt} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ad5523ccfeacb957acb9cf2fae40e19e51bc92e10d093a950949fbe00bb50b1a
4
- data.tar.gz: 280ed439110fd03ca5510ae81d8b17a4f0db21f4f0aed7360238bbcef83fe6c1
3
+ metadata.gz: bf3dca478538f6a659cfe1cbe39b0688782e34f606cba0b116a63a87c42f022e
4
+ data.tar.gz: 83508be980a643ec2a481582ecc8ad02f3f8271b2d34359ab26bad2369d4eddd
5
5
  SHA512:
6
- metadata.gz: cc5ddd224ce189eeb5d16a60059a9fcab868ff65de9aad4efac3177425004d98b22d9af29f556d001ae0c083b31cdaef4cf723c7d1342739fc01c7be12841f42
7
- data.tar.gz: 28a12fef7f3c7a96c9bdb186a71b06b8263da2c1f6b77dfcba45239129a17311d9fbcfa799aaf004efbf09876cc380de99bb91cab6be23ffefc23ce70286618b
6
+ metadata.gz: 48c8f83ca6e2c893731098c076680c37eeb6ff8fe1bde0589957c56239f8239cdb2e8fad01ea2278c6c10f25879e9adc4ba43385f6250435c08207d7b9381a87
7
+ data.tar.gz: a059b27747b6ca12201171500c8f08672b2b378d4e80c83ed5caa9725e009f0366470607e756c02905c253f9c2c4dd173aa58760c7978238a3862c85b038b431
data/HISTORY.md CHANGED
@@ -1,4 +1,18 @@
1
1
  # Changelog
2
+ ## Version 3.0.0 - 2026-05-23
3
+
4
+ * Modernize project structure
5
+ * Bump minimum Ruby version from 2.3.0 to 3.0.0
6
+ * Add rubocop for code linting with multiple plugins
7
+ * Rename `is_entry?`/`is_entry_for?` methods to `entry?`/`entry_for?` (Ruby naming conventions)
8
+ * Update CI build matrix: Ruby 3.3, 3.4, 4.0, JRuby 10.1, TruffleRuby 34.0
9
+ * Remove Ruby 3.2 from build matrix
10
+ * Move development dependencies from gemspec to Gemfile
11
+ * Add `ostruct` as a runtime dependency
12
+ * Remove test files from gem package
13
+ * Rename `LICENSE` to `LICENSE.txt`
14
+ * Apply rubocop autocorrections across all source and spec files
15
+
2
16
  ## Version 2.3.0 - 2024-02-03
3
17
 
4
18
  * Add support for argon2 encryption [#18](https://github.com/copiousfreetime/htauth/pull/18)
data/Manifest.txt CHANGED
@@ -1,11 +1,11 @@
1
1
  CONTRIBUTING.md
2
2
  HISTORY.md
3
- LICENSE
3
+ LICENSE.txt
4
4
  Manifest.txt
5
5
  README.md
6
- Rakefile
7
- bin/htdigest-ruby
8
- bin/htpasswd-ruby
6
+ exe/htdigest-ruby
7
+ exe/htpasswd-ruby
8
+ htauth.gemspec
9
9
  lib/htauth.rb
10
10
  lib/htauth/algorithm.rb
11
11
  lib/htauth/argon2.rb
@@ -27,27 +27,3 @@ lib/htauth/passwd_file.rb
27
27
  lib/htauth/plaintext.rb
28
28
  lib/htauth/sha1.rb
29
29
  lib/htauth/version.rb
30
- spec/algorithm_spec.rb
31
- spec/argon2_spec.rb
32
- spec/bcrypt_spec.rb
33
- spec/cli/digest_spec.rb
34
- spec/cli/passwd_spec.rb
35
- spec/crypt_spec.rb
36
- spec/digest_entry_spec.rb
37
- spec/digest_file_spec.rb
38
- spec/md5_spec.rb
39
- spec/passwd_entry_spec.rb
40
- spec/passwd_file_spec.rb
41
- spec/plaintext_spec.rb
42
- spec/sha1_spec.rb
43
- spec/spec_helper.rb
44
- spec/test.add.digest
45
- spec/test.add.passwd
46
- spec/test.delete.digest
47
- spec/test.delete.passwd
48
- spec/test.original.digest
49
- spec/test.original.passwd
50
- spec/test.update.digest
51
- spec/test.update.passwd
52
- tasks/default.rake
53
- tasks/this.rb
data/exe/htdigest-ruby ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ begin
5
+ require "htauth/cli/digest"
6
+ rescue LoadError
7
+ path = File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
8
+ raise if $LOAD_PATH.include?(path)
9
+
10
+ $LOAD_PATH << path
11
+ retry
12
+ end
13
+
14
+ HTAuth::CLI::Digest.new.run(ARGV, ENV)
data/exe/htpasswd-ruby ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ begin
5
+ require "htauth/cli/passwd"
6
+ rescue LoadError
7
+ path = File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
8
+ raise if $LOAD_PATH.include?(path)
9
+
10
+ $LOAD_PATH << path
11
+ retry
12
+ end
13
+
14
+ HTAuth::CLI::Passwd.new.run(ARGV, ENV)
data/htauth.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # DO NOT EDIT - This file is automatically generated
2
+ # Make changes to Manifest.txt and/or Rakefile and regenerate
3
+ # -*- encoding: utf-8 -*-
4
+ # stub: htauth 3.0.0 ruby lib
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "htauth".freeze
8
+ s.version = "3.0.0".freeze
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
11
+ s.metadata = { "bug_tracker_uri" => "https://github.com/copiousfreetime/htauth/issues", "changelog_uri" => "https://github.com/copiousfreetime/htauth/blob/master/HISTORY.md", "homepage_uri" => "https://github.com/copiousfreetime/htauth", "source_code_uri" => "https://github.com/copiousfreetime/htauth" } if s.respond_to? :metadata=
12
+ s.require_paths = ["lib".freeze]
13
+ s.authors = ["Jeremy Hinegardner".freeze]
14
+ s.bindir = "exe".freeze
15
+ s.date = "2026-05-23"
16
+ s.description = "HTAuth provides an API and commandline tools for managing Apache/httpd style htpasswd and htdigest files.".freeze
17
+ s.email = "jeremy@copiousfreetime.org".freeze
18
+ s.executables = ["htdigest-ruby".freeze, "htpasswd-ruby".freeze]
19
+ s.extra_rdoc_files = ["CONTRIBUTING.md".freeze, "HISTORY.md".freeze, "LICENSE.txt".freeze, "Manifest.txt".freeze, "README.md".freeze]
20
+ s.files = ["CONTRIBUTING.md".freeze, "HISTORY.md".freeze, "LICENSE.txt".freeze, "Manifest.txt".freeze, "README.md".freeze, "exe/htdigest-ruby".freeze, "exe/htpasswd-ruby".freeze, "htauth.gemspec".freeze, "lib/htauth.rb".freeze, "lib/htauth/algorithm.rb".freeze, "lib/htauth/argon2.rb".freeze, "lib/htauth/bcrypt.rb".freeze, "lib/htauth/cli.rb".freeze, "lib/htauth/cli/digest.rb".freeze, "lib/htauth/cli/passwd.rb".freeze, "lib/htauth/console.rb".freeze, "lib/htauth/crypt.rb".freeze, "lib/htauth/descendant_tracker.rb".freeze, "lib/htauth/digest_entry.rb".freeze, "lib/htauth/digest_file.rb".freeze, "lib/htauth/entry.rb".freeze, "lib/htauth/error.rb".freeze, "lib/htauth/file.rb".freeze, "lib/htauth/md5.rb".freeze, "lib/htauth/passwd_entry.rb".freeze, "lib/htauth/passwd_file.rb".freeze, "lib/htauth/plaintext.rb".freeze, "lib/htauth/sha1.rb".freeze, "lib/htauth/version.rb".freeze]
21
+ s.homepage = "http://github.com/copiousfreetime/htauth".freeze
22
+ s.licenses = ["MIT".freeze]
23
+ s.rdoc_options = ["--main".freeze, "README.md".freeze, "--markup".freeze, "tomdoc".freeze]
24
+ s.required_ruby_version = Gem::Requirement.new(">= 3.0.0".freeze)
25
+ s.rubygems_version = "4.0.10".freeze
26
+ s.summary = "HTAuth provides an API and commandline tools for managing Apache/httpd style htpasswd and htdigest files.".freeze
27
+
28
+ s.specification_version = 4
29
+
30
+ s.add_runtime_dependency(%q<bcrypt>.freeze, ["~> 3.1".freeze])
31
+ s.add_runtime_dependency(%q<base64>.freeze, ["~> 0.2".freeze])
32
+ s.add_runtime_dependency(%q<ostruct>.freeze, ["~> 0.6".freeze])
33
+ end
@@ -1,50 +1,50 @@
1
- require 'htauth/error'
2
- require 'htauth/descendant_tracker'
3
- require 'securerandom'
1
+ # frozen_string_literal: true
2
+
3
+ require "htauth/error"
4
+ require "htauth/descendant_tracker"
5
+ require "securerandom"
4
6
  module HTAuth
5
7
  class InvalidAlgorithmError < Error; end
6
8
 
7
9
  # Internal: Base class all the password algorithms derive from
8
10
  #
9
11
  class Algorithm
10
-
11
12
  extend DescendantTracker
12
13
 
13
- SALT_CHARS = (%w[ . / ] + ("0".."9").to_a + ('A'..'Z').to_a + ('a'..'z').to_a).freeze
14
+ SALT_CHARS = (%w[. /] + ("0".."9").to_a + ("A".."Z").to_a + ("a".."z").to_a).freeze
14
15
  SALT_LENGTH = 8
15
16
 
16
17
  # Public: flag for the argon2 algorithm
17
- ARGON2 = "argon2".freeze
18
+ ARGON2 = "argon2"
18
19
  # Public: flag for the bcrypt algorithm
19
- BCRYPT = "bcrypt".freeze
20
+ BCRYPT = "bcrypt"
20
21
  # Public: flag for the md5 algorithm
21
- MD5 = "md5".freeze
22
+ MD5 = "md5"
22
23
  # Public: flag for the sha1 algorithm
23
- SHA1 = "sha1".freeze
24
+ SHA1 = "sha1"
24
25
  # Public: flag for the plaintext algorithm
25
- PLAINTEXT = "plaintext".freeze
26
+ PLAINTEXT = "plaintext"
26
27
  # Public: flag for the crypt algorithm
27
- CRYPT = "crypt".freeze
28
+ CRYPT = "crypt"
28
29
 
29
30
  # Public: flag for the default algorithm
30
31
  DEFAULT = MD5
31
32
 
32
33
  # Public: flag to indicate using the existing algorithm of the entry
33
- EXISTING = "existing".freeze
34
-
34
+ EXISTING = "existing"
35
35
 
36
36
  class << self
37
37
  def algorithm_name
38
- self.name.split("::").last.downcase
38
+ name.split("::").last.downcase
39
39
  end
40
40
 
41
41
  def algorithm_from_name(a_name, params = {})
42
42
  found = children.find { |c| c.algorithm_name == a_name }
43
- if !found then
44
- names = children.map { |c| c.algorithm_name }
43
+ unless found
44
+ names = children.map(&:algorithm_name)
45
45
  raise InvalidAlgorithmError, "`#{a_name}' is an unknown encryption algorithm, use one of #{names.join(', ')}"
46
46
  end
47
- return found.new(params)
47
+ found.new(params)
48
48
  end
49
49
 
50
50
  # NOTE: if it is plaintext, and the length is 13 - it may matched crypt
@@ -57,13 +57,13 @@ module HTAuth
57
57
 
58
58
  raise InvalidAlgorithmError, "unknown encryption algorithm used for `#{password_field}`" if match.nil?
59
59
 
60
- return match.new(:existing => password_field)
60
+ match.new(existing: password_field)
61
61
  end
62
62
 
63
63
  # Internal: Does this class handle this type of password entry
64
64
  #
65
65
  def handles?(password_entry)
66
- raise NotImplementedError, "#{self.name} must implement #{self.name}.handles?(password_entry)"
66
+ raise NotImplementedError, "#{name} must implement #{name}.handles?(password_entry)"
67
67
  end
68
68
 
69
69
  # Internal: Constant time string comparison.
@@ -74,14 +74,15 @@ module HTAuth
74
74
  # that have already been processed by HMAC. This should not be used
75
75
  # on variable length plaintext strings because it could leak length info
76
76
  # via timing attacks.
77
- def secure_compare(a, b)
78
- return false unless a.bytesize == b.bytesize
77
+ def secure_compare(lhs, rhs)
78
+ return false unless lhs.bytesize == rhs.bytesize
79
79
 
80
- l = a.unpack("C*")
80
+ l = lhs.unpack("C*")
81
81
 
82
- r, i = 0, -1
83
- b.each_byte { |v| r |= v ^ l[i+=1] }
84
- r == 0
82
+ r = 0
83
+ i = -1
84
+ rhs.each_byte { |v| r |= v ^ l[i += 1] }
85
+ r.zero?
85
86
  end
86
87
  end
87
88
 
@@ -100,19 +101,19 @@ module HTAuth
100
101
 
101
102
  # Internal: 8 bytes of random items from SALT_CHARS
102
103
  def gen_salt(length = SALT_LENGTH)
103
- Array.new(length) { SALT_CHARS.sample }.join('')
104
+ Array.new(length) { SALT_CHARS.sample }.join
104
105
  end
105
106
 
106
107
  # Internal: this is not the Base64 encoding, this is the to64()
107
108
  # method from the Apache Portable Runtime (APR) library
108
109
  # https://github.com/apache/apr/blob/trunk/crypto/apr_md5.c#L493-L502
109
- def to_64(number, rounds)
110
+ def to64(number, rounds)
110
111
  r = StringIO.new
111
- rounds.times do |x|
112
+ rounds.times do |_x|
112
113
  r.print(SALT_CHARS[number % 64])
113
114
  number >>= 6
114
115
  end
115
- return r.string
116
+ r.string
116
117
  end
117
118
  end
118
119
  end
data/lib/htauth/argon2.rb CHANGED
@@ -1,18 +1,25 @@
1
- require 'htauth/algorithm'
1
+ # frozen_string_literal: true
2
+
3
+ require "htauth/algorithm"
2
4
  begin
3
- require 'argon2'
5
+ require "argon2"
4
6
  rescue LoadError
5
7
  end
6
8
 
7
9
  module HTAuth
8
10
  # Internal: Support of the argon2id algorithm and password format.
9
-
10
11
  class Argon2 < Algorithm
12
+ # Internal: Error class when argon2 is specified on windows
11
13
  class NotSupportedError < ::HTAuth::InvalidAlgorithmError
12
14
  def message
13
- "Unfortunately Argon2 passwords are not supported on `#{RUBY_PLATFORM} at this time. This because the upstream argon2 gem does not support windows."
15
+ [
16
+ "Unfortunately Argon2 passwords are not supported on `#{RUBY_PLATFORM} at this time.",
17
+ "This because the upstream argon2 gem does not support windows.",
18
+ ].join(" ")
14
19
  end
15
20
  end
21
+
22
+ # Internal: Error class when argon2 is not installed
16
23
  class NotInstalledError < ::HTAuth::InvalidAlgorithmError
17
24
  def message
18
25
  "Argon2 passwords are supported if the `argon2' gem is installed. Add `gem 'argon2', '~> 2.3'` to your Gemfile"
@@ -21,7 +28,7 @@ module HTAuth
21
28
 
22
29
  # from upstream, used to help make a nice error message if its not installed
23
30
  # https://github.com/technion/ruby-argon2/blob/3388d7e05e8b486ea4ba8bd2aeb1e9988f025f13/lib/argon2/hash_format.rb#L45
24
- PREFIX = /^\$argon2(id?|d).{,113}/.freeze
31
+ PREFIX = /^\$argon2(id?|d).{,113}/
25
32
  ARGON2_GEM_INSTALLED = defined?(::Argon2)
26
33
 
27
34
  def self.supported?
@@ -35,40 +42,42 @@ module HTAuth
35
42
 
36
43
  attr_accessor :options
37
44
 
38
- def self.handles?(password_entry)
45
+ def self.handles?(password_entry)
39
46
  return false unless PREFIX.match?(password_entry)
47
+
40
48
  ensure_available!
41
49
 
42
- return ::Argon2::Password.valid_hash?(password_entry)
43
- end
44
-
45
- def self.extract_options_from_existing_password_field(existing)
46
- hash_format = ::Argon2::HashFormat.new(existing)
47
-
48
- # m_cost on the input is the 2**m_cost, but in the hash its the number of
49
- # bytes, so need to convert it back to a power of 2, which is the
50
- # log2(m_cost)
51
-
52
- {
53
- t_cost: hash_format.t_cost,
54
- m_cost: ::Math.log2(hash_format.m_cost).floor,
55
- p_cost: hash_format.p_cost,
56
- }
57
- end
58
-
59
- def initialize(params = { profile: :rfc_9106_low_memory })
60
- self.class.ensure_available!
61
- if existing = (params['existing'] || params[:existing]) then
62
- @options = self.class.extract_options_from_existing_password_field(existing)
63
- else
64
- @options = params
65
- end
66
- end
67
-
68
- def encode(password)
69
- argon2 = ::Argon2::Password.new(options)
70
- argon2.create(password)
71
- end
50
+ ::Argon2::Password.valid_hash?(password_entry)
51
+ end
52
+
53
+ def self.extract_options_from_existing_password_field(existing)
54
+ hash_format = ::Argon2::HashFormat.new(existing)
55
+
56
+ # m_cost on the input is the 2**m_cost, but in the hash its the number of
57
+ # bytes, so need to convert it back to a power of 2, which is the
58
+ # log2(m_cost)
59
+
60
+ {
61
+ t_cost: hash_format.t_cost,
62
+ m_cost: ::Math.log2(hash_format.m_cost).floor,
63
+ p_cost: hash_format.p_cost,
64
+ }
65
+ end
66
+
67
+ def initialize(params = { profile: :rfc_9106_low_memory })
68
+ super()
69
+ self.class.ensure_available!
70
+ @options = if (existing = params["existing"] || params[:existing])
71
+ self.class.extract_options_from_existing_password_field(existing)
72
+ else
73
+ params
74
+ end
75
+ end
76
+
77
+ def encode(password)
78
+ argon2 = ::Argon2::Password.new(options)
79
+ argon2.create(password)
80
+ end
72
81
 
73
82
  def verify_password?(password, digest)
74
83
  ::Argon2::Password.verify_password(password, digest)
data/lib/htauth/bcrypt.rb CHANGED
@@ -1,18 +1,18 @@
1
- require 'htauth/algorithm'
2
- require 'bcrypt'
1
+ # frozen_string_literal: true
2
+
3
+ require "htauth/algorithm"
4
+ require "bcrypt"
3
5
 
4
6
  module HTAuth
5
7
  # Internal: an implementation of the Bcrypt based encoding algorithm
6
8
  # as used in the apache htpasswd -B option
7
-
8
9
  class Bcrypt < Algorithm
9
-
10
10
  attr_accessor :cost
11
11
 
12
12
  DEFAULT_APACHE_COST = 5 # this is the default cost from htpasswd
13
13
 
14
14
  def self.handles?(password_entry)
15
- return ::BCrypt::Password.valid_hash?(password_entry)
15
+ ::BCrypt::Password.valid_hash?(password_entry)
16
16
  end
17
17
 
18
18
  def self.extract_cost_from_existing_password_field(existing)
@@ -21,15 +21,16 @@ module HTAuth
21
21
  end
22
22
 
23
23
  def initialize(params = {})
24
- if existing = (params['existing'] || params[:existing]) then
25
- @cost = self.class.extract_cost_from_existing_password_field(existing)
26
- else
27
- @cost = params['cost'] || params[:cost] || DEFAULT_APACHE_COST
28
- end
24
+ super()
25
+ @cost = if (existing = params["existing"] || params[:existing])
26
+ self.class.extract_cost_from_existing_password_field(existing)
27
+ else
28
+ params["cost"] || params[:cost] || DEFAULT_APACHE_COST
29
+ end
29
30
  end
30
31
 
31
32
  def encode(password)
32
- ::BCrypt::Password.create(password, :cost => cost)
33
+ ::BCrypt::Password.create(password, cost: cost)
33
34
  end
34
35
 
35
36
  def verify_password?(password, digest)
@@ -1,13 +1,14 @@
1
- require 'htauth/cli'
1
+ # frozen_string_literal: true
2
2
 
3
- require 'ostruct'
4
- require 'optparse'
3
+ require "htauth/cli"
4
+
5
+ require "ostruct"
6
+ require "optparse"
5
7
 
6
8
  module HTAuth
7
9
  module CLI
8
10
  # Internal: Implemenation of the commandline htdigest-ruby
9
11
  class Digest
10
-
11
12
  MAX_PASSWD_LENGTH = 255
12
13
 
13
14
  attr_accessor :digest_file
@@ -19,7 +20,7 @@ module HTAuth
19
20
  end
20
21
 
21
22
  def options
22
- if @options.nil? then
23
+ if @options.nil?
23
24
  @options = ::OpenStruct.new
24
25
  @options.show_version = false
25
26
  @options.show_help = false
@@ -33,24 +34,22 @@ module HTAuth
33
34
  end
34
35
 
35
36
  def option_parser
36
- if not @option_parser then
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
53
- 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
54
53
  end
55
54
  end
56
55
  @option_parser
@@ -67,27 +66,25 @@ module HTAuth
67
66
  end
68
67
 
69
68
  def parse_options(argv)
70
- begin
71
- option_parser.parse!(argv)
72
- show_version if options.show_version
73
- show_help if options.show_help or argv.size < 3
74
-
75
- options.passwdfile = argv.shift
76
- options.realm = argv.shift
77
- options.username = argv.shift
78
- rescue ::OptionParser::ParseError => pe
79
- $stderr.puts "ERROR: #{option_parser.program_name} - #{pe}"
80
- $stderr.puts "Try `#{option_parser.program_name} --help` for more information"
81
- exit 1
82
- 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
83
80
  end
84
81
 
85
- def run(argv, env = ENV)
82
+ def run(argv, _env = ENV)
86
83
  begin
87
84
  parse_options(argv)
88
85
  digest_file = DigestFile.new(options.passwdfile, options.file_mode)
89
86
 
90
- if options.delete_entry then
87
+ if options.delete_entry
91
88
  digest_file.delete(options.username, options.realm)
92
89
  else
93
90
  console = Console.new
@@ -106,18 +103,17 @@ module HTAuth
106
103
  end
107
104
 
108
105
  digest_file.save!
109
-
110
- rescue HTAuth::FileAccessError => fae
106
+ rescue HTAuth::FileAccessError => e
111
107
  msg = "Could not open password file #{options.passwdfile} "
112
- $stderr.puts "#{msg}: #{fae.message}"
113
- $stderr.puts fae.backtrace.join("\n")
108
+ warn "#{msg}: #{e.message}"
109
+ warn e.backtrace.join("\n")
114
110
  exit 1
115
- rescue HTAuth::Error => pe
116
- $stderr.puts "#{pe.message}"
111
+ rescue HTAuth::Error => e
112
+ warn e.message
117
113
  exit 1
118
- rescue SignalException => se
114
+ rescue SignalException => e
119
115
  $stderr.puts
120
- $stderr.puts "Interrupted #{se}"
116
+ warn "Interrupted #{e}"
121
117
  exit 1
122
118
  end
123
119
  exit 0