secrit 0.0.4 → 0.0.6
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 +4 -4
- data/lib/secrit.rb +74 -10
- data/test/secrit_test.rb +45 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6faa44d62bd340907b101bf6ba6e56837587d51638f8741452fcc27b5c12095
|
4
|
+
data.tar.gz: ce5893a67b02b928ac95a214151cf1bd3bd2daf7332ed2813f4d89798e4d6124
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f34ba5b85f46dd496c32a388aea79e29737748cead405b268f64c4923ebe91cb51ca58a48b476f8befdd012d2a7a2694be94d193412c502728d457e24f82d30
|
7
|
+
data.tar.gz: 2d476217fc7b85149af601e19d6af6471ff7155c8788ffa413e2b2196310d3f795eed4d68623d24f3b6515062c34e8ec6afd861e57538fcc9ecf6c483cbb5024
|
data/lib/secrit.rb
CHANGED
@@ -1,20 +1,84 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'gpgme'
|
3
3
|
|
4
|
-
|
4
|
+
# Decryptor provides an interface for decryption. Classes that extend Decryptor
|
5
|
+
# must implement the decrypt method.
|
6
|
+
class Decryptor
|
7
|
+
# Decrypts a file at the given path.
|
8
|
+
#
|
9
|
+
# @param file_path [String] the path to the file to be decrypted.
|
10
|
+
# @raise [NotImplementedError] if the method is called on the Decryptor class
|
11
|
+
# itself, rather than a subclass.
|
12
|
+
def decrypt(file_path)
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# GPGDecryptor is a default implementation of the Decryptor interface using GPG.
|
18
|
+
class GPGDecryptor < Decryptor
|
19
|
+
# Decrypts a file at the given path using GPG.
|
20
|
+
#
|
21
|
+
# @param file_path [String] the path to the file to be decrypted.
|
22
|
+
# @return [GPGME::Data] the decrypted data.
|
23
|
+
def decrypt(file_path)
|
24
|
+
crypto = GPGME::Crypto.new
|
25
|
+
decrypted_data = crypto.decrypt(File.open(file_path))
|
26
|
+
decrypted_data
|
27
|
+
end
|
28
|
+
end
|
5
29
|
|
30
|
+
# Secrit provides methods to get encrypted data, allowing optional customization
|
31
|
+
# of the decryption process.
|
6
32
|
class Secrit
|
7
|
-
|
8
|
-
full_path = File.join(PASSWORD_STORE_PATH, "#{entry_path}.gpg")
|
33
|
+
attr_accessor :storage
|
9
34
|
|
10
|
-
|
11
|
-
|
35
|
+
# Retrieves decrypted data for a given entry path.
|
36
|
+
#
|
37
|
+
# @param entry_path [String] the entry path to the encrypted data.
|
38
|
+
# @param storage [String] the storage path for the encrypted files (optional).
|
39
|
+
# @return [String] the decrypted content as a string.
|
40
|
+
def self.get(entry_path, storage: nil)
|
41
|
+
new(
|
42
|
+
storage: storage
|
43
|
+
).get(entry_path).to_s.strip
|
44
|
+
end
|
12
45
|
|
13
|
-
|
14
|
-
|
15
|
-
|
46
|
+
# Initializes a new Secrit object with optional customization.
|
47
|
+
#
|
48
|
+
# @param decryptor [Decryptor] an object that responds to the decrypt method
|
49
|
+
# (optional, defaults to GPGDecryptor.new).
|
50
|
+
# @param storage [String] the storage path for the encrypted files (optional).
|
51
|
+
def initialize(decryptor: GPGDecryptor.new, storage: nil)
|
52
|
+
@decryptor = decryptor
|
53
|
+
@storage = storage || File.expand_path("~/.password-store/")
|
54
|
+
end
|
55
|
+
|
56
|
+
# Retrieves decrypted data for a given entry path.
|
57
|
+
#
|
58
|
+
# @param entry_path [String] the entry path to the encrypted data.
|
59
|
+
# @return [GPGME::Data] the decrypted data.
|
60
|
+
# @raise [RuntimeError] if the file does not exist at the constructed path.
|
61
|
+
def get(entry_path)
|
62
|
+
full_path = construct_path(entry_path)
|
63
|
+
validate_file_existence(full_path)
|
64
|
+
@decryptor.decrypt(full_path)
|
65
|
+
end
|
16
66
|
|
17
|
-
|
18
|
-
|
67
|
+
private
|
68
|
+
|
69
|
+
# Constructs the full path to an encrypted file based on the entry path.
|
70
|
+
#
|
71
|
+
# @param entry_path [String] the entry path.
|
72
|
+
# @return [String] the full path to the encrypted file.
|
73
|
+
def construct_path(entry_path)
|
74
|
+
File.join(storage, "#{entry_path}.gpg")
|
75
|
+
end
|
76
|
+
|
77
|
+
# Validates that a file exists at the given path.
|
78
|
+
#
|
79
|
+
# @param full_path [String] the full path to the file.
|
80
|
+
# @raise [RuntimeError] if the file does not exist at the given path.
|
81
|
+
def validate_file_existence(full_path)
|
82
|
+
raise "File not found: #{full_path}" unless File.exist?(full_path)
|
19
83
|
end
|
20
84
|
end
|
data/test/secrit_test.rb
CHANGED
@@ -4,6 +4,30 @@ require 'mocha/minitest'
|
|
4
4
|
require_relative '../lib/secrit'
|
5
5
|
|
6
6
|
class SecritTest < Minitest::Test
|
7
|
+
def with_encrypted_file(contents, key_path = 'test_entry')
|
8
|
+
Dir.mktmpdir do |temp_dir|
|
9
|
+
# Create a temporary GPG file with known content
|
10
|
+
test_file_path = File.join(temp_dir, "#{key_path}.gpg")
|
11
|
+
file = File.open(test_file_path, 'w+')
|
12
|
+
|
13
|
+
crypto = GPGME::Crypto.new
|
14
|
+
crypto.encrypt(contents, output: file)
|
15
|
+
|
16
|
+
yield(temp_dir)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_real_decryption
|
21
|
+
# Create a temporary GPG file with known content
|
22
|
+
key_path = 'foo_bar'
|
23
|
+
|
24
|
+
with_encrypted_file('test content', key_path) do |storage|
|
25
|
+
# Run the get method and check the result
|
26
|
+
result = Secrit.get(key_path, storage: storage)
|
27
|
+
assert_equal "test content", result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
7
31
|
def test_successful_decryption
|
8
32
|
# Mocking the file existence check
|
9
33
|
File.stubs(:exist?).returns(true)
|
@@ -21,12 +45,32 @@ class SecritTest < Minitest::Test
|
|
21
45
|
assert_equal 'decrypted content', result
|
22
46
|
end
|
23
47
|
|
48
|
+
def test_successful_decryption_object
|
49
|
+
entry_path = "valid_entry_path"
|
50
|
+
expected_decrypted_content = "secret content"
|
51
|
+
|
52
|
+
# Create a mock decryptor
|
53
|
+
mock_decryptor = Minitest::Mock.new
|
54
|
+
mock_decryptor.expect(:decrypt, expected_decrypted_content, [String])
|
55
|
+
File.stubs(:exist?).returns(true)
|
56
|
+
|
57
|
+
# Create an instance of Secrit with the mock decryptor
|
58
|
+
secrit = Secrit.new(decryptor: mock_decryptor)
|
59
|
+
|
60
|
+
# Test the get method
|
61
|
+
decrypted_content = secrit.get(entry_path)
|
62
|
+
assert_equal expected_decrypted_content, decrypted_content
|
63
|
+
|
64
|
+
# Verify that the mock expectations were met
|
65
|
+
mock_decryptor.verify
|
66
|
+
end
|
67
|
+
|
24
68
|
def test_file_not_found
|
25
69
|
# Mocking the file existence check to return false
|
26
70
|
File.stubs(:exist?).returns(false)
|
27
71
|
|
28
72
|
# Testing the get method to ensure it raises the correct error
|
29
|
-
assert_raises(RuntimeError, "File not found: #{File.join(
|
73
|
+
assert_raises(RuntimeError, "File not found: #{File.join(Secrit.new.storage, 'non_existent_file.gpg')}") do
|
30
74
|
Secrit.get('non_existent_file')
|
31
75
|
end
|
32
76
|
end
|