dotenvcrypt-core 0.7.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 256f81ef09fad3aee0108ae5d490cdb5c0bf3cdce712d53160b185d1b1e6b150
4
+ data.tar.gz: 8274f1cdffefe95628e2e3d62af81dd7f7b3286352ab8c8ef917ed74e62e21ba
5
+ SHA512:
6
+ metadata.gz: 3db1b1d2c3aaa40419b3ace5e8cda5f1e0ceb7e9eeb3a19c9c986caedf180350bfd3c2acb995398f64553aa08bb24958bb374ec64d310c6974ab51e10cadbd3a
7
+ data.tar.gz: 320c16b44c395c9d6eda29ac194cd2ba66bb5e8d7f1a751712ece266d9ab7cdb966297fdd39ee20c47a10b7476d24c7a582c3d5b67f0fc047630a3e51d98f2ac
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Dan Loman
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 all
13
+ 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 THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # dotenvcrypt-core
2
+
3
+ Pure Ruby library for encrypting and decrypting .env files using AES-256-GCM encryption.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ gem install dotenvcrypt-core
9
+ ```
10
+
11
+ Or add to your Gemfile:
12
+
13
+ ```ruby
14
+ gem 'dotenvcrypt-core'
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ### Loading Encrypted ENV Files
20
+
21
+ The simplest way to use dotenvcrypt-core is to load an encrypted .env file directly into your environment:
22
+
23
+ ```ruby
24
+ require 'dotenvcrypt-core'
25
+
26
+ # Load encrypted .env file into ENV
27
+ Dotenvcrypt.load_env('.env.enc', key: 'your-secret-key')
28
+
29
+ # Now you can access your environment variables
30
+ puts ENV['DATABASE_URL']
31
+ ```
32
+
33
+ ### Encrypting and Decrypting Manually
34
+
35
+ For more control, you can use the Encryptor class directly:
36
+
37
+ ```ruby
38
+ require 'dotenvcrypt-core'
39
+
40
+ # Create an encryptor with your secret key
41
+ encryptor = Dotenvcrypt::Core::Encryptor.new('your-secret-key')
42
+
43
+ # Encrypt data
44
+ plaintext = "SECRET_KEY=my-secret-value\nAPI_TOKEN=abc123"
45
+ encrypted = encryptor.encrypt(plaintext)
46
+ File.write('.env.enc', encrypted)
47
+
48
+ # Decrypt data
49
+ encrypted_data = File.read('.env.enc')
50
+ decrypted = encryptor.decrypt(encrypted_data)
51
+ puts decrypted
52
+ ```
53
+
54
+ ### Error Handling
55
+
56
+ The library raises exceptions instead of printing to stdout or exiting:
57
+
58
+ ```ruby
59
+ begin
60
+ Dotenvcrypt.load('.env.enc', key: 'wrong-key')
61
+ rescue Dotenvcrypt::Core::DecryptionError => e
62
+ puts "Failed to decrypt: #{e.message}"
63
+ rescue Dotenvcrypt::Core::InvalidFormatError => e
64
+ puts "Invalid file format: #{e.message}"
65
+ end
66
+ ```
67
+
68
+ Available exceptions:
69
+ - `Dotenvcrypt::Core::EncryptionError` - General encryption errors
70
+ - `Dotenvcrypt::Core::DecryptionError` - Decryption failed (wrong key, corrupted file, tampering)
71
+ - `Dotenvcrypt::Core::InvalidFormatError` - File is not in valid base64 format
72
+
73
+ ## Features
74
+
75
+ - **AES-256-GCM encryption** - Industry-standard authenticated encryption
76
+ - **Pure Ruby** - No external dependencies beyond Ruby's standard library
77
+ - **Exception-based error handling** - Integrate cleanly into your application
78
+ - **Dotenv-compatible** - Works with standard .env file format
79
+
80
+ ## Security
81
+
82
+ - Uses AES-256 in GCM (Galois/Counter Mode) for authenticated encryption
83
+ - Generates secure random initialization vectors (IV) for each encryption
84
+ - Provides tamper detection via authentication tags
85
+ - Keys are hashed with SHA256 before use
86
+
87
+ ## License
88
+
89
+ MIT
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dotenvcrypt
4
+ module Core
5
+ class EncryptionError < StandardError; end
6
+ class DecryptionError < StandardError; end
7
+ class InvalidFormatError < DecryptionError; end
8
+
9
+ class Encryptor
10
+ def initialize(encryption_key)
11
+ @encryption_key = encryption_key
12
+ end
13
+
14
+ # Encrypt file
15
+ def encrypt(data)
16
+ cipher = OpenSSL::Cipher::AES256.new(:GCM)
17
+ cipher.encrypt
18
+ key = OpenSSL::Digest::SHA256.digest(encryption_key)
19
+ cipher.key = key
20
+
21
+ # Generate a secure random IV (12 bytes is recommended for GCM)
22
+ iv = cipher.random_iv
23
+
24
+ encrypted = cipher.update(data) + cipher.final
25
+
26
+ # Get the authentication tag (16 bytes)
27
+ auth_tag = cipher.auth_tag
28
+
29
+ # Combine IV, encrypted data, and auth tag
30
+ combined = iv + auth_tag + encrypted
31
+
32
+ # Convert to base64 for readability
33
+ Base64.strict_encode64(combined)
34
+ end
35
+
36
+ # Decrypt file
37
+ def decrypt(encoded_data)
38
+ begin
39
+ data = Base64.strict_decode64(encoded_data)
40
+ rescue ArgumentError
41
+ raise InvalidFormatError, "File is not in valid base64 format"
42
+ end
43
+
44
+ # For GCM mode:
45
+ # - IV is 12 bytes
46
+ # - Auth tag is 16 bytes
47
+ iv_size = 12
48
+ auth_tag_size = 16
49
+
50
+ # Extract the components
51
+ iv = data[0...iv_size]
52
+ auth_tag = data[iv_size...(iv_size + auth_tag_size)]
53
+ encrypted_data = data[(iv_size + auth_tag_size)..-1]
54
+
55
+ cipher = OpenSSL::Cipher::AES256.new(:GCM)
56
+ cipher.decrypt
57
+ cipher.key = OpenSSL::Digest::SHA256.digest(encryption_key)
58
+ cipher.iv = iv
59
+ cipher.auth_tag = auth_tag
60
+
61
+ cipher.update(encrypted_data) + cipher.final
62
+ rescue OpenSSL::Cipher::CipherError
63
+ raise DecryptionError, "Invalid key, corrupted file, or tampering detected"
64
+ end
65
+
66
+ private
67
+
68
+ attr_reader :encryption_key
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dotenvcrypt
4
+ module Core
5
+ class EnvLoader
6
+ def self.load_env(encrypted_file_path, key:)
7
+ raise ArgumentError, "File not found: #{encrypted_file_path}" unless File.exist?(encrypted_file_path)
8
+
9
+ # Read and decrypt
10
+ encrypted_data = File.read(encrypted_file_path)
11
+ encryptor = Encryptor.new(key)
12
+ decrypted_content = encryptor.decrypt(encrypted_data)
13
+
14
+ # Parse and load into ENV
15
+ parse_and_load_env(decrypted_content)
16
+ end
17
+
18
+ private
19
+
20
+ def self.parse_and_load_env(content)
21
+ loaded = {}
22
+
23
+ content.each_line do |line|
24
+ line = line.strip
25
+
26
+ # Skip comments and empty lines
27
+ next if line.empty? || line.start_with?('#')
28
+
29
+ # Parse KEY=value format
30
+ if line =~ /\A([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\z/
31
+ key = $1
32
+ value = $2
33
+
34
+ # Remove surrounding quotes if present (single or double)
35
+ value = value.gsub(/\A["']|["']\z/, '')
36
+
37
+ # Load into ENV
38
+ ENV[key] = value
39
+ loaded[key] = value
40
+ end
41
+ end
42
+
43
+ loaded
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dotenvcrypt
4
+ module Core
5
+ VERSION = "0.7.0"
6
+ end
7
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require 'openssl'
5
+ require_relative 'core/version'
6
+ require_relative 'core/encryptor'
7
+ require_relative 'core/env_loader'
8
+
9
+ module Dotenvcrypt
10
+ module Core
11
+ # Convenience method for loading encrypted env files
12
+ def self.load_env(encrypted_file_path, key:)
13
+ EnvLoader.load_env(encrypted_file_path, key: key)
14
+ end
15
+ end
16
+
17
+ # Also expose load_env at the top level for convenience
18
+ def self.load_env(encrypted_file_path, key:)
19
+ Core.load_env(encrypted_file_path, key: key)
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'dotenvcrypt/core'
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dotenvcrypt-core
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.0
5
+ platform: ruby
6
+ authors:
7
+ - Dan Loman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-12-30 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Pure Ruby library for encrypting and decrypting .env files using AES-256-GCM
14
+ email:
15
+ - daniel.loman@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - LICENSE
21
+ - README.md
22
+ - lib/dotenvcrypt-core.rb
23
+ - lib/dotenvcrypt/core.rb
24
+ - lib/dotenvcrypt/core/encryptor.rb
25
+ - lib/dotenvcrypt/core/env_loader.rb
26
+ - lib/dotenvcrypt/core/version.rb
27
+ homepage: https://github.com/namolnad/dotenvcrypt
28
+ licenses:
29
+ - MIT
30
+ metadata:
31
+ homepage_uri: https://github.com/namolnad/dotenvcrypt
32
+ source_code_uri: https://github.com/namolnad/dotenvcrypt
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: 2.5.0
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ requirements: []
48
+ rubygems_version: 3.5.22
49
+ signing_key:
50
+ specification_version: 4
51
+ summary: Core encryption/decryption library for dotenvcrypt
52
+ test_files: []