crypt_keeper 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
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