crypt_keeper 1.1.0 → 1.1.1

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
  SHA1:
3
- metadata.gz: 93d4da07900ca51f6d83c1e1f8fb114d665a5221
4
- data.tar.gz: '035843dd610e41f98fff046550cb7845ecc088e0'
3
+ metadata.gz: 78d7a7f1ea679f9a1542a65b537a446065c9cd27
4
+ data.tar.gz: 518d78e7d4a80e07faa80b9eac9c3b268e2db2c8
5
5
  SHA512:
6
- metadata.gz: 2baadc47a82dca8346a4c90fbb1ebbe7992fee8d58a7beb771223fbb0fdbe8986a14000dbd2b35d7878233812a38fd56b02b73ca328865f9177120a48edd6118
7
- data.tar.gz: 59270976cc0c52b01ce4540255637e94b26bcc2a88f53d0e04398456f4335384df6a0cc842a1ad6b648060cd968876a3d7c4351630a371b5dd1b6897d9572111
6
+ metadata.gz: 30b9ccbea99c9ac89ee4bf4c9df73fc0b95e2ae3f65aca3e9936a95bd406d271e672e73cefa2c717a2f0c057c638ca876a238c7058da2c3ad6e3f2d2d12720cb
7
+ data.tar.gz: 07f33f2caca79c5be2c45f2365601e8939b5c64200fba53c00de3e70a9d6b221a68efe47aad00fc7b42003bce2c964ce68701656966149afe4b65dfc45a4e0a7
@@ -6,6 +6,7 @@ require 'crypt_keeper/helper'
6
6
  require 'crypt_keeper/provider/base'
7
7
  require 'crypt_keeper/provider/aes_new'
8
8
  require 'crypt_keeper/provider/mysql_aes_new'
9
+ require 'crypt_keeper/provider/postgres_base'
9
10
  require 'crypt_keeper/provider/postgres_pgp'
10
11
  require 'crypt_keeper/provider/postgres_pgp_public_key'
11
12
 
@@ -3,10 +3,38 @@ module CryptKeeper
3
3
  module SQL
4
4
  private
5
5
 
6
- # Private: Sanitize an sql query and then execute it
7
- def escape_and_execute_sql(query)
6
+ # Private: Sanitize an sql query and then execute it.
7
+ #
8
+ # query - the sql query
9
+ # new_transaction - if the query should run inside a new transaction
10
+ #
11
+ # Returns the ActiveRecord response.
12
+ def escape_and_execute_sql(query, new_transaction: false)
8
13
  query = ::ActiveRecord::Base.send :sanitize_sql_array, query
9
- ::ActiveRecord::Base.connection.execute(query).first
14
+
15
+ if CryptKeeper.silence_logs?
16
+ ::ActiveRecord::Base.logger.silence do
17
+ execute_sql(query, new_transaction: new_transaction)
18
+ end
19
+ else
20
+ execute_sql(query, new_transaction: new_transaction)
21
+ end
22
+ end
23
+
24
+ # Private: Executes the query.
25
+ #
26
+ # query - the sql query
27
+ # new_transaction - if the query should run inside a new transaction
28
+ #
29
+ # Returns an Array.
30
+ def execute_sql(query, new_transaction: false)
31
+ if new_transaction
32
+ ::ActiveRecord::Base.transaction(requires_new: true) do
33
+ ::ActiveRecord::Base.connection.execute(query).first
34
+ end
35
+ else
36
+ ::ActiveRecord::Base.connection.execute(query).first
37
+ end
10
38
  end
11
39
  end
12
40
 
@@ -14,8 +14,6 @@ module CryptKeeper
14
14
  payload = event.payload[:sql]
15
15
  .encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
16
16
 
17
- return if CryptKeeper.silence_logs? && payload =~ filter
18
-
19
17
  event.payload[:sql] = payload.gsub(filter) do |_|
20
18
  "#{$1}([FILTERED])"
21
19
  end
@@ -4,7 +4,7 @@ require 'active_support/lazy_load_hooks'
4
4
  module CryptKeeper
5
5
  module LogSubscriber
6
6
  module PostgresPgp
7
- FILTER = /(\(*)pgp_(sym|pub)_(?<operation>decrypt|encrypt)(\(+.*\)+)/im
7
+ FILTER = /(\(*)(?<operation>pgp_sym_encrypt|pgp_sym_decrypt|pgp_pub_encrypt|pgp_pub_decrypt|pgp_key_id)(\(+.*\)+)/im
8
8
 
9
9
  # Public: Prevents sensitive data from being logged
10
10
  #
@@ -13,9 +13,6 @@ module CryptKeeper
13
13
  # Returns a boolean.
14
14
  def sql(event)
15
15
  payload = crypt_keeper_payload_parse(event.payload[:sql])
16
-
17
- return if CryptKeeper.silence_logs? && payload =~ FILTER
18
-
19
16
  event.payload[:sql] = crypt_keeper_filter_postgres_log(payload)
20
17
  super(event)
21
18
  end
@@ -0,0 +1,28 @@
1
+ require 'crypt_keeper/log_subscriber/postgres_pgp'
2
+
3
+ module CryptKeeper
4
+ module Provider
5
+ class PostgresBase < Base
6
+ include CryptKeeper::Helper::SQL
7
+ include CryptKeeper::LogSubscriber::PostgresPgp
8
+
9
+ INVALID_DATA_ERROR = "Wrong key or corrupt data".freeze
10
+
11
+ # Public: Checks if value is already encrypted.
12
+ #
13
+ # Returns boolean
14
+ def encrypted?(value)
15
+ begin
16
+ escape_and_execute_sql(["SELECT pgp_key_id(?)", value.to_s],
17
+ new_transaction: true)['pgp_key_id'].present?
18
+ rescue ActiveRecord::StatementInvalid => e
19
+ if e.message.include?(INVALID_DATA_ERROR)
20
+ false
21
+ else
22
+ raise
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,11 +1,6 @@
1
- require 'crypt_keeper/log_subscriber/postgres_pgp'
2
-
3
1
  module CryptKeeper
4
2
  module Provider
5
- class PostgresPgp < Base
6
- include CryptKeeper::Helper::SQL
7
- include CryptKeeper::LogSubscriber::PostgresPgp
8
-
3
+ class PostgresPgp < PostgresBase
9
4
  attr_accessor :key
10
5
  attr_accessor :pgcrypto_options
11
6
 
@@ -37,8 +32,12 @@ module CryptKeeper
37
32
  # Returns a plaintext string
38
33
  def decrypt(value)
39
34
  rescue_invalid_statement do
40
- escape_and_execute_sql(["SELECT pgp_sym_decrypt(?, ?)",
41
- value, key])['pgp_sym_decrypt']
35
+ if encrypted?(value)
36
+ escape_and_execute_sql(["SELECT pgp_sym_decrypt(?, ?)",
37
+ value, key])['pgp_sym_decrypt']
38
+ else
39
+ value
40
+ end
42
41
  end
43
42
  end
44
43
 
@@ -1,10 +1,6 @@
1
- require 'crypt_keeper/log_subscriber/postgres_pgp'
2
-
3
1
  module CryptKeeper
4
2
  module Provider
5
- class PostgresPgpPublicKey < Base
6
- include CryptKeeper::Helper::SQL
7
-
3
+ class PostgresPgpPublicKey < PostgresBase
8
4
  attr_accessor :key
9
5
 
10
6
  def initialize(options = {})
@@ -33,25 +29,13 @@ module CryptKeeper
33
29
  #
34
30
  # Returns a plaintext string
35
31
  def decrypt(value)
36
- if @private_key.present?
37
- escape_and_execute_sql(["SELECT pgp_pub_decrypt(?, dearmor(?), ?)", value, @private_key, @key])['pgp_pub_decrypt']
32
+ if @private_key.present? && encrypted?(value)
33
+ escape_and_execute_sql(["SELECT pgp_pub_decrypt(?, dearmor(?), ?)",
34
+ value, @private_key, @key])['pgp_pub_decrypt']
38
35
  else
39
36
  value
40
37
  end
41
38
  end
42
-
43
- # Public: Attempts to extract a PGP key id. If it's successful, it returns true
44
- #
45
- # Returns boolean
46
- def encrypted?(value)
47
- begin
48
- ActiveRecord::Base.transaction(requires_new: true) do
49
- escape_and_execute_sql(["SELECT pgp_key_id(?)", value.to_s])['pgp_key_id'].present?
50
- end
51
- rescue ActiveRecord::StatementInvalid
52
- false
53
- end
54
- end
55
39
  end
56
40
  end
57
41
  end
@@ -1,3 +1,3 @@
1
1
  module CryptKeeper
2
- VERSION = "1.1.0"
2
+ VERSION = "1.1.1"
3
3
  end
@@ -46,11 +46,5 @@ describe CryptKeeper::LogSubscriber::MysqlAes do
46
46
 
47
47
  should_log_scrubbed_query(input: input_query, output: output_query)
48
48
  end
49
-
50
- it "skips logging if CryptKeeper.silence_logs is set" do
51
- CryptKeeper.silence_logs = true
52
-
53
- should_not_log_query(input_query)
54
- end
55
49
  end
56
50
  end
@@ -13,44 +13,32 @@ describe CryptKeeper::LogSubscriber::PostgresPgp do
13
13
  CryptKeeper::Provider::PostgresPgp.new key: 'secret'
14
14
  end
15
15
 
16
- let(:input_query) do
17
- "SELECT pgp_sym_encrypt('encrypt_value', 'encrypt_key'), pgp_sym_decrypt('decrypt_value', 'decrypt_key') FROM DUAL;"
18
- end
19
-
20
- let(:output_query) do
21
- "SELECT encrypt([FILTERED]) FROM DUAL;"
22
- end
23
-
24
- let(:input_search_query) do
25
- "SELECT \"sensitive_data\".* FROM \"sensitive_data\" WHERE ((pgp_sym_decrypt('f'), 'tool') = 'blah')) AND secret = 'testing'"
26
- end
27
-
28
- let(:output_search_query) do
29
- "SELECT \"sensitive_data\".* FROM \"sensitive_data\" WHERE decrypt([FILTERED]) AND secret = 'testing'"
30
- end
16
+ let(:queries) {
17
+ {
18
+ "SELECT pgp_sym_encrypt('encrypt_value', 'encrypt_key') FROM DUAL;" => "SELECT pgp_sym_encrypt([FILTERED]) FROM DUAL;",
19
+ "SELECT pgp_sym_decrypt('encrypt_value') FROM DUAL;" => "SELECT pgp_sym_decrypt([FILTERED]) FROM DUAL;",
20
+ "SELECT pgp_key_id('encrypt_value') FROM DUAL;" => "SELECT pgp_key_id([FILTERED]) FROM DUAL;",
21
+ "SELECT \"sensitive_data\".* FROM \"sensitive_data\" WHERE ((pgp_sym_decrypt('f'), 'tool') = 'blah')) AND secret = 'testing'" => "SELECT \"sensitive_data\".* FROM \"sensitive_data\" WHERE pgp_sym_decrypt([FILTERED]) AND secret = 'testing'",
22
+ }
23
+ }
31
24
 
32
25
  it "filters pgp functions" do
33
- should_log_scrubbed_query(input: input_query, output: output_query)
26
+ queries.each do |k, v|
27
+ should_log_scrubbed_query(input: k, output: v)
28
+ end
34
29
  end
35
30
 
36
31
  it "filters pgp functions in lowercase" do
37
- should_log_scrubbed_query(input: input_query.downcase, output: output_query.downcase.gsub(/filtered/, 'FILTERED'))
38
- end
39
-
40
- it "filters pgp functions when searching" do
41
- should_log_scrubbed_query(input: input_search_query, output: output_search_query)
32
+ queries.each do |k, v|
33
+ should_log_scrubbed_query(input: k.downcase, output: v.downcase.gsub(/filtered/, 'FILTERED'))
34
+ end
42
35
  end
43
36
 
44
37
  it "forces string encodings" do
45
- input_query = "SELECT pgp_sym_encrypt('hi \255', 'test') FROM DUAL;"
46
-
47
- should_log_scrubbed_query(input: input_query, output: output_query)
48
- end
49
-
50
- it "skips logging if CryptKeeper.silence_logs is set" do
51
- CryptKeeper.silence_logs = true
52
-
53
- should_not_log_query(input_query)
38
+ queries.each do |k, v|
39
+ k = "#{k}\255"
40
+ should_log_scrubbed_query(input: k, output: v)
41
+ end
54
42
  end
55
43
  end
56
44
 
@@ -68,27 +56,23 @@ describe CryptKeeper::LogSubscriber::PostgresPgp do
68
56
  CryptKeeper::Provider::PostgresPgpPublicKey.new key: 'secret', public_key: public_key, private_key: private_key
69
57
  end
70
58
 
71
- let(:input_query) do
72
- "SELECT pgp_pub_encrypt('test', dearmor('#{public_key}
73
- '))"
74
- end
75
-
76
- let(:output_query) do
77
- "SELECT encrypt([FILTERED])"
78
- end
59
+ let(:queries) {
60
+ {
61
+ "SELECT pgp_pub_encrypt('test', dearmor('#{public_key}')) FROM DUAL;" => "SELECT pgp_pub_encrypt([FILTERED]) FROM DUAL;",
62
+ "SELECT pgp_pub_decrypt('test', dearmor('#{public_key}'), '#{private_key}') FROM DUAL;" => "SELECT pgp_pub_decrypt([FILTERED]) FROM DUAL;",
63
+ }
64
+ }
79
65
 
80
66
  it "filters pgp functions" do
81
- should_log_scrubbed_query(input: input_query, output: output_query)
67
+ queries.each do |k, v|
68
+ should_log_scrubbed_query(input: k, output: v)
69
+ end
82
70
  end
83
71
 
84
72
  it "filters pgp functions in lowercase" do
85
- should_log_scrubbed_query(input: input_query.downcase, output: output_query.downcase.gsub(/filtered/, 'FILTERED'))
86
- end
87
-
88
- it "skips logging if CryptKeeper.silence_logs is set" do
89
- CryptKeeper.silence_logs = true
90
-
91
- should_not_log_query(input_query)
73
+ queries.each do |k, v|
74
+ should_log_scrubbed_query(input: k.downcase, output: v.downcase.gsub(/filtered/, 'FILTERED'))
75
+ end
92
76
  end
93
77
  end
94
78
  end
@@ -47,6 +47,7 @@ describe CryptKeeper::Provider::PostgresPgpPublicKey do
47
47
  describe "#decrypt" do
48
48
  specify { expect(subject.decrypt(cipher_text)).to eq(plain_text) }
49
49
  specify { expect(subject.decrypt(integer_cipher_text)).to eq(integer_plain_text.to_s) }
50
+ specify { expect(subject.decrypt(plain_text)).to eq(plain_text) }
50
51
 
51
52
  it "does not decrypt w/o private key" do
52
53
  pgp = described_class.new key: ENCRYPTION_PASSWORD, public_key: public_key
@@ -44,6 +44,7 @@ describe CryptKeeper::Provider::PostgresPgp do
44
44
  describe "#decrypt" do
45
45
  specify { expect(subject.decrypt(cipher_text)).to eq(plain_text) }
46
46
  specify { expect(subject.decrypt(integer_cipher_text)).to eq(integer_plain_text.to_s) }
47
+ specify { expect(subject.decrypt(plain_text)).to eq(plain_text) }
47
48
 
48
49
  it "filters StatementInvalid errors" do
49
50
  begin
@@ -47,11 +47,8 @@ module CryptKeeper
47
47
  def should_log_scrubbed_query(input:, output:)
48
48
  queries = sql(input)
49
49
 
50
- valid_input = queries.none? { |line| line.include? input }
51
- expect(valid_input).to eq(true), "found unscrubbed SQL query logged!"
52
-
53
- valid_output = queries.any? { |line| line.include? output }
54
- expect(valid_output).to eq(true), "output query was not logged!"
50
+ expect(queries.join("\n")).to_not include(input)
51
+ expect(queries.join("\n")).to include(output)
55
52
  end
56
53
 
57
54
  # Public: Verifies that the given input query was not logged.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crypt_keeper
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Mazzi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-25 00:00:00.000000000 Z
11
+ date: 2017-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -245,6 +245,7 @@ files:
245
245
  - lib/crypt_keeper/provider/aes_new.rb
246
246
  - lib/crypt_keeper/provider/base.rb
247
247
  - lib/crypt_keeper/provider/mysql_aes_new.rb
248
+ - lib/crypt_keeper/provider/postgres_base.rb
248
249
  - lib/crypt_keeper/provider/postgres_pgp.rb
249
250
  - lib/crypt_keeper/provider/postgres_pgp_public_key.rb
250
251
  - lib/crypt_keeper/version.rb