manageiq-password 1.0.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9a506e65c484778a8b89cc16300e5145922de810e612499fe5046015e8668915
4
- data.tar.gz: 5322663567882ef7b24f4275d9a6f21e1d967bd086de0afe64dcdf45d67e868d
3
+ metadata.gz: e2afb4581105b776ca6285b4324b2e228774c2f4f6ef0bb19c1947a56fa481ea
4
+ data.tar.gz: 53e56209872207f7e03656b95a0973000404bbcf79bc3d84690742481503a6e6
5
5
  SHA512:
6
- metadata.gz: 3ea27faaef7f610f5f07f67e19c1b27739c43f418f9662cfbf558d6a05168f0002b8697a1ec782b540b29b99e67a9d25996b03e1ad5cf9044d3644b5b3aaa9cb
7
- data.tar.gz: 4b5e896206731cdd5895b1a90165c69af0bbdd789bf86509e2d4e1568a7a3437b794e043094a9183d09612717a67b278b5d32733523e3652698abcb637dd5ad0
6
+ metadata.gz: 919c5faa8a027cb296296c37a93fdd684a19614dc733aae01d11852ffef98f5d56ae91c4600b5f412fea42d23bdb30273a9858ddedc497a899310adca4959475
7
+ data.tar.gz: '0383c3dc4e538f1928c2f485786e8b1e12409d0a6f3726b013bed1c3b2907791db70d16d1c146cd38635ebe6b8e08235d384c752cd48b5a26bae2741d6652c47'
@@ -0,0 +1,33 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+ schedule:
7
+ - cron: '0 0 * * 0'
8
+
9
+ jobs:
10
+ ci:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ ruby-version:
15
+ - '2.7'
16
+ - '3.0'
17
+ - '3.1'
18
+ env:
19
+ CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - name: Set up Ruby
23
+ uses: ruby/setup-ruby@v1
24
+ with:
25
+ ruby-version: ${{ matrix.ruby-version }}
26
+ bundler-cache: true
27
+ timeout-minutes: 30
28
+ - name: Run tests
29
+ run: bundle exec rake
30
+ - name: Report code coverage
31
+ if: ${{ github.ref == 'refs/heads/master' && matrix.ruby-version == '3.0' }}
32
+ continue-on-error: true
33
+ uses: paambaati/codeclimate-action@v5
data/.rspec CHANGED
@@ -1,3 +1,3 @@
1
- --format progress
2
- --color
3
1
  --require spec_helper
