-
Notifications
You must be signed in to change notification settings - Fork 101
/
Copy pathpostgres_pgp.rb
68 lines (60 loc) · 1.9 KB
/
postgres_pgp.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
module CryptKeeper
module Provider
class PostgresPgp < PostgresBase
attr_accessor :key
attr_accessor :pgcrypto_options
# Public: Initializes the encryptor
#
# options - A hash, :key is required
def initialize(options = {})
::ActiveSupport.run_load_hooks(:crypt_keeper_postgres_pgp_log, self)
@key = options.fetch(:key) do
raise ArgumentError, "Missing :key"
end
@pgcrypto_options = options.fetch(:pgcrypto_options, '')
end
# Public: Encrypts a string
#
# Returns an encrypted string
def encrypt(value)
rescue_invalid_statement do
escape_and_execute_sql(["SELECT pgp_sym_encrypt(?, ?, ?)",
value.to_s, key, pgcrypto_options])['pgp_sym_encrypt']
end
end
# Public: Decrypts a string
#
# Returns a plaintext string
def decrypt(value)
rescue_invalid_statement do
if encrypted?(value)
escape_and_execute_sql(["SELECT pgp_sym_decrypt(?, ?)",
value, key])['pgp_sym_decrypt']
else
value
end
end
end
def search(records, field, criteria)
if criteria.present?
records
.where.not("TRIM(BOTH FROM \"#{field}\") = ?", "")
.where("(pgp_sym_decrypt(cast(\"#{field}\" AS bytea), ?) = ?)",
key, criteria)
else
records.where(field => criteria)
end
end
private
# Private: Rescues and filters invalid statement errors. Run the code
# within a block for it to be rescued.
def rescue_invalid_statement
yield
rescue ActiveRecord::StatementInvalid => e
message = crypt_keeper_payload_parse(e.message)
message = crypt_keeper_filter_postgres_log(message)
raise ActiveRecord::StatementInvalid, message
end
end
end
end