easy_crypt 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +248 -0
- data/lib/easy_crypt/exception.rb +17 -0
- data/lib/easy_crypt/secrets_provider/base.rb +65 -0
- data/lib/easy_crypt/secrets_provider/env_provider.rb +70 -0
- data/lib/easy_crypt/secrets_provider/rails_credentials_provider.rb +82 -0
- data/lib/easy_crypt/secrets_provider.rb +53 -0
- data/lib/easy_crypt/version.rb +5 -0
- data/lib/easy_crypt.rb +188 -0
- metadata +62 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a3936f18965419a36551cd0cc5b5e4d8acd6bdd3afe1ba39dc9879869fb1f649
|
4
|
+
data.tar.gz: 852d38340c89b75221b884eb9e12d2475f06e441e19abad17e9f5ca216a13024
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3b84dd63f38fe9b6802a5ca667f38800b346e8b52040147967872db726f2e4e23de37702259a5744fc421b1c228deab46757d7b8b8966af9e4724b8dd7c50007
|
7
|
+
data.tar.gz: d3769217d764e084b035785d6a7d7a1e52df286ad1de46a374d3ca115d36f1d1f110c6e75d040a5ed0dd196f5e7ee940b699578778ac927dce538e950070afac
|
data/CHANGELOG.md
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our
|
6
|
+
community a harassment-free experience for everyone, regardless of age, body
|
7
|
+
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
8
|
+
identity and expression, level of experience, education, socio-economic status,
|
9
|
+
nationality, personal appearance, race, caste, color, religion, or sexual
|
10
|
+
identity and orientation.
|
11
|
+
|
12
|
+
We pledge to act and interact in ways that contribute to an open, welcoming,
|
13
|
+
diverse, inclusive, and healthy community.
|
14
|
+
|
15
|
+
## Our Standards
|
16
|
+
|
17
|
+
Examples of behavior that contributes to a positive environment for our
|
18
|
+
community include:
|
19
|
+
|
20
|
+
* Demonstrating empathy and kindness toward other people
|
21
|
+
* Being respectful of differing opinions, viewpoints, and experiences
|
22
|
+
* Giving and gracefully accepting constructive feedback
|
23
|
+
* Accepting responsibility and apologizing to those affected by our mistakes,
|
24
|
+
and learning from the experience
|
25
|
+
* Focusing on what is best not just for us as individuals, but for the overall
|
26
|
+
community
|
27
|
+
|
28
|
+
Examples of unacceptable behavior include:
|
29
|
+
|
30
|
+
* The use of sexualized language or imagery, and sexual attention or advances of
|
31
|
+
any kind
|
32
|
+
* Trolling, insulting or derogatory comments, and personal or political attacks
|
33
|
+
* Public or private harassment
|
34
|
+
* Publishing others' private information, such as a physical or email address,
|
35
|
+
without their explicit permission
|
36
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
37
|
+
professional setting
|
38
|
+
|
39
|
+
## Enforcement Responsibilities
|
40
|
+
|
41
|
+
Community leaders are responsible for clarifying and enforcing our standards of
|
42
|
+
acceptable behavior and will take appropriate and fair corrective action in
|
43
|
+
response to any behavior that they deem inappropriate, threatening, offensive,
|
44
|
+
or harmful.
|
45
|
+
|
46
|
+
Community leaders have the right and responsibility to remove, edit, or reject
|
47
|
+
comments, commits, code, wiki edits, issues, and other contributions that are
|
48
|
+
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
49
|
+
decisions when appropriate.
|
50
|
+
|
51
|
+
## Scope
|
52
|
+
|
53
|
+
This Code of Conduct applies within all community spaces, and also applies when
|
54
|
+
an individual is officially representing the community in public spaces.
|
55
|
+
Examples of representing our community include using an official email address,
|
56
|
+
posting via an official social media account, or acting as an appointed
|
57
|
+
representative at an online or offline event.
|
58
|
+
|
59
|
+
## Enforcement
|
60
|
+
|
61
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
62
|
+
reported to the community leaders responsible for enforcement at
|
63
|
+
[INSERT CONTACT METHOD].
|
64
|
+
All complaints will be reviewed and investigated promptly and fairly.
|
65
|
+
|
66
|
+
All community leaders are obligated to respect the privacy and security of the
|
67
|
+
reporter of any incident.
|
68
|
+
|
69
|
+
## Enforcement Guidelines
|
70
|
+
|
71
|
+
Community leaders will follow these Community Impact Guidelines in determining
|
72
|
+
the consequences for any action they deem in violation of this Code of Conduct:
|
73
|
+
|
74
|
+
### 1. Correction
|
75
|
+
|
76
|
+
**Community Impact**: Use of inappropriate language or other behavior deemed
|
77
|
+
unprofessional or unwelcome in the community.
|
78
|
+
|
79
|
+
**Consequence**: A private, written warning from community leaders, providing
|
80
|
+
clarity around the nature of the violation and an explanation of why the
|
81
|
+
behavior was inappropriate. A public apology may be requested.
|
82
|
+
|
83
|
+
### 2. Warning
|
84
|
+
|
85
|
+
**Community Impact**: A violation through a single incident or series of
|
86
|
+
actions.
|
87
|
+
|
88
|
+
**Consequence**: A warning with consequences for continued behavior. No
|
89
|
+
interaction with the people involved, including unsolicited interaction with
|
90
|
+
those enforcing the Code of Conduct, for a specified period of time. This
|
91
|
+
includes avoiding interactions in community spaces as well as external channels
|
92
|
+
like social media. Violating these terms may lead to a temporary or permanent
|
93
|
+
ban.
|
94
|
+
|
95
|
+
### 3. Temporary Ban
|
96
|
+
|
97
|
+
**Community Impact**: A serious violation of community standards, including
|
98
|
+
sustained inappropriate behavior.
|
99
|
+
|
100
|
+
**Consequence**: A temporary ban from any sort of interaction or public
|
101
|
+
communication with the community for a specified period of time. No public or
|
102
|
+
private interaction with the people involved, including unsolicited interaction
|
103
|
+
with those enforcing the Code of Conduct, is allowed during this period.
|
104
|
+
Violating these terms may lead to a permanent ban.
|
105
|
+
|
106
|
+
### 4. Permanent Ban
|
107
|
+
|
108
|
+
**Community Impact**: Demonstrating a pattern of violation of community
|
109
|
+
standards, including sustained inappropriate behavior, harassment of an
|
110
|
+
individual, or aggression toward or disparagement of classes of individuals.
|
111
|
+
|
112
|
+
**Consequence**: A permanent ban from any sort of public interaction within the
|
113
|
+
community.
|
114
|
+
|
115
|
+
## Attribution
|
116
|
+
|
117
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
118
|
+
version 2.1, available at
|
119
|
+
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
120
|
+
|
121
|
+
Community Impact Guidelines were inspired by
|
122
|
+
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
123
|
+
|
124
|
+
For answers to common questions about this code of conduct, see the FAQ at
|
125
|
+
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
126
|
+
[https://www.contributor-covenant.org/translations][translations].
|
127
|
+
|
128
|
+
[homepage]: https://www.contributor-covenant.org
|
129
|
+
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
130
|
+
[Mozilla CoC]: https://github.com/mozilla/diversity
|
131
|
+
[FAQ]: https://www.contributor-covenant.org/faq
|
132
|
+
[translations]: https://www.contributor-covenant.org/translations
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2025 Benjamin Bouchet
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,248 @@
|
|
1
|
+
# EasyCrypt
|
2
|
+
|
3
|
+
EasyCrypt is a Ruby utility that provides secure and flexible encryption and decryption capabilities for Ruby on Rails applications. It is built on top of Rails’ ActiveSupport::MessageEncryptor, allowing you to securely and easily encrypt and decrypt data.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
- Multiple secrets providers support (currently _Rails credentials_ and _env variables_).
|
8
|
+
- Simple, purpose-based encryption/decryption API.
|
9
|
+
- Configurable encryption cipher.
|
10
|
+
- Minimal configuration required.
|
11
|
+
- Built-in encryption signatures to ensure data integrity.
|
12
|
+
|
13
|
+
## Table of Contents
|
14
|
+
|
15
|
+
- [Installation](#installation)
|
16
|
+
- [Configuration](#configuration)
|
17
|
+
- [Usage](#usage)
|
18
|
+
- [Secrets Provider Configuration](#secrets-provider-configuration)
|
19
|
+
- [Encrypting Data](#encrypting-data)
|
20
|
+
- [Decrypting Data](#decrypting-data)
|
21
|
+
- [Dynamic Method Calls](#dynamic-method-calls)
|
22
|
+
- [Error Handling](#error-handling)
|
23
|
+
- [Customizing the Cipher](#customizing-the-cipher)
|
24
|
+
- [Advanced Topics](#advanced-topics)
|
25
|
+
- [Message Expiration](#message-expiration)
|
26
|
+
- [Performance Considerations](#performance-considerations)
|
27
|
+
- [Security Best Practices](#security-best-practices)
|
28
|
+
- [Contributing](#contributing)
|
29
|
+
- [License](#license)
|
30
|
+
- [Code of Conduct](#code-of-Conduct)
|
31
|
+
|
32
|
+
## Installation
|
33
|
+
|
34
|
+
Add this line to your application's Gemfile:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
gem 'easy_crypt'
|
38
|
+
```
|
39
|
+
|
40
|
+
Then execute:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
bundle install
|
44
|
+
```
|
45
|
+
|
46
|
+
Or install it yourself:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
gem install easy_crypt
|
50
|
+
```
|
51
|
+
|
52
|
+
## Configuration
|
53
|
+
|
54
|
+
Create an initializer in your Rails application (e.g., `config/initializers/easy_crypt.rb`).
|
55
|
+
Configure EasyCrypt to specify how secrets are stored and which cipher to use:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
EasyCrypt.configure do |config|
|
59
|
+
# Choose your secrets provider. Currently supports :rails_credentials or :env_vars
|
60
|
+
# Default is :rails_credentials
|
61
|
+
config.secrets_provider = :rails_credentials
|
62
|
+
|
63
|
+
# Set your default cipher
|
64
|
+
# Default is identical to ActiveSupport::MessageEncryptor.default_cipher,
|
65
|
+
# commonly 'aes-256-gcm' or 'aes-256-cbc', depending on your Rails configuration
|
66
|
+
config.default_cipher = 'aes-256-gcm'
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
## Usage
|
71
|
+
|
72
|
+
EasyCrypt expects you to define secrets for multiple "purposes". This means that if you’re encrypting user data, you can set up one pair of secret and salt for the "user_data" purpose. If you’re encrypting tokens for session authentication, you might use the "authentication" purpose with a different pair of secret and salt, and so on.
|
73
|
+
|
74
|
+
### Secrets Provider Configuration
|
75
|
+
|
76
|
+
EasyCrypt currently supports two types of secrets providers: environment variables (`:env_vars`) and Rails credentials (`:rails_credentials`).
|
77
|
+
|
78
|
+
#### Using Rails Credentials
|
79
|
+
|
80
|
+
With Rails credentials, you can define secrets for each purpose in `config/credentials.yml.enc`:
|
81
|
+
|
82
|
+
```yaml
|
83
|
+
easy_crypt:
|
84
|
+
authentication:
|
85
|
+
salt: "auth-salt"
|
86
|
+
secret: "auth-secret"
|
87
|
+
user_data:
|
88
|
+
salt: "user-data-salt"
|
89
|
+
secret: "user-data-secret"
|
90
|
+
```
|
91
|
+
|
92
|
+
This structure allows you to define multiple purposes under the `easy_crypt` key, each with its own `salt` and `secret`. EasyCrypt will automatically retrieve the corresponding values when encrypting or decrypting using the corresponding purpose.
|
93
|
+
|
94
|
+
The example above defines "authentication" and "user_data" purpose, but you are free to pick the names that make sense for the purposes you need, as long as you follow the same structure.
|
95
|
+
|
96
|
+
#### Using Environment Variables
|
97
|
+
|
98
|
+
If you prefer using environment variables, define the salt and secret for each purpose in your `.env` file or directly in the environment. The format is:
|
99
|
+
|
100
|
+
```env
|
101
|
+
EASY_CRYPT_<PURPOSE>_SALT=your-salt
|
102
|
+
EASY_CRYPT_<PURPOSE>_SECRET=your-secret
|
103
|
+
```
|
104
|
+
|
105
|
+
For example:
|
106
|
+
|
107
|
+
```env
|
108
|
+
EASY_CRYPT_AUTHENTICATION_SALT=auth-salt
|
109
|
+
EASY_CRYPT_AUTHENTICATION_SECRET=auth-secret
|
110
|
+
EASY_CRYPT_USER_DATA_SALT=user-data-salt
|
111
|
+
EASY_CRYPT_USER_DATA_SECRET=user-data-secret
|
112
|
+
```
|
113
|
+
|
114
|
+
You can then encrypt or decrypt data for these purposes.
|
115
|
+
|
116
|
+
### Encrypting Data
|
117
|
+
|
118
|
+
To encrypt a piece of data with the "user_data" purpose:
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
encrypted_value = EasyCrypt.encrypt_user_data("Sensitive Information")
|
122
|
+
```
|
123
|
+
|
124
|
+
Internally, EasyCrypt automatically retrieves the secret and salt for the "user_data" purpose, using your configured secrets provider. It uses `ActiveSupport::MessageEncryptor` to encrypt and sign the data.
|
125
|
+
|
126
|
+
### Decrypting Data
|
127
|
+
|
128
|
+
To decrypt the data you just encrypted, call:
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
decrypted_value = EasyCrypt.decrypt_user_data(encrypted_value)
|
132
|
+
|
133
|
+
if decrypted_value
|
134
|
+
puts "Decrypted successfully: #{decrypted_value}"
|
135
|
+
else
|
136
|
+
puts "Invalid or expired data."
|
137
|
+
end
|
138
|
+
```
|
139
|
+
|
140
|
+
If anything goes wrong in the decryption process (e.g., invalid signature or message expiration when using time-based encryption), EasyCrypt returns `nil` rather than raising an exception.
|
141
|
+
|
142
|
+
### Dynamic Method Calls
|
143
|
+
|
144
|
+
EasyCrypt uses `method_missing` to allow dynamic encrypt/decrypt methods for different purposes, following this pattern:
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
encrypt_<purpose>
|
148
|
+
decrypt_<purpose>
|
149
|
+
```
|
150
|
+
|
151
|
+
For example, if you want data to be encrypted with a "passwords" purpose:
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
encrypted_pw = EasyCrypt.encrypt_passwords("super_secret")
|
155
|
+
decrypted_pw = EasyCrypt.decrypt_passwords(encrypted_pw)
|
156
|
+
```
|
157
|
+
|
158
|
+
Given that you have properly defined the secret and salt for the "passwords" purpose in your secrets provider.
|
159
|
+
|
160
|
+
### Error Handling
|
161
|
+
|
162
|
+
When decryption fails (e.g., altered data or expired message), EasyCrypt returns `nil` to avoid exposing decryption errors.
|
163
|
+
|
164
|
+
For method names that don't match the `encrypt_<purpose>` or `decrypt_<purpose>` naming pattern, a `NoMethodError` will be raised.
|
165
|
+
|
166
|
+
If your secrets provider returns invalid or missing credentials, such as when `salt` or `secret` are missing, EasyCrypt raises a `MissingSecretsConfigurationError`.
|
167
|
+
|
168
|
+
### Customizing the Cipher
|
169
|
+
|
170
|
+
EasyCrypt uses by default the cipher returned by `ActiveSupport::MessageEncryptor.default_cipher`, which depends on your application configuration.
|
171
|
+
|
172
|
+
You can override the gem’s default cipher through EasyCrypt configuration:
|
173
|
+
|
174
|
+
```ruby
|
175
|
+
EasyCrypt.configure do |config|
|
176
|
+
# Choose a different cipher if desired
|
177
|
+
config.default_cipher = 'aes-128-gcm'
|
178
|
+
end
|
179
|
+
```
|
180
|
+
|
181
|
+
Secrets Providers can also specify cipher for a particular purpose.
|
182
|
+
|
183
|
+
#### Using Rails Credentials
|
184
|
+
|
185
|
+
In `config/credentials.yml.enc`:
|
186
|
+
|
187
|
+
```yaml
|
188
|
+
easy_crypt:
|
189
|
+
data_in_transit:
|
190
|
+
cipher: "aes-128-gcm"
|
191
|
+
salt: "auth-salt"
|
192
|
+
secret: "auth-secret"
|
193
|
+
```
|
194
|
+
|
195
|
+
Here, the `data_in_transit` purpose will use the `aes-128-gcm` cipher, overriding the default cipher.
|
196
|
+
|
197
|
+
### Using Environment Variables
|
198
|
+
|
199
|
+
You can set the cipher for a purpose using an environment variable:
|
200
|
+
|
201
|
+
```env
|
202
|
+
EASY_CRYPT_DATA_IN_TRANSIT_CIPHER=aes-128-gcm
|
203
|
+
EASY_CRYPT_DATA_IN_TRANSIT_SALT=auth-salt
|
204
|
+
EASY_CRYPT_DATA_IN_TRANSIT_SECRET=auth-secret
|
205
|
+
```
|
206
|
+
|
207
|
+
Here, the `data_in_transit` purpose will use the `aes-128-gcm` cipher, overriding the default cipher.
|
208
|
+
|
209
|
+
## Advanced Topics
|
210
|
+
|
211
|
+
### Message Expiration
|
212
|
+
|
213
|
+
EasyCrypt supports passing `expires_at` or `expires_in` to the underlying `encrypt_and_sign` method as described in [Rails' documentation](ActiveSupport::MessageEncryptor.default_cipher). If provided, the data becomes invalid after that time:
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
encrypted = EasyCrypt.encrypt_user_data("Sensitive Info", expires_in: 1.hour)
|
217
|
+
```
|
218
|
+
|
219
|
+
### Performance Considerations
|
220
|
+
|
221
|
+
If you need to handle large data encryption, consider compressing it before calling the encrypt methods. Also, avoid redundant encryption in tight loops for better performance.
|
222
|
+
|
223
|
+
### Security Best Practices
|
224
|
+
|
225
|
+
This list is not exhaustive:
|
226
|
+
|
227
|
+
- __Use Strong Algorithms__: Choose encryption methods wisely, AES-256 for symmetric and RSA-2048+ or elliptic curves for asymmetric encryption.
|
228
|
+
- __Hashing for Validation__: Use secure hashing algorithms (e.g., bcrypt, Argon2) to validate secrets you don't need to store, like passwords.
|
229
|
+
- __Sign for Integrity__: Sign data to prevent tampering (e.g., with RSA or ECDSA).
|
230
|
+
- __Store Secrets Securely__: Use secret management tools (e.g., HashiCorp Vault).
|
231
|
+
- __Rotate Secrets Periodically__: Regularly update keys and credentials to limit exposure.
|
232
|
+
- __Avoid Exposing Secrets__: Never log sensitive information or hardcode secrets in code or repositories.
|
233
|
+
- __Encrypt Everywhere__: Encrypt data at rest, in transit, and even on trusted networks.
|
234
|
+
- __Rely on Proven Libraries__: Avoid building custom encryption; use trusted libraries (e.g., OpenSSL, EasyCrypt). Note: EasyCrypt uses OpenSSL under the hood.
|
235
|
+
|
236
|
+
## Contributing
|
237
|
+
|
238
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/randoum/easy_crypt. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/randoum/easy_crypt/blob/main/CODE_OF_CONDUCT.md).
|
239
|
+
|
240
|
+
Adding a rotation feature could be a good contribution, if you feel like doing so.
|
241
|
+
|
242
|
+
## License
|
243
|
+
|
244
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
245
|
+
|
246
|
+
## Code of Conduct
|
247
|
+
|
248
|
+
Everyone interacting in the EasyCrypt project's codebases and issue trackers is expected to follow the [code of conduct](https://github.com/randoum/easy_crypt/blob/main/CODE_OF_CONDUCT.md).
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EasyCrypt
|
4
|
+
# Exception raised when the requested secrets provider does not exist
|
5
|
+
class InvalidSecretsProvider < StandardError
|
6
|
+
def initialize(str)
|
7
|
+
super("Unknown secrets provider `#{str}`")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# Exception raised when secrets are missing for the requested purpose
|
12
|
+
class MissingSecretsConfigurationError < StandardError
|
13
|
+
def initialize(purpose, missing_attributes)
|
14
|
+
super("Missing required secret configuration for '#{purpose}': #{missing_attributes.join(', ')}")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EasyCrypt
|
4
|
+
class SecretsProvider
|
5
|
+
# Base class for all secret providers. Implements the interface that
|
6
|
+
# concrete providers must follow.
|
7
|
+
#
|
8
|
+
# This abstract base class defines the structure for secrets providers, including
|
9
|
+
# required methods for retrieving encryption configuration values such as `salt`,
|
10
|
+
# `secret`, and `cipher`. Subclasses are expected to implement these methods based
|
11
|
+
# on their respective sources (e.g., environment variables, Rails credentials).
|
12
|
+
#
|
13
|
+
# @abstract Subclass and override {#secret}, {#salt}, and {#cipher} to implement
|
14
|
+
# a custom secrets provider.
|
15
|
+
class Base
|
16
|
+
# @return [Symbol] The purpose of the credential being accessed
|
17
|
+
attr_reader :purpose
|
18
|
+
|
19
|
+
# Initialize a new secrets provider
|
20
|
+
#
|
21
|
+
# @param purpose [Symbol] The purpose of the credential (e.g., :authentication)
|
22
|
+
def initialize(purpose)
|
23
|
+
@purpose = purpose
|
24
|
+
end
|
25
|
+
|
26
|
+
# Validates the presence of required attributes for the secrets provider.
|
27
|
+
#
|
28
|
+
# Checks if the attributes `salt`, and `secret` are defined.
|
29
|
+
# Raises a `MissingSecretsConfigurationError` error if any of these attributes are missing.
|
30
|
+
#
|
31
|
+
# @raise [MissingSecretsConfigurationError] If any required attribute is missing.
|
32
|
+
def validate_attributes!
|
33
|
+
missing_attributes = %w[salt secret].reject { |attr| send(attr) }
|
34
|
+
raise MissingSecretsConfigurationError.new(purpose, missing_attributes) if missing_attributes.any?
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the encryption cipher.
|
38
|
+
#
|
39
|
+
# @abstract
|
40
|
+
# @return [String, nil] The encryption cipher.
|
41
|
+
# @raise [NotImplementedError] If not implemented in the subclass.
|
42
|
+
def cipher
|
43
|
+
raise NotImplementedError, 'Subclasses must implement #cipher'
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns the salt value for key generation
|
47
|
+
#
|
48
|
+
# @abstract
|
49
|
+
# @return [String] The salt value
|
50
|
+
# @raise [NotImplementedError] If the subclass doesn't implement this method
|
51
|
+
def salt
|
52
|
+
raise NotImplementedError, 'Subclasses must implement #salt'
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns the secret key for encryption
|
56
|
+
#
|
57
|
+
# @abstract
|
58
|
+
# @return [String] The secret key
|
59
|
+
# @raise [NotImplementedError] If the subclass doesn't implement this method
|
60
|
+
def secret
|
61
|
+
raise NotImplementedError, 'Subclasses must implement #secret'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EasyCrypt
|
4
|
+
class SecretsProvider
|
5
|
+
# Provider that fetches encryption configuration from environment variables
|
6
|
+
#
|
7
|
+
# Multiple credential purposes can be configured using environment variables.
|
8
|
+
# Each credential purpose requires three environment variables following this pattern:
|
9
|
+
#
|
10
|
+
# EASY_CRYPT_[PURPOSE]_CIPHER - (optional) Cipher to use for the encryption
|
11
|
+
# falls back to EasyCrypt.default_cipher is not set
|
12
|
+
# EASY_CRYPT_[PURPOSE]_SALT - Salt value for the encryption
|
13
|
+
# EASY_CRYPT_[PURPOSE]_SECRET - Secret key for the encryption
|
14
|
+
#
|
15
|
+
# Where [PURPOSE] is the uppercase version of the credential purpose
|
16
|
+
#
|
17
|
+
# @example Using authentication credentials
|
18
|
+
# # In .env file or environment:
|
19
|
+
# EASY_CRYPT_AUTHENTICATION_CIPHER=aes128
|
20
|
+
# EASY_CRYPT_AUTHENTICATION_SALT=your-salt-value
|
21
|
+
# EASY_CRYPT_AUTHENTICATION_SECRET=your-secret-key
|
22
|
+
#
|
23
|
+
# provider = EnvProvider.new(:authentication)
|
24
|
+
# provider.cipher #=> "aes128"
|
25
|
+
# provider.salt #=> "your-salt-value"
|
26
|
+
# provider.secret #=> "your-secret-key"
|
27
|
+
#
|
28
|
+
# @example Using user_data credentials
|
29
|
+
# # In .env file or environment:
|
30
|
+
# EASY_CRYPT_USER_DATA_SALT=different-salt
|
31
|
+
# EASY_CRYPT_USER_DATA_SECRET=different-secret
|
32
|
+
#
|
33
|
+
# provider = EnvProvider.new(:user_data)
|
34
|
+
# provider.cipher #=> nil
|
35
|
+
# provider.salt #=> "different-salt"
|
36
|
+
# provider.secret #=> "different-secret"
|
37
|
+
#
|
38
|
+
# You can set these variables in your .env file:
|
39
|
+
# echo "EASY_CRYPT_AUTHENTICATION_CIPHER=aes128" >> .env
|
40
|
+
# echo "EASY_CRYPT_AUTHENTICATION_SALT=your-salt" >> .env
|
41
|
+
# echo "EASY_CRYPT_AUTHENTICATION_SECRET=your-secret" >> .env
|
42
|
+
#
|
43
|
+
# Or export them directly in your environment:
|
44
|
+
# export EASY_CRYPT_AUTHENTICATION_CIPHER=aes128
|
45
|
+
# export EASY_CRYPT_AUTHENTICATION_SALT=your-salt
|
46
|
+
# export EASY_CRYPT_AUTHENTICATION_SECRET=your-secret
|
47
|
+
class EnvProvider < Base
|
48
|
+
# @return [String, nil] The encryption cipher from environment variable
|
49
|
+
def cipher
|
50
|
+
credentials('CIPHER')
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [String, nil] The salt value from environment variable
|
54
|
+
def salt
|
55
|
+
credentials('SALT')
|
56
|
+
end
|
57
|
+
|
58
|
+
# @return [String, nil] The secret key from environment variable
|
59
|
+
def secret
|
60
|
+
credentials('SECRET')
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def credentials(key)
|
66
|
+
ENV.fetch("EASY_CRYPT_#{purpose.to_s.upcase}_#{key}", nil)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EasyCrypt
|
4
|
+
class SecretsProvider
|
5
|
+
# Provider that fetches encryption configuration from Rails credentials
|
6
|
+
#
|
7
|
+
# Configuration should be structured in credentials.yml.enc as:
|
8
|
+
#
|
9
|
+
# easy_crypt: # EasyCrypt purposes configuration parent key
|
10
|
+
# authentication: # Credential for the "authentication" purpose
|
11
|
+
# cipher: "aes128" # (optional) Cipher to use for the encryption
|
12
|
+
# # falls back to EasyCrypt.default_cipher is not set
|
13
|
+
# salt: "your-salt-value" # Salt value for the encryption
|
14
|
+
# secret: "your-secret-key" # Secret key for the encryption
|
15
|
+
# user_data: # Credential for the "user data" purpose
|
16
|
+
# salt: "different-salt" # Salt value for the encryption
|
17
|
+
# secret: "different-secret" # Secret key for the encryption
|
18
|
+
#
|
19
|
+
# You can define multiple credential purposes under the `easy_crypt` namespace,
|
20
|
+
# each with its own configuration. The credential purpose is specified when
|
21
|
+
# initializing the provider.
|
22
|
+
#
|
23
|
+
# To edit credentials.yml.enc, you can use one of these commands:
|
24
|
+
#
|
25
|
+
# With Visual Studio Code:
|
26
|
+
# EDITOR="code --wait" bin/rails credentials:edit
|
27
|
+
#
|
28
|
+
# With Vim:
|
29
|
+
# EDITOR="vim" bin/rails credentials:edit
|
30
|
+
#
|
31
|
+
# With Sublime Text:
|
32
|
+
# EDITOR="subl --wait" bin/rails credentials:edit
|
33
|
+
#
|
34
|
+
# With Nano:
|
35
|
+
# EDITOR="nano" bin/rails credentials:edit
|
36
|
+
#
|
37
|
+
# @example Configuration in credentials.yml.enc
|
38
|
+
# easy_crypt:
|
39
|
+
# authentication:
|
40
|
+
# cipher: aes128
|
41
|
+
# salt: "salt for the authentication purpose"
|
42
|
+
# secret: "secret for the authentication purpose"
|
43
|
+
# user_data:
|
44
|
+
# salt: "different-salt"
|
45
|
+
# secret: "different-secret"
|
46
|
+
#
|
47
|
+
# @example Accessing credentials
|
48
|
+
# # Using authentication credentials
|
49
|
+
# provider = RailsCredentialsProvider.new(:authentication)
|
50
|
+
# provider.cipher #=> "aes128"
|
51
|
+
# provider.salt #=> "salt for the authentication purpose"
|
52
|
+
# provider.secret #=> "secret for the authentication purpose"
|
53
|
+
#
|
54
|
+
# # Using user_data credentials
|
55
|
+
# provider = RailsCredentialsProvider.new(:user_data)
|
56
|
+
# provider.cipher #=> nil
|
57
|
+
# provider.salt #=> "different-salt"
|
58
|
+
# provider.secret #=> "different-secret"
|
59
|
+
class RailsCredentialsProvider < Base
|
60
|
+
# @return [String, nil] The encryption cipher from Rails credentials
|
61
|
+
def cipher
|
62
|
+
credentials&.cipher
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [String] The salt value from Rails credentials
|
66
|
+
def salt
|
67
|
+
credentials&.salt
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [String] The secret key from Rails credentials
|
71
|
+
def secret
|
72
|
+
credentials&.secret
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def credentials
|
78
|
+
Rails.application.credentials.easy_crypt[purpose]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'secrets_provider/base'
|
4
|
+
require_relative 'secrets_provider/env_provider'
|
5
|
+
require_relative 'secrets_provider/rails_credentials_provider'
|
6
|
+
|
7
|
+
module EasyCrypt
|
8
|
+
# The SecretsProvider class serves as a factory for creating secret providers
|
9
|
+
# that supply encryption configuration values from different sources.
|
10
|
+
#
|
11
|
+
# @example Creating a provider for Rails credentials and for the authentication purpose
|
12
|
+
# provider = SecretsProvider.build(:rails_credentials, :authentication)
|
13
|
+
#
|
14
|
+
# @example Creating a provider for environment variables and for the user_data purpose
|
15
|
+
# provider = SecretsProvider.build(:env_vars, :user_data)
|
16
|
+
class SecretsProvider
|
17
|
+
# Available secrets providers and their corresponding classes
|
18
|
+
PROVIDERS = {
|
19
|
+
env_vars: EnvProvider,
|
20
|
+
rails_credentials: RailsCredentialsProvider
|
21
|
+
}.freeze
|
22
|
+
|
23
|
+
# Builds a new secrets provider instance based on the specified provider
|
24
|
+
#
|
25
|
+
# This method acts as a factory for instantiating a secrets provider that fetches
|
26
|
+
# encryption configurations (e.g., secret keys, salts) for a given purpose from
|
27
|
+
# the selected source. The method ensures the specified provider exists and validates
|
28
|
+
# the configuration values.
|
29
|
+
#
|
30
|
+
# @param provider [Symbol] The secrets provider to use (:env_vars or :rails_credentials).
|
31
|
+
# - `:env_vars`: To fetch secrets from environment variables.
|
32
|
+
# - `:rails_credentials`: To fetch secrets from Rails credentials.
|
33
|
+
# @param purpose [Symbol] The purpose of the credential (e.g., :authentication, :user_data).
|
34
|
+
# This links the encryption secrets to a set of credentials (such as secret key and salt).
|
35
|
+
#
|
36
|
+
# @example Building a provider for Rails credentials with the `authentication` purpose
|
37
|
+
# provider = SecretsProvider.build(:rails_credentials, :authentication)
|
38
|
+
#
|
39
|
+
# @example Building a provider for environment variables with the `user_data` purpose
|
40
|
+
# provider = SecretsProvider.build(:env_vars, :user_data)
|
41
|
+
#
|
42
|
+
# @raise [InvalidSecretsProvider] If the specified secrets provider is not recognized.
|
43
|
+
#
|
44
|
+
# @return [Base] An instance of the appropriate provider class.
|
45
|
+
def self.build(provider, purpose)
|
46
|
+
provider = PROVIDERS
|
47
|
+
.fetch(provider.to_sym) { raise InvalidSecretsProvider, provider }
|
48
|
+
.new(purpose)
|
49
|
+
provider.validate_attributes!
|
50
|
+
provider
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/easy_crypt.rb
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails'
|
4
|
+
require 'active_support/message_encryptor'
|
5
|
+
require 'active_support/key_generator'
|
6
|
+
|
7
|
+
require_relative 'easy_crypt/exception'
|
8
|
+
require_relative 'easy_crypt/secrets_provider'
|
9
|
+
|
10
|
+
# EasyCrypt
|
11
|
+
# =========
|
12
|
+
#
|
13
|
+
# EasyCrypt is a Ruby utility that provides secure and flexible encryption/decryption capabilities
|
14
|
+
# for Ruby on Rails applications.
|
15
|
+
#
|
16
|
+
# Features
|
17
|
+
# --------
|
18
|
+
# * Multiple secrets providers support (environment variables and Rails credentials)
|
19
|
+
# * Configurable encryption cipher
|
20
|
+
# * Purpose-based encryption/decryption
|
21
|
+
# * Built on top of Rails' ActiveSupport::MessageEncryptor
|
22
|
+
# * Simple and intuitive API
|
23
|
+
#
|
24
|
+
# Installation
|
25
|
+
# ------------
|
26
|
+
# Add this line to your application's Gemfile:
|
27
|
+
# gem 'easy_crypt'
|
28
|
+
#
|
29
|
+
# Then execute:
|
30
|
+
# $ bundle install
|
31
|
+
#
|
32
|
+
# Or install it yourself as:
|
33
|
+
# $ gem install easy_crypt
|
34
|
+
#
|
35
|
+
# Configuration
|
36
|
+
# -------------
|
37
|
+
#
|
38
|
+
# Create an initializer at config/initializers/easy_crypt.rb:
|
39
|
+
#
|
40
|
+
# ```ruby
|
41
|
+
# EasyCrypt.configure do |config|
|
42
|
+
# # Choose your secrets provider. Currently supports :rails_credentials or :env_vars.
|
43
|
+
# # Default to :rails_credentials
|
44
|
+
# config.secrets_provider = :rails_credentials
|
45
|
+
#
|
46
|
+
# # Set your default cipher (optional)
|
47
|
+
# # Default to `ActiveSupport::MessageEncryptor.default_cipher` which is set to
|
48
|
+
# # 'aes-256-gcm' or 'aes-256-cbc' as of now, depending on your application configuration.
|
49
|
+
# # See `use_authenticated_message_encryption` configuration option for more information.
|
50
|
+
# # See `OpenSSL::Cipher.ciphers` for a list of accepted values.
|
51
|
+
# config.default_cipher = 'aes-256-gcm'
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# Usage
|
55
|
+
# ---
|
56
|
+
#
|
57
|
+
# First, you need to configure a secret and a salt for a specific purpose.
|
58
|
+
# To do so, you'll need to use one of the supported secrets providers (currently
|
59
|
+
# Rails credentials and env vars) and define a purpose and its credentials.
|
60
|
+
#
|
61
|
+
# See `EasyCrypt::SecretsProvider` subclasses for more information on how
|
62
|
+
# to configure the secrets provider of your choice.
|
63
|
+
#
|
64
|
+
# Given that you provided a secret and a salt for the "user_data" purpose,
|
65
|
+
# you are able to call the `encrypt_user_data` and `decrypt_user_data` methods
|
66
|
+
# to directly use the credentials of the "user_data" purpose.
|
67
|
+
#
|
68
|
+
# ```ruby
|
69
|
+
# # Encrypt a value
|
70
|
+
# encrypted = EasyCrypt.encrypt_user_data("sensitive information")
|
71
|
+
#
|
72
|
+
# # Decrypt a value
|
73
|
+
# decrypted = EasyCrypt.decrypt_user_data(encrypted)
|
74
|
+
# ```
|
75
|
+
#
|
76
|
+
module EasyCrypt
|
77
|
+
# @return [String] The default cipher used for encryption/decryption operations
|
78
|
+
@default_cipher = ActiveSupport::MessageEncryptor.default_cipher
|
79
|
+
|
80
|
+
# @return [Symbol] The provider used for retrieving encryption secrets
|
81
|
+
@secrets_provider = :rails_credentials
|
82
|
+
|
83
|
+
class << self
|
84
|
+
attr_accessor :default_cipher, :secrets_provider
|
85
|
+
|
86
|
+
# Configures the EasyCrypt module with custom settings
|
87
|
+
#
|
88
|
+
# @example
|
89
|
+
# EasyCrypt.configure do |config|
|
90
|
+
# config.secrets_provider = :env_vars
|
91
|
+
# config.default_cipher = 'aes-128-gcm'
|
92
|
+
# end
|
93
|
+
#
|
94
|
+
# @yieldparam config [EasyCrypt] The configuration object
|
95
|
+
# @return [void]
|
96
|
+
def configure
|
97
|
+
yield self
|
98
|
+
end
|
99
|
+
|
100
|
+
# Handles dynamic encryption/decryption method calls
|
101
|
+
#
|
102
|
+
# This method allows dynamically calling encryption or decryption methods for specific purposes
|
103
|
+
# by embedding the purpose directly in the method name. The pattern for such method names is:
|
104
|
+
# `encrypt_<purpose>` for encryption and `decrypt_<purpose>` for decryption.
|
105
|
+
#
|
106
|
+
# For instance:
|
107
|
+
# - Calling `EasyCrypt.encrypt_authentication(value)` will encrypt the provided value using the
|
108
|
+
# credentials configured for the `authentication` purpose.
|
109
|
+
# - Calling `EasyCrypt.decrypt_user_data(encrypted_value)` will decrypt the given value using the
|
110
|
+
# credentials for the `user_data` purpose.
|
111
|
+
#
|
112
|
+
# This dynamic approach enables simple and intuitive APIs without requiring explicit method
|
113
|
+
# definitions for each purpose.
|
114
|
+
#
|
115
|
+
# @example Encrypting a value for the "authentication" purpose
|
116
|
+
# encrypted = EasyCrypt.encrypt_authentication("my_secret_data")
|
117
|
+
#
|
118
|
+
# @example Decrypting a value for the "user_data" purpose
|
119
|
+
# decrypted = EasyCrypt.decrypt_user_data(encrypted_data)
|
120
|
+
#
|
121
|
+
# @note If the method name does not match the expected pattern, `method_missing` will defer to
|
122
|
+
# the superclass implementation, raising a `NoMethodError` if the method is undefined.
|
123
|
+
#
|
124
|
+
# @return [Object, String, nil] The encrypted or decrypted value, or nil if decryption fails
|
125
|
+
def method_missing(method_name, *args)
|
126
|
+
if /^(?<action>encrypt|decrypt)_(?<purpose>[a-z_]+)$/ =~ method_name
|
127
|
+
send(action, *args.unshift(purpose.to_sym))
|
128
|
+
else
|
129
|
+
super
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Checks if a method is supported by the module
|
134
|
+
def respond_to_missing?(method_name, include_private)
|
135
|
+
/^(encrypt|decrypt)_[a-z_]+$/ =~ method_name || super
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
# Encrypts and signs a value for a specific purpose
|
141
|
+
#
|
142
|
+
# @param purpose [Symbol] The purpose for which the value is being encrypted, e.g., :user_data
|
143
|
+
# @param value [Object] The value to encrypt (must be serializable)
|
144
|
+
# @param options [Hash] Additional options for encryption
|
145
|
+
#
|
146
|
+
# @example Encrypting a value for the "user_data" purpose
|
147
|
+
# EasyCrypt.encrypt_user_data("sensitive information")
|
148
|
+
#
|
149
|
+
# @return [String] The encrypted and signed value
|
150
|
+
def encrypt(purpose, value, options = {})
|
151
|
+
options.merge!(purpose: purpose)
|
152
|
+
encryptor(purpose).encrypt_and_sign(value, **options)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Decrypts a value that was encrypted for a specific purpose
|
156
|
+
#
|
157
|
+
# @param purpose [Symbol] The purpose for which the value was encrypted, e.g., :user_data
|
158
|
+
# @param encrypted_data [String] The encrypted data to decrypt
|
159
|
+
#
|
160
|
+
# @example Decrypting a value for the "user_data" purpose
|
161
|
+
# EasyCrypt.decrypt_user_data(encrypted_value)
|
162
|
+
#
|
163
|
+
# @return [Object, nil] The decrypted value, or nil if decryption fails
|
164
|
+
def decrypt(purpose, encrypted_data)
|
165
|
+
encryptor(purpose).decrypt_and_verify(encrypted_data, purpose: purpose)
|
166
|
+
rescue ActiveSupport::MessageEncryptor::InvalidMessage
|
167
|
+
nil
|
168
|
+
end
|
169
|
+
|
170
|
+
# Creates a new MessageEncryptor instance for a specific purpose
|
171
|
+
#
|
172
|
+
# @param purpose [Symbol] The purpose for which to create the encryptor, e.g., :user_data
|
173
|
+
#
|
174
|
+
# @example Creating an encryptor configured for the "user_data" purpose
|
175
|
+
# encryptor = EasyCrypt.send(:encryptor, :user_data)
|
176
|
+
#
|
177
|
+
# @return [ActiveSupport::MessageEncryptor] The configured encryptor instance
|
178
|
+
def encryptor(purpose)
|
179
|
+
provider = SecretsProvider.build(secrets_provider, purpose)
|
180
|
+
|
181
|
+
cipher = provider.cipher || default_cipher
|
182
|
+
|
183
|
+
len = ActiveSupport::MessageEncryptor.key_len(cipher)
|
184
|
+
key = ActiveSupport::KeyGenerator.new(provider.secret).generate_key(provider.salt, len)
|
185
|
+
ActiveSupport::MessageEncryptor.new(key, cipher: cipher)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: easy_crypt
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Benjamin Bouchet
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-01-27 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: |2-
|
14
|
+
|
15
|
+
Encryption and decryption for Rails applications, based on ActiveSupport::MessageEncryptor, using
|
16
|
+
multiple secrets providers, and defining a simple, purpose-based encryption/decryption API.
|
17
|
+
email: randoum@gmail.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- CHANGELOG.md
|
23
|
+
- CODE_OF_CONDUCT.md
|
24
|
+
- LICENSE.txt
|
25
|
+
- README.md
|
26
|
+
- lib/easy_crypt.rb
|
27
|
+
- lib/easy_crypt/exception.rb
|
28
|
+
- lib/easy_crypt/secrets_provider.rb
|
29
|
+
- lib/easy_crypt/secrets_provider/base.rb
|
30
|
+
- lib/easy_crypt/secrets_provider/env_provider.rb
|
31
|
+
- lib/easy_crypt/secrets_provider/rails_credentials_provider.rb
|
32
|
+
- lib/easy_crypt/version.rb
|
33
|
+
homepage: https://github.com/randoum/easy_crypt
|
34
|
+
licenses:
|
35
|
+
- MIT
|
36
|
+
metadata:
|
37
|
+
homepage_uri: https://github.com/randoum/easy_crypt
|
38
|
+
documentation_uri: https://rubydoc.info/github/randoum/easy_crypt
|
39
|
+
changelog_uri: https://github.com/randoum/easy_crypt/blob/main/CHANGELOG.md
|
40
|
+
source_code_uri: https://github.com/randoum/easy_crypt
|
41
|
+
bug_tracker_uri: https://github.com/randoum/easy_crypt/issues
|
42
|
+
rubygems_mfa_required: 'true'
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: 2.7.0
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 1.8.11
|
57
|
+
requirements: []
|
58
|
+
rubygems_version: 3.1.2
|
59
|
+
signing_key:
|
60
|
+
specification_version: 4
|
61
|
+
summary: Secure and flexible encryption for Ruby on Rails applications.
|
62
|
+
test_files: []
|