2
+ --color
3
+ --order random
data/.whitesource ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "settingsInheritedFrom": "ManageIQ/whitesource-config@master"
3
+ }
data/CHANGELOG.md CHANGED
@@ -4,6 +4,25 @@ This project adheres to [Semantic Versioning](http://semver.org/).
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [1.2.0] - 2023-10-12
8
+ ### Added
9
+ - Add Ruby 3.1 support including ruby 3.1's psych 4 default of safe_load [[#37](https://github.com/ManageIQ/manageiq-password/pull/37)]
10
+
11
+ ### Changed
12
+ - Change .to_s to use a regular attr_reader [[#34](https://github.com/ManageIQ/manageiq-password/pull/34)]
13
+
14
+ ### Removed
15
+ - Removed support for Ruby 2.5 and 2.6 [[#37](https://github.com/ManageIQ/manageiq-password/pull/37)]
16
+
17
+ ## [1.1.0] - 2021-11-08
18
+ ### Added
19
+ - Add manageiq-password CLI [[#23](https://github.com/ManageIQ/manageiq-password/pull/23)]
20
+
21
+ ### Fixed
22
+ - chmod v2_key on creation [[#22](https://github.com/ManageIQ/manageiq-password/pull/22)]
23
+ - Raise an exception when decrypting plaintext [[#26](https://github.com/ManageIQ/manageiq-password/pull/26)]
24
+ - Fix encrypted? and try_decrypt to work with erb strings [[#28](https://github.com/ManageIQ/manageiq-password/pull/28)]
25
+
7
26
  ## [1.0.0] - 2021-05-05
8
27
  ### Removed
9
28
  - **BREAKING**: Drop support for legacy v0 and v1 keys [[#14](https://github.com/ManageIQ/manageiq-password/pull/14)]
@@ -13,5 +32,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
13
32
  key
14
33
  - **BREAKING**: Drop deprecated methods [[#16](https://github.com/ManageIQ/manageiq-password/pull/16)]
15
34
 
16
- [Unreleased]: https://github.com/ManageIQ/more_core_extensions/compare/v1.0.0...HEAD
17
- [1.0.0]: https://github.com/ManageIQ/more_core_extensions/compare/v1.0.0...v0.3.0
35
+ [Unreleased]: https://github.com/ManageIQ/manageiq-password/compare/v1.2.0...HEAD
36
+ [1.2.0]: https://github.com/ManageIQ/manageiq-password/compare/v1.1.0...v1.2.0
37
+ [1.1.0]: https://github.com/ManageIQ/manageiq-password/compare/v1.0.0...v1.1.0
38
+ [1.0.0]: https://github.com/ManageIQ/manageiq-password/compare/v0.3.0...v1.0.0
data/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # ManageIQ Password
2
2
 
3
- [![Build Status](https://travis-ci.com/ManageIQ/manageiq-password.svg)](https://travis-ci.com/ManageIQ/manageiq-password)
4
- [![Maintainability](https://api.codeclimate.com/v1/badges/85064711d083dea96636/maintainability)](https://codeclimate.com/github/ManageIQ/manageiq-password/maintainability)
5
- [![Test Coverage](https://api.codeclimate.com/v1/badges/85064711d083dea96636/test_coverage)](https://codeclimate.com/github/ManageIQ/manageiq-password/test_coverage)
3
+ [![Gem Version](https://badge.fury.io/rb/manageiq-password.svg)](http://badge.fury.io/rb/manageiq-password)
4
+ [![CI](https://github.com/ManageIQ/manageiq-password/actions/workflows/ci.yaml/badge.svg)](https://github.com/ManageIQ/manageiq-password/actions/workflows/ci.yaml)
5
+ [![Code Climate](https://codeclimate.com/github/ManageIQ/manageiq-password.svg)](https://codeclimate.com/github/ManageIQ/manageiq-password)
6
+ [![Test Coverage](https://codeclimate.com/github/ManageIQ/manageiq-password/badges/coverage.svg)](https://codeclimate.com/github/ManageIQ/manageiq-password/coverage)
6
7
 
7
8
  A simple encryption util for storing passwords in a database.
8
9
 
@@ -0,0 +1,100 @@
1
+ #!/bin/bash
2
+
3
+ while [[ "$#" -gt 0 ]]; do
4
+ case $1 in
5
+ -d|--decrypt)
6
+ mode="decrypt"
7
+ ;;
8
+ -e|--encrypt)
9
+ mode="encrypt"
10
+ ;;
11
+ -k|--key)
12
+ keyfile="$2"
13
+ shift
14
+ ;;
15
+ -h|--help|-?)
16
+ cat <<-EOS >&2
17
+ Usage: $(basename $0) [--encrypt|--decrypt] [--key KEYFILE]
18
+
19
+ Options:
20
+ -d, --decrypt Decrypt the value on STDIN (default mode)
21
+ -e, --encrypt Encrypt the value on STDIN
22
+ -k, --key Path to the key file (default: $(pwd)/certs/v2_key)
23
+
24
+ -h, --help, -? Display help
25
+ EOS
26
+ exit 0
27
+ ;;
28
+ *)
29
+ echo "ERROR: Unknown parameter passed: $1" >&2
30
+ exit 1
31
+ ;;
32
+ esac
33
+ shift
34
+ done
35
+
36
+ mode=${mode:-"decrypt"}
37
+ keyfile=${keyfile:-"$(pwd)/certs/v2_key"}
38
+
39
+ if [ ! -r "$keyfile" ]; then
40
+ echo "ERROR: Cannot read v2 key file: $keyfile" >&2
41
+ exit 1
42
+ fi
43
+
44
+ extractFromKeyfile() {
45
+ grep :$1: "$keyfile" | cut -d ' ' -f 2
46
+ }
47
+
48
+ extractAlgorithm() {
49
+ extractFromKeyfile "algorithm"
50
+ }
51
+
52
+ extractKey() {
53
+ extractFromKeyfile "key" | base64 -d | xxd -p -c256
54
+ }
55
+
56
+ extractIv() {
57
+ iv=$(extractFromKeyfile "iv" | base64 -d | xxd -p -c256)
58
+ echo -n "${iv:-"00000000000000000000000000000000"}"
59
+ }
60
+
61
+ algorithm=$(extractAlgorithm)
62
+ if [ "$algorithm" != "aes-256-cbc" ]; then
63
+ echo "ERROR: Invalid v2 key file: $keyfile" >&2
64
+ exit 1
65
+ fi
66
+
67
+ if [ -n "$DEBUG" ]; then
68
+ cat <<-EOS >&2
69
+ ==============================================================================
70
+ Mode: $mode
71
+ Key File: $keyfile
72
+ Algorithm: $algorithm
73
+ IV (Base64): $(extractFromKeyfile "iv")
74
+ IV (Hex): $(extractIv)
75
+ Key (Base64): $(extractFromKeyfile "key")
76
+ Key (Hex): $(extractKey)
77
+ ==============================================================================
78
+ EOS
79
+ fi
80
+
81
+ case $mode in
82
+ decrypt)
83
+ (
84
+ xargs -L1 echo | \
85
+ sed 's/^.\{4\}//;s/.$//' | \
86
+ openssl enc -d -base64 -$algorithm -iv "$(extractIv)" -K "$(extractKey)"
87
+ ) < /dev/stdin
88
+ ;;
89
+ encrypt)
90
+ (
91
+ xargs -L1 echo -n | \
92
+ openssl enc -base64 -$algorithm -iv "$(extractIv)" -K "$(extractKey)" | \
93
+ sed "s/^/v2:{/;s/$/}/" | \
94
+ xargs -L1 echo -n
95
+ ) < /dev/stdin
96
+ ;;
97
+ *)
98
+ echo "ERROR: Invalid mode: $mode" >&2
99
+ exit 1
100
+ esac
@@ -1,5 +1,5 @@
1
1
  module ManageIQ
2
2
  class Password
3
- VERSION = "1.0.0".freeze
3
+ VERSION = "1.2.0".freeze
4
4
  end
5
5
  end
@@ -22,15 +22,32 @@ module ManageIQ
22
22
  @encStr = encrypt(str)
23
23
  end
24
24
 
25
- def encrypt(str, key = self.class.key)
25
+ def encrypt(*args)
26
+ self.class.encrypt(*args)
27
+ end
28
+
29
+ def decrypt(*args)
30
+ self.class.decrypt(*args)
31
+ end
32
+
33
+ def recrypt(*args)
34
+ self.class.recrypt(*args)
35
+ end
36
+
37
+ def self.encrypt(str, key = self.key)
26
38
  return str if str.nil?
27
39
 
28
40
  enc = key.encrypt64(str).delete("\n") unless str.empty?
29
- self.class.wrap(enc)
41
+ wrap(enc)
30
42
  end
31
43
 
32
- def decrypt(str, key = self.class.key)
33
- enc = self.class.unwrap(str)
44
+ def self.decrypt(str, key = self.key)
45
+ str = remove_erb(str)
46
+ return str if str.nil? || str.empty?
47
+
48
+ raise PasswordError, "cannot decrypt plaintext string" unless wrapped?(str)
49
+
50
+ enc = unwrap(str)
34
51
  return enc if enc.nil? || enc.empty?
35
52
 
36
53
  begin
@@ -40,7 +57,7 @@ module ManageIQ
40
57
  end
41
58
  end
42
59
 
43
- def recrypt(str, prior_key = nil)
60
+ def self.recrypt(str, prior_key = nil)
44
61
  return str if str.nil?
45
62
 
46
63
  decrypted_str = decrypt(str, prior_key) if prior_key rescue nil
@@ -48,21 +65,8 @@ module ManageIQ
48
65
  encrypt(decrypted_str)
49
66
  end
50
67
 
51
- def self.encrypt(*args)
52
- new.encrypt(*args)
53
- end
54
-
55
- def self.decrypt(*args)
56
- new.decrypt(*args)
57
- end
58
-
59
- def self.recrypt(*args)
60
- new.recrypt(*args)
61
- end
62
-
63
68
  def self.encrypted?(str)
64
- return false if str.nil? || str.empty?
65
- !!unwrap(str)
69
+ wrapped?(remove_erb(str))
66
70
  end
67
71
 
68
72
  def self.md5crypt(str)
@@ -83,6 +87,7 @@ module ManageIQ
83
87
  end
84
88
 
85
89
  def self.try_decrypt(str)
90
+ str = remove_erb(str)
86
91
  encrypted?(str) ? decrypt(str) : str
87
92
  end
88
93
 
@@ -124,26 +129,27 @@ module ManageIQ
124
129
  Key.new.tap { |key| store_key_file(filename, key) if filename }
125
130
  end
126
131
 
127
- protected
128
-
129
- def self.wrap(encrypted_str)
132
+ private_class_method def self.wrap(encrypted_str)
130
133
  "v2:{#{encrypted_str}}"
131
134
  end
132
135
 
133
- def self.unwrap(str)
134
- _unwrap(str) || _unwrap(extract_erb_encrypted_value(str))
135
- end
136
-
137
- private_class_method def self._unwrap(str)
136
+ private_class_method def self.unwrap(str)
138
137
  return str if str.nil? || str.empty?
138
+
139
139
  str.match(REGEXP_START_LINE)&.public_send(:[], 1)
140
140
  end
141
141
 
142
- def self.store_key_file(filename, key)
143
- File.write(filename, key.to_h.to_yaml)
142
+ private_class_method def self.wrapped?(str)
143
+ return false if str.nil? || str.empty?
144
+
145
+ str.match?(REGEXP_START_LINE)
146
+ end
147
+
148
+ private_class_method def self.store_key_file(filename, key)
149
+ File.write(filename, key.to_h.to_yaml, :perm => 0440)
144
150
  end
145
151
 
146
- def self.load_key_file(filename)
152
+ private_class_method def self.load_key_file(filename)
147
153
  return filename if filename.respond_to?(:decrypt64)
148
154
 
149
155
  # if it is an absolute path, or relative to pwd, leave as is
@@ -151,11 +157,15 @@ module ManageIQ
151
157
  filename = File.expand_path(filename, key_root) unless File.exist?(filename)
152
158
  return nil unless File.exist?(filename)
153
159
 
154
- Key.new(*YAML.load_file(filename).values_at(:algorithm, :key, :iv))
160
+ # Switch to YAML.safe_load_file when we drop ruby 2.7. Psych 3.2.1 added it.
161
+ Key.new(*YAML.safe_load(File.read(filename), :permitted_classes => [Symbol, Time]).values_at(:algorithm, :key, :iv))
155
162
  end
156
163
 
157
- def self.extract_erb_encrypted_value(value)
158
- return $1 if value =~ /\A<%= (?:MiqPassword|DB_PASSWORD|ManageIQ::Password)\.decrypt\(['"]([^'"]+)['"]\) %>\Z/
164
+ private_class_method def self.remove_erb(str)
165
+ return str if str.nil? || str.empty? || !str.start_with?("<%=")
166
+
167
+ match = str.match(/\A<%= (?:MiqPassword|DB_PASSWORD|ManageIQ::Password)\.decrypt\(['"](.+?)['"]\) %>\Z/m)
168
+ match ? match[1] : str
159
169
  end
160
170
 
161
171
  class Key
@@ -166,6 +176,9 @@ module ManageIQ
166
176
  Base64.strict_encode64(Digest::SHA256.digest("#{password}#{salt}")[0, GENERATED_KEY_SIZE])
167
177
  end
168
178
 
179
+ attr_reader :key
180
+ alias to_s key
181
+
169
182
  def initialize(algorithm = nil, key = nil, iv = nil)
170
183
  @algorithm = algorithm || "aes-256-cbc"
171
184
  @key = key || generate_key
@@ -190,10 +203,6 @@ module ManageIQ
190
203
  decrypt(Base64.decode64(str))
191
204
  end
192
205
 
193
- def to_s
194
- @key
195
- end
196
-
197
206
  def to_h
198
207
  {
199
208
  :algorithm => @algorithm,
@@ -18,9 +18,10 @@ Gem::Specification.new do |spec|
18
18
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_development_dependency "awesome_spawn"
21
22
  spec.add_development_dependency "bundler"
22
23
  spec.add_development_dependency "manageiq-style"
23
24
  spec.add_development_dependency "rake", ">= 12.3.3"
24
25
  spec.add_development_dependency "rspec", "~> 3.0"
25
- spec.add_development_dependency "simplecov"
26
+ spec.add_development_dependency "simplecov", ">= 0.21.2"
26
27
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: manageiq-password
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ManageIQ Authors
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-06 00:00:00.000000000 Z
11
+ date: 2023-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: awesome_spawn
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -72,27 +86,29 @@ dependencies:
72
86
  requirements:
73
87
  - - ">="
74
88
  - !ruby/object:Gem::Version
75
- version: '0'
89
+ version: 0.21.2
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - ">="
81
95
  - !ruby/object:Gem::Version
82
- version: '0'
96
+ version: 0.21.2
83
97
  description:
84
98
  email:
85
- executables: []
99
+ executables:
100
+ - manageiq-password
86
101
  extensions: []
87
102
  extra_rdoc_files: []
88
103
  files:
89
104
  - ".codeclimate.yml"
105
+ - ".github/workflows/ci.yaml"
90
106
  - ".gitignore"
91
107
  - ".rspec"
92
108
  - ".rubocop.yml"
93
109
  - ".rubocop_cc.yml"
94
110
  - ".rubocop_local.yml"
95
- - ".travis.yml"
111
+ - ".whitesource"
96
112
  - CHANGELOG.md
97
113
  - CODE_OF_CONDUCT.md
98
114
  - Gemfile
@@ -101,6 +117,7 @@ files:
101
117
  - Rakefile
102
118
  - bin/console
103
119
  - bin/setup
120
+ - exe/manageiq-password
104
121
  - lib/manageiq-password.rb
105
122
  - lib/manageiq/password.rb
106
123
  - lib/manageiq/password/password_mixin.rb
@@ -128,7 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
128
145
  - !ruby/object:Gem::Version
129
146
  version: '0'
130
147
  requirements: []
131
- rubygems_version: 3.1.4
148
+ rubygems_version: 3.2.33
132
149
  signing_key:
133
150
  specification_version: 4
134
151
  summary: A simple encryption util for storing passwords in a database.
data/.travis.yml DELETED
@@ -1,13 +0,0 @@
1
- ---
2
- language: ruby
3
- cache: bundler
4
- rvm:
5
- - 2.6.7
6
- - 2.7.3
7
- - 3.0.1
8
- before_script:
9
- - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
10
- - chmod +x ./cc-test-reporter
11
- - "./cc-test-reporter before-build"
12
- after_script:
13
- - "./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT"