legion-crypt 1.2.0 → 1.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8dc8ac30453ea23fbdd8f8b2a11b0168fcd1d5d2d1bb8cfd289f96bd6fdc2620
4
- data.tar.gz: fa52ef3ddeb5da0f0ea151c178612832f46da404fd1c5c145dcc86f53570250c
3
+ metadata.gz: 3bf2e0f0673b2c963e56d71c586d299a39c3711b0d3f49fe851375d78cebe07e
4
+ data.tar.gz: 194d4c8b64922f5634dcf75607af87a0d83ba10efcb1c83421456bf7a3fddfc6
5
5
  SHA512:
6
- metadata.gz: a538b27d572615fc9a14dcb026b8641a4459438c24e689584166a82c97fd234ea19d5d55600b60c0e7c5eb688cb8c28838b1c1b30bb275691a124544ce93ea50
7
- data.tar.gz: 1cfd861ed4f57d538dc25640e69178cfa638c1e529dab1b24402b202173488f42447fb3553e08516593b64ff7f39be6bfdf1f944683d7a2a5c22f3d59f7692a4
6
+ metadata.gz: 33e4ea2d0ca6413f24099181f5ccf3b61ced2c33f079dd11029ded41095ceaedaf419b315e097ede586560e5478cec5be946dbe627d0ab68763c5354baa3617f
7
+ data.tar.gz: 8985763ca6ee45362527ec0368175125ed95d6001dc4d0f43759017fe1c7de33f7c194be7501e8c9c19a12fe72ac3fa1ce2aca5e6c5fde8d39c2bc76999ec925
@@ -0,0 +1,16 @@
1
+ name: CI
2
+ on:
3
+ push:
4
+ branches: [main]
5
+ pull_request:
6
+
7
+ jobs:
8
+ ci:
9
+ uses: LegionIO/.github/.github/workflows/ci.yml@main
10
+
11
+ release:
12
+ needs: ci
13
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
14
+ uses: LegionIO/.github/.github/workflows/release.yml@main
15
+ secrets:
16
+ rubygems-api-key: ${{ secrets.RUBYGEMS_API_KEY }}
data/.rubocop.yml CHANGED
@@ -1,26 +1,53 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.4
3
+ NewCops: enable
4
+ SuggestExtensions: false
5
+
1
6
  Layout/LineLength:
2
- Max: 140
7
+ Max: 160
8
+
9
+ Layout/SpaceAroundEqualsInParameterDefault:
10
+ EnforcedStyle: space
11
+
12
+ Layout/HashAlignment:
13
+ EnforcedHashRocketStyle: table
14
+ EnforcedColonStyle: table
15
+
3
16
  Metrics/MethodLength:
4
17
  Max: 50
18
+
5
19
  Metrics/ClassLength:
6
20
  Max: 1500
21
+
22
+ Metrics/ModuleLength:
23
+ Max: 1500
24
+
7
25
  Metrics/BlockLength:
8
- Max: 50
9
- Metrics/CyclomaticComplexity:
10
- Max: 14
26
+ Max: 40
27
+ Exclude:
28
+ - 'spec/**/*'
29
+
11
30
  Metrics/AbcSize:
12
- Max: 17
31
+ Max: 60
32
+
33
+ Metrics/CyclomaticComplexity:
34
+ Max: 15
35
+
13
36
  Metrics/PerceivedComplexity:
14
- Max: 16
15
- Naming/MethodParameterName:
16
- Enabled: false
37
+ Max: 17
38
+
17
39
  Style/Documentation:
18
40
  Enabled: false
19
- AllCops:
20
- TargetRubyVersion: 2.6
21
- NewCops: enable
22
- SuggestExtensions: false
41
+
42
+ Style/SymbolArray:
43
+ Enabled: true
44
+
23
45
  Style/FrozenStringLiteralComment:
46
+ Enabled: true
47
+ EnforcedStyle: always
48
+
49
+ Naming/FileName:
50
+ Enabled: false
51
+
52
+ Naming/PredicateMethod:
24
53
  Enabled: false
25
- Gemspec/RequiredRubyVersion:
26
- Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,4 +1,40 @@
1
1
  # Legion::Crypt
2
2
 
3
+ ## [Unreleased]
4
+
5
+ ## [1.4.0] - 2026-03-16
6
+
7
+ ### Added
8
+ - `JwksClient` module: fetch, parse, and cache public keys from JWKS endpoints (TTL 3600s, thread-safe)
9
+ - `JWT.verify_with_jwks` for RS256 token verification against external identity providers (Entra ID, Bot Framework)
10
+ - Multi-issuer support via `issuers:` array parameter
11
+ - Audience validation via `audience:` parameter
12
+ - `Crypt.verify_external_token` convenience method
13
+
14
+ ## [1.3.0] - 2026-03-16
15
+
16
+ ### Added
17
+ - `LeaseManager` singleton for dynamic Vault secret lease management
18
+ - Named lease definitions in `crypt.vault.leases` settings
19
+ - Boot-time lease fetch with data caching
20
+ - Background renewal thread with rotation detection
21
+ - Settings push-back on credential rotation via reverse index
22
+ - `lease://name#key` URI references resolved by Settings resolver
23
+
24
+ ## v1.2.1
25
+
26
+ ### Fixed
27
+ - `validate_hex` and `set_cluster_secret` now handle leading zeros correctly by padding the
28
+ base-32 round-trip result back to the original string length. Previously, secrets whose
29
+ hex representation started with one or more zero bytes would fail validation and cause
30
+ `find_cluster_secret` to return nil non-deterministically.
31
+
32
+ ### Added
33
+ - Comprehensive spec coverage for `Legion::Crypt::VaultJwtAuth` (`.login`, `.login!`,
34
+ `.worker_login`, `AuthError`, constants).
35
+ - `after` hook in `cluster_secret_spec` to restore `Legion::Settings[:crypt][:cluster_secret]`
36
+ between examples, eliminating ordering-dependent state pollution.
37
+ - TODO comments in `vault_spec` for tests that require live Vault connectivity.
38
+
3
39
  ## v1.2.0
4
- Moving from BitBucket to GitHub inside the Optum org. All git history is reset from this point on
40
+ Moving from BitBucket to GitHub. All git history is reset from this point on
data/CLAUDE.md ADDED
@@ -0,0 +1,149 @@
1
+ # legion-crypt: Encryption and Vault Integration for LegionIO
2
+
3
+ **Repository Level 3 Documentation**
4
+ - **Parent**: `/Users/miverso2/rubymine/legion/CLAUDE.md`
5
+
6
+ ## Purpose
7
+
8
+ Handles encryption, decryption, secrets management, JWT token management, and HashiCorp Vault connectivity for the LegionIO framework. Provides AES-256-CBC message encryption, RSA key pair generation, cluster secret management, JWT issue/verify operations, and Vault token lifecycle management.
9
+
10
+ **GitHub**: https://github.com/LegionIO/legion-crypt
11
+ **License**: Apache-2.0
12
+
13
+ ## Architecture
14
+
15
+ ```
16
+ Legion::Crypt (singleton module)
17
+ ├── .start # Initialize: generate keys, connect to Vault
18
+ ├── .encrypt(string) # AES-256-CBC encryption
19
+ ├── .decrypt(message) # AES-256-CBC decryption
20
+ ├── .shutdown # Stop Vault renewer, close sessions
21
+
22
+ ├── Cipher # OpenSSL cipher operations (AES-256-CBC)
23
+ │ ├── .encrypt # Encrypt with cluster secret
24
+ │ ├── .decrypt # Decrypt with cluster secret
25
+ │ ├── .private_key # RSA private key (generated or loaded)
26
+ │ └── .public_key # RSA public key
27
+
28
+ ├── Vault # HashiCorp Vault integration
29
+ │ ├── .connect_vault # Establish Vault session
30
+ │ ├── .read(path) # Read secret from Vault
31
+ │ ├── .write(path) # Write secret to Vault
32
+ │ └── .renew_token # Token renewal
33
+
34
+ ├── JWT # JSON Web Token operations
35
+ │ ├── .issue # Create signed JWT (HS256 or RS256)
36
+ │ ├── .verify # Verify and decode JWT
37
+ │ └── .decode # Decode without verification (inspection)
38
+
39
+ ├── ClusterSecret # Cluster-wide shared secret management
40
+ │ └── .cs # Generate/distribute cluster secret
41
+
42
+ ├── VaultJwtAuth # Vault JWT auth backend integration
43
+ │ ├── .login # Authenticate to Vault using a JWT token, returns Vault token hash
44
+ │ ├── .login! # Authenticate and set ::Vault.token for subsequent operations
45
+ │ └── .worker_login # Issue a Legion JWT and authenticate to Vault in one step
46
+
47
+ ├── VaultRenewer # Background Vault token renewal thread
48
+ ├── LeaseManager # Dynamic Vault lease lifecycle: fetch, cache, renew, rotate, push-back
49
+ ├── Settings # Default crypt config
50
+ └── Version
51
+ ```
52
+
53
+ ### Key Design Patterns
54
+
55
+ - **Dynamic Keys**: By default, generates new RSA key pair per process start (no persistent keys)
56
+ - **Cluster Secret**: Shared AES key distributed across Legion nodes for inter-node encrypted communication
57
+ - **Vault Conditional**: Vault module is only included if the `vault` gem is available
58
+ - **Token Lifecycle**: VaultRenewer runs background thread for automatic token renewal
59
+ - **JWT Dual Algorithm**: HS256 (symmetric, cluster secret) for intra-cluster tokens; RS256 (asymmetric, RSA keypair) for tokens verifiable without sharing the signing key
60
+
61
+ ## Default Settings
62
+
63
+ ```json
64
+ {
65
+ "vault": { "..." : "see vault settings" },
66
+ "jwt": {
67
+ "enabled": true,
68
+ "default_algorithm": "HS256",
69
+ "default_ttl": 3600,
70
+ "issuer": "legion",
71
+ "verify_expiration": true,
72
+ "verify_issuer": true
73
+ },
74
+ "cs_encrypt_ready": false,
75
+ "dynamic_keys": true,
76
+ "cluster_secret": null,
77
+ "save_private_key": true,
78
+ "read_private_key": true
79
+ }
80
+ ```
81
+
82
+ ## Dependencies
83
+
84
+ | Gem | Purpose |
85
+ |-----|---------|
86
+ | `jwt` (>= 2.7) | JSON Web Token encoding/decoding |
87
+ | `vault` (>= 0.17) | HashiCorp Vault Ruby client |
88
+
89
+ Dev dependencies: `legion-logging`, `legion-settings`
90
+
91
+ ## File Map
92
+
93
+ | Path | Purpose |
94
+ |------|---------|
95
+ | `lib/legion/crypt.rb` | Module entry, start/shutdown lifecycle |
96
+ | `lib/legion/crypt/cipher.rb` | AES-256-CBC encrypt/decrypt, RSA key generation |
97
+ | `lib/legion/crypt/jwt.rb` | JWT issue/verify/decode operations |
98
+ | `lib/legion/crypt/vault.rb` | Vault read/write/connect/renew operations |
99
+ | `lib/legion/crypt/cluster_secret.rb` | Cluster-wide shared secret management |
100
+ | `lib/legion/crypt/vault_jwt_auth.rb` | Vault JWT auth backend: `.login`, `.login!`, `.worker_login`; raises `AuthError` on failure |
101
+ | `lib/legion/crypt/vault_renewer.rb` | Background Vault token renewal |
102
+ | `lib/legion/crypt/lease_manager.rb` | Dynamic Vault lease lifecycle management |
103
+ | `lib/legion/crypt/settings.rb` | Default configuration |
104
+ | `lib/legion/crypt/version.rb` | VERSION constant |
105
+
106
+ ## Role in LegionIO
107
+
108
+ First service-level module initialized during `Legion::Service` startup (before transport). Provides:
109
+ 1. Vault token for `legion-transport` to fetch RabbitMQ credentials
110
+ 2. Message encryption for `legion-transport` (optional `transport.messages.encrypt`)
111
+ 3. Cluster secret for inter-node encrypted communication
112
+ 4. JWT tokens for node authentication and task authorization
113
+
114
+ ### Vault JWT Auth Usage
115
+
116
+ ```ruby
117
+ # Authenticate to Vault using a JWT (Vault must have JWT auth method enabled)
118
+ result = Legion::Crypt::VaultJwtAuth.login(jwt: token, role: 'legion-worker')
119
+ # => { token: '...', lease_duration: 3600, renewable: true, policies: [...], metadata: {} }
120
+
121
+ # Authenticate and set Vault client token in one step
122
+ Legion::Crypt::VaultJwtAuth.login!(jwt: token)
123
+
124
+ # Issue a Legion JWT and use it to authenticate to Vault (convenience for workers)
125
+ result = Legion::Crypt::VaultJwtAuth.worker_login(worker_id: 'abc', owner_msid: 'user@example.com')
126
+ ```
127
+
128
+ Vault prerequisites: `vault auth enable jwt` + configure `auth/jwt/config` with JWKS URL or bound issuer.
129
+
130
+ ### JWT Usage
131
+
132
+ ```ruby
133
+ # Convenience methods (auto-selects keys from settings)
134
+ token = Legion::Crypt.issue_token({ node_id: 'abc' }, ttl: 3600)
135
+ claims = Legion::Crypt.verify_token(token)
136
+
137
+ # Direct module usage (explicit keys)
138
+ token = Legion::Crypt::JWT.issue(payload, signing_key: key, algorithm: 'RS256')
139
+ claims = Legion::Crypt::JWT.verify(token, verification_key: pub_key, algorithm: 'RS256')
140
+ decoded = Legion::Crypt::JWT.decode(token) # no verification, inspection only
141
+ ```
142
+
143
+ **Algorithms:**
144
+ - `HS256` (default): Uses cluster secret. All cluster nodes can issue and verify.
145
+ - `RS256`: Uses RSA keypair. Only the issuing node can sign; anyone with the public key can verify.
146
+
147
+ ---
148
+
149
+ **Maintained By**: Matthew Iverson (@Esity)
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gemspec
@@ -8,3 +10,5 @@ group :test do
8
10
  gem 'rubocop'
9
11
  gem 'simplecov'
10
12
  end
13
+ gem 'legion-logging'
14
+ gem 'legion-settings'
data/LICENSE CHANGED
@@ -1,6 +1,7 @@
1
+
1
2
  Apache License
2
3
  Version 2.0, January 2004
3
- http://www.apache.org/licenses/
4
+ https://www.apache.org/licenses/
4
5
 
5
6
  TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7
 
@@ -175,27 +176,16 @@
175
176
 
176
177
  END OF TERMS AND CONDITIONS
177
178
 
178
- APPENDIX: How to apply the Apache License to your work.
179
-
180
- To apply the Apache License to your work, attach the following
181
- boilerplate notice, with the fields enclosed by brackets "[]"
182
- replaced with your own identifying information. (Don't include
183
- the brackets!) The text should be enclosed in the appropriate
184
- comment syntax for the file format. We also recommend that a
185
- file or class name and description of purpose be included on the
186
- same "printed page" as the copyright notice for easier
187
- identification within third-party archives.
188
-
189
- Copyright 2021 Optum
179
+ Copyright 2021 Esity
190
180
 
191
181
  Licensed under the Apache License, Version 2.0 (the "License");
192
182
  you may not use this file except in compliance with the License.
193
183
  You may obtain a copy of the License at
194
184
 
195
- http://www.apache.org/licenses/LICENSE-2.0
185
+ https://www.apache.org/licenses/LICENSE-2.0
196
186
 
197
187
  Unless required by applicable law or agreed to in writing, software
198
188
  distributed under the License is distributed on an "AS IS" BASIS,
199
189
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
190
  See the License for the specific language governing permissions and
201
- limitations under the License.
191
+ limitations under the License.
data/README.md CHANGED
@@ -1,26 +1,21 @@
1
- Legion::Crypt
2
- =====
1
+ # legion-crypt
3
2
 
4
- Legion::Crypt is the class responsible for encryption, managing secrets and connecting with Vault
3
+ Encryption, secrets management, JWT token management, and HashiCorp Vault integration for the [LegionIO](https://github.com/LegionIO/LegionIO) framework. Provides AES-256-CBC message encryption, RSA key pair generation, cluster secret management, JWT issue/verify operations, and Vault token lifecycle management.
5
4
 
6
- Supported Ruby versions and implementations
7
- ------------------------------------------------
8
-
9
- Legion::Crypt should work identically on:
10
-
11
- * JRuby 9.2+
12
- * Ruby 2.4+
13
-
14
-
15
- Installation and Usage
16
- ------------------------
17
-
18
- You can verify your installation using this piece of code:
5
+ ## Installation
19
6
 
20
7
  ```bash
21
8
  gem install legion-crypt
22
9
  ```
23
10
 
11
+ Or add to your Gemfile:
12
+
13
+ ```ruby
14
+ gem 'legion-crypt'
15
+ ```
16
+
17
+ ## Usage
18
+
24
19
  ```ruby
25
20
  require 'legion/crypt'
26
21
 
@@ -29,8 +24,24 @@ Legion::Crypt.encrypt('this is my string')
29
24
  Legion::Crypt.decrypt(message)
30
25
  ```
31
26
 
32
- Settings
33
- ----------
27
+ ### JWT Tokens
28
+
29
+ ```ruby
30
+ # Issue a token (defaults to HS256 using cluster secret)
31
+ token = Legion::Crypt.issue_token({ node_id: 'abc' }, ttl: 3600)
32
+
33
+ # Verify and decode a token
34
+ claims = Legion::Crypt.verify_token(token)
35
+
36
+ # Use RS256 (RSA keypair) instead
37
+ token = Legion::Crypt.issue_token({ node_id: 'abc' }, algorithm: 'RS256')
38
+ claims = Legion::Crypt.verify_token(token, algorithm: 'RS256')
39
+
40
+ # Inspect a token without verification
41
+ decoded = Legion::Crypt::JWT.decode(token)
42
+ ```
43
+
44
+ ## Configuration
34
45
 
35
46
  ```json
36
47
  {
@@ -40,17 +51,89 @@ Settings
40
51
  "address": "localhost",
41
52
  "port": 8200,
42
53
  "token": null,
43
- "connected": false
54
+ "connected": false,
55
+ "renewer_time": 5,
56
+ "renewer": true,
57
+ "push_cluster_secret": true,
58
+ "read_cluster_secret": true,
59
+ "kv_path": "legion",
60
+ "leases": {}
61
+ },
62
+ "jwt": {
63
+ "enabled": true,
64
+ "default_algorithm": "HS256",
65
+ "default_ttl": 3600,
66
+ "issuer": "legion",
67
+ "verify_expiration": true,
68
+ "verify_issuer": true
44
69
  },
45
70
  "cs_encrypt_ready": false,
46
71
  "dynamic_keys": true,
47
72
  "cluster_secret": null,
48
- "save_private_key": false,
49
- "read_private_key": false
73
+ "save_private_key": true,
74
+ "read_private_key": true
75
+ }
76
+ ```
77
+
78
+ ### JWT Algorithms
79
+
80
+ | Algorithm | Key | Use Case |
81
+ |-----------|-----|----------|
82
+ | `HS256` (default) | Cluster secret (symmetric) | Intra-cluster tokens — all nodes can issue and verify |
83
+ | `RS256` | RSA key pair (asymmetric) | Tokens verifiable by external services without sharing the signing key |
84
+
85
+ ### Vault Integration
86
+
87
+ When `vault.token` is set (or via `VAULT_TOKEN_ID` env var), Crypt connects to Vault on `start`. The background `VaultRenewer` thread keeps the token alive. Vault is an optional runtime dependency — the Vault module is only included if the `vault` gem is available.
88
+
89
+ ### Dynamic Vault Leases
90
+
91
+ The `LeaseManager` handles dynamic secrets from any Vault secrets engine (database, RabbitMQ, AWS, PKI, etc.). Define named leases in crypt settings — each lease maps a stable name to a Vault path:
92
+
93
+ ```json
94
+ {
95
+ "crypt": {
96
+ "vault": {
97
+ "leases": {
98
+ "rabbitmq": { "path": "rabbitmq/creds/legion-role" },
99
+ "bedrock": { "path": "aws/creds/bedrock-role" },
100
+ "postgres": { "path": "database/creds/apollo-rw" }
101
+ }
102
+ }
103
+ }
104
+ }
105
+ ```
106
+
107
+ Other settings files reference lease data using `lease://name#key`:
108
+
109
+ ```json
110
+ {
111
+ "transport": {
112
+ "connection": {
113
+ "username": "lease://rabbitmq#username",
114
+ "password": "lease://rabbitmq#password"
115
+ }
116
+ }
50
117
  }
51
118
  ```
52
119
 
53
- Authors
54
- ----------
120
+ Both `username` and `password` come from a single Vault read — one lease, one credential pair. The `LeaseManager`:
121
+
122
+ - Fetches all leases at boot (during `Crypt.start`, before `resolve_secrets!`)
123
+ - Caches response data and lease metadata
124
+ - Renews leases in the background at 50% TTL
125
+ - Detects credential rotation and pushes new values into `Legion::Settings` in-place
126
+ - Revokes all leases on `Crypt.shutdown`
127
+
128
+ Lease names are stable across environments. The actual Vault paths are deployment-specific config.
129
+
130
+ ## Requirements
131
+
132
+ - Ruby >= 3.4
133
+ - `jwt` gem (>= 2.7)
134
+ - `vault` gem (>= 0.17, optional)
135
+ - HashiCorp Vault (optional, for secrets management)
136
+
137
+ ## License
55
138
 
56
- * [Matthew Iverson](https://github.com/Esity) - current maintainer
139
+ Apache-2.0
data/legion-crypt.gemspec CHANGED
@@ -6,27 +6,25 @@ Gem::Specification.new do |spec|
6
6
  spec.name = 'legion-crypt'
7
7
  spec.version = Legion::Crypt::VERSION
8
8
  spec.authors = ['Esity']
9
- spec.email = %w[matthewdiverson@gmail.com ruby@optum.com]
9
+ spec.email = ['matthewdiverson@gmail.com']
10
10
  spec.summary = 'Handles requests for encrypt, decrypting, connecting to Vault, among other things'
11
11
  spec.description = 'A gem used by the LegionIO framework for encryption'
12
- spec.homepage = 'https://github.com/Optum/legion-crypt'
12
+ spec.homepage = 'https://github.com/LegionIO/legion-crypt'
13
13
  spec.license = 'Apache-2.0'
14
14
  spec.require_paths = ['lib']
15
- spec.required_ruby_version = '>= 2.4'
15
+ spec.required_ruby_version = '>= 3.4'
16
16
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
- spec.test_files = spec.files.select { |p| p =~ %r{^test/.*_test.rb} }
18
- spec.extra_rdoc_files = %w[README.md LICENSE CHANGELOG.md]
17
+ spec.extra_rdoc_files = %w[README.md LICENSE CHANGELOG.md]
19
18
  spec.metadata = {
20
- 'bug_tracker_uri' => 'https://github.com/Optum/legion-crypt/issues',
21
- 'changelog_uri' => 'https://github.com/Optum/legion-crypt/src/main/CHANGELOG.md',
22
- 'documentation_uri' => 'https://github.com/Optum/legion-crypt',
23
- 'homepage_uri' => 'https://github.com/Optum/LegionIO',
24
- 'source_code_uri' => 'https://github.com/Optum/legion-crypt',
25
- 'wiki_uri' => 'https://github.com/Optum/legion-crypt/wiki'
19
+ 'bug_tracker_uri' => 'https://github.com/LegionIO/legion-crypt/issues',
20
+ 'changelog_uri' => 'https://github.com/LegionIO/legion-crypt/blob/main/CHANGELOG.md',
21
+ 'documentation_uri' => 'https://github.com/LegionIO/legion-crypt',
22
+ 'homepage_uri' => 'https://github.com/LegionIO/LegionIO',
23
+ 'source_code_uri' => 'https://github.com/LegionIO/legion-crypt',
24
+ 'wiki_uri' => 'https://github.com/LegionIO/legion-crypt/wiki',
25
+ 'rubygems_mfa_required' => 'true'
26
26
  }
27
27
 
28
- spec.add_dependency 'vault', '>= 0.15.0'
29
-
30
- spec.add_development_dependency 'legion-logging'
31
- spec.add_development_dependency 'legion-settings'
28
+ spec.add_dependency 'jwt', '>= 2.7'
29
+ spec.add_dependency 'vault', '>= 0.17'
32
30
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'securerandom'
2
4
  require 'legion/crypt/cluster_secret'
3
5
 
@@ -14,7 +16,7 @@ module Legion
14
16
  { enciphered_message: Base64.encode64(cipher.update(message) + cipher.final), iv: Base64.encode64(iv) }
15
17
  end
16
18
 
17
- def decrypt(message, iv)
19
+ def decrypt(message, init_vector)
18
20
  until cs.is_a?(String) || Legion::Settings[:client][:shutting_down]
19
21
  Legion::Logging.debug('sleeping Legion::Crypt.decrypt due to CS not being set')
20
22
  sleep(0.5)
@@ -23,7 +25,7 @@ module Legion
23
25
  decipher = OpenSSL::Cipher.new('aes-256-cbc')
24
26
  decipher.decrypt
25
27
  decipher.key = cs
26
- decipher.iv = Base64.decode64(iv)
28
+ decipher.iv = Base64.decode64(init_vector)
27
29
  message = Base64.decode64(message)
28
30
  decipher.update(message) + decipher.final
29
31
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'securerandom'
2
4
 
3
5
  module Legion
@@ -39,7 +41,7 @@ module Legion
39
41
  end
40
42
  alias cluster_secret from_settings
41
43
 
42
- def from_transport # rubocop:disable Metrics/AbcSize
44
+ def from_transport
43
45
  return nil unless Legion::Settings[:transport][:connected]
44
46
 
45
47
  require 'legion/transport/messages/request_cluster_secret'
@@ -55,10 +57,11 @@ module Legion
55
57
 
56
58
  unless from_settings.nil?
57
59
  Legion::Logging.info "Received cluster secret in #{((Time.new - start) * 1000.0).round}ms"
58
- from_settings
60
+ return from_settings
59
61
  end
60
62
 
61
63
  Legion::Logging.error 'Cluster secret is still unknown!'
64
+ nil
62
65
  rescue StandardError => e
63
66
  Legion::Logging.error e.message
64
67
  Legion::Logging.error e.backtrace[0..10]
@@ -79,7 +82,7 @@ module Legion
79
82
  end
80
83
 
81
84
  def set_cluster_secret(value, push_to_vault = true) # rubocop:disable Style/OptionalBooleanParameter
82
- raise TypeError unless value.to_i(32).to_s(32) == value.downcase
85
+ raise TypeError unless value.to_i(32).to_s(32).rjust(value.length, '0') == value.downcase
83
86
 
84
87
  Legion::Settings[:crypt][:cs_encrypt_ready] = true
85
88
  push_cs_to_vault if push_to_vault && settings_push_vault
@@ -114,7 +117,10 @@ module Legion
114
117
  end
115
118
 
116
119
  def validate_hex(value, length = secret_length)
117
- value.to_i(length).to_s(length) == value.downcase
120
+ return false unless value.is_a?(String)
121
+ return false if value.empty?
122
+
123
+ value.to_i(length).to_s(length).rjust(value.length, '0') == value.downcase
118
124
  end
119
125
  end
120
126
  end