squelch 0.1.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +88 -0
- data/lib/squelch.rb +109 -0
- data/lib/squelch/database.rb +101 -0
- data/lib/squelch/error.rb +28 -0
- data/lib/squelch/pairs.rb +11 -0
- data/lib/squelch/patterns.rb +81 -0
- data/lib/squelch/version.rb +6 -0
- metadata +60 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 3882fdd525cffcfe62b3ac46dac3af8ebce60ea3c83e69315be51ac211dce232
|
|
4
|
+
data.tar.gz: 7e82cc70e6341afd6de48aa8d67c55d4ce618d06f62e52aff7c4fdd6f1c202cc
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 6bd3863b88e5ed602d2f632c4f67c6f339032d743d47281b8a0041dfb2e0ff47b335426c8dfbb88cc15e1ff8d7b2c82b37c7d0e58e102e597a6cc4a0a08021b0
|
|
7
|
+
data.tar.gz: 3c48c016f881d621db4ddad51883e29b5cf5ac8aa2db58baaf225904d1a46633e26489b8f6de6c274556f401d931082296911f423f3e62c2f74040e95a209fda
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Alex Vondrak
|
|
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,88 @@
|
|
|
1
|
+
# Squelch
|
|
2
|
+
|
|
3
|
+
[](https://github.com/ajvondrak/squelch/actions?query=workflow%3Abuild)
|
|
4
|
+
[](https://coveralls.io/github/ajvondrak/squelch?branch=main)
|
|
5
|
+
|
|
6
|
+
Squelch squelches SQL!
|
|
7
|
+
|
|
8
|
+
```sql
|
|
9
|
+
-- Before
|
|
10
|
+
INSERT INTO users(name, address, phone) VALUES ("John Doe", "1600 Pennsylvania Ave", "867-5309");
|
|
11
|
+
|
|
12
|
+
-- After
|
|
13
|
+
INSERT INTO users(name, address, phone) VALUES (?, ?, ?);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This gem is a purposefully simple string obfuscator. It aims to replace every data literal in a SQL query with a `?` placeholder, as though it were a prepared statement. The result should still be readable SQL, but without the risk of leaking potentially sensitive information.
|
|
17
|
+
|
|
18
|
+
The code was originally adapted from the [`NewRelic::Agent::Database::ObfuscationHelpers`](https://github.com/newrelic/newrelic-ruby-agent/blob/f0290ab6468ad205dd014d63c794883dc47eebe7/lib/new_relic/agent/database/obfuscation_helpers.rb) in the [newrelic\_rpm](https://rubygems.org/gems/newrelic_rpm) gem. By abstracting out these low-level implementation details, the hope is that Squelch can empower other libraries to easily sanitize their SQL logs.
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
Add this line to your application's Gemfile:
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
gem "squelch"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
and then install it with `bundle install`.
|
|
29
|
+
|
|
30
|
+
Alternatively, you could install it to your system's gems with:
|
|
31
|
+
|
|
32
|
+
```console
|
|
33
|
+
$ gem install squelch
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
### Basic interface
|
|
39
|
+
|
|
40
|
+
The main API is the `Squelch.obfuscate` method, which takes in your SQL string and returns an obfuscated version of it.
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
Squelch.obfuscate("SELECT * FROM social_security_cards WHERE number = 'pii';")
|
|
44
|
+
|
|
45
|
+
#=> "SELECT * FROM social_security_cards WHERE number = ?;"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
This method is powered by regular expression patterns, some of which correspond to particular database systems. For example, Postgres supports a unique [dollar quoting](https://www.postgresql.org/docs/13/sql-syntax-lexical.html#SQL-SYNTAX-DOLLAR-QUOTING) syntax, while Oracle has its own [Q quoting](https://livesql.oracle.com/apex/livesql/file/content_CIREYU9EA54EOKQ7LAMZKRF6P.html) syntax. If possible, try to always supply the optional `db:` keyword parameter with a symbol corresponding to your RDMS. The currently supported options are `:mysql`, `:postgres`, `:sqlite`, `:oracle`, and `:cassandra`, but any other option will fall back safely to a generic default pattern.
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
Squelch.obfuscate("SELECT * FROM credit_cards WHERE number = $pii$ ... $pii$;", db: :postgres)
|
|
52
|
+
|
|
53
|
+
#=> "SELECT * FROM credit_cards WHERE number = ?;"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```ruby
|
|
57
|
+
Squelch.obfuscate("SELECT * FROM phones WHERE number = q'<pii>';", db: :oracle)
|
|
58
|
+
|
|
59
|
+
#=> "SELECT * FROM phones WHERE number = ?;"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Handling errors
|
|
63
|
+
|
|
64
|
+
When there's an issue with squelching the SQL, we don't want to risk of using the problematic results that might still be leaking PII. The error-safe `Squelch.obfuscate` method returns a single `?` placeholder in the event of an issue, but Squelch has the error-raising variant `Squelch.obfuscate!` as well.
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
Squelch.obfuscate("SELECT * FROM table WHERE pii = 'a string missing a closing quote;")
|
|
68
|
+
|
|
69
|
+
#=> "?"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
Squelch.obfuscate!("SELECT * FROM table WHERE pii = 'a string missing a closing quote;")
|
|
74
|
+
|
|
75
|
+
#=> Squelch::Error: Failed to squelch SQL, delimiter ' remained after obfuscation
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
If you rescue the `Squelch::Error`, you can access the problematic obfuscation result in `Squelch::Error#obfuscation`.
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
81
|
+
begin
|
|
82
|
+
Squelch.obfuscate!("SELECT * FROM users WHERE id = 12345 AND name = 'Mister Danglin' Quote';")
|
|
83
|
+
rescue Squelch::Error => e
|
|
84
|
+
e.obfuscation
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
#=> "SELECT * FROM users WHERE id = ? AND name = ? Quote';"
|
|
88
|
+
```
|
data/lib/squelch.rb
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "squelch/version"
|
|
4
|
+
require "squelch/pairs"
|
|
5
|
+
require "squelch/patterns"
|
|
6
|
+
require "squelch/database"
|
|
7
|
+
require "squelch/error"
|
|
8
|
+
|
|
9
|
+
# A simple SQL obfuscator.
|
|
10
|
+
#
|
|
11
|
+
# The goal of {Squelch} is to replace every data literal in any given SQL
|
|
12
|
+
# string with a placeholder `?`. This removes any potentially sensitive values
|
|
13
|
+
# by removing *all* values, making the SQL read like it was a prepared
|
|
14
|
+
# statement all along.
|
|
15
|
+
#
|
|
16
|
+
# However, this process might produce bad results if there's a bug or you give
|
|
17
|
+
# a malformed SQL query. One heuristic we use to try to catch these cases is to
|
|
18
|
+
# look at the end result: are there any unmatched delimiters left over? Since
|
|
19
|
+
# obfuscation should remove *all* strings and comments, any dangling quotes or
|
|
20
|
+
# `/*` markers or such would indicate that either:
|
|
21
|
+
#
|
|
22
|
+
# * the SQL query had mismatched delimiter pairs in the first place, or
|
|
23
|
+
# * the obfuscation patterns failed to parse all the data literals correctly.
|
|
24
|
+
#
|
|
25
|
+
# Either way, we should be cautious of using either the original or the
|
|
26
|
+
# improperly-obfuscated query, since both may still contain sensitive
|
|
27
|
+
# information. To deal with these issues, we have both the error-safe
|
|
28
|
+
# {Squelch.obfuscate} and the error-raising {Squelch.obfuscate!}.
|
|
29
|
+
#
|
|
30
|
+
# Both methods not only accept a string of SQL, but optionally a specific
|
|
31
|
+
# database driver. This is because certain databases have their own special
|
|
32
|
+
# syntax. For example, Postgres uses double quotes around table names and
|
|
33
|
+
# supports `$$dollar quoted$$` strings, whereas MySQL uses backticks around
|
|
34
|
+
# table names and supports `"double quoted"` strings.
|
|
35
|
+
#
|
|
36
|
+
# To stand the best chance of scrubbing all sensitive values from your SQL, you
|
|
37
|
+
# should provide the specific database that you're using. That way, {Squelch}
|
|
38
|
+
# can make tweaks to its internal pattern matching. The default just tries to
|
|
39
|
+
# match all possible special cases, but that may wind up obfuscating too much
|
|
40
|
+
# or even being less performant than a more specific option.
|
|
41
|
+
#
|
|
42
|
+
# @example Basic obfuscation
|
|
43
|
+
# Squelch.obfuscate("SELECT * FROM examples WHERE name = 'basic';")
|
|
44
|
+
# #=> "SELECT * FROM examples WHERE name = ?;"
|
|
45
|
+
#
|
|
46
|
+
# @example Malformed query
|
|
47
|
+
# Squelch.obfuscate("SELECT * FROM examples WHERE name = ''malformed';")
|
|
48
|
+
# #=> "?"
|
|
49
|
+
#
|
|
50
|
+
# begin
|
|
51
|
+
# Squelch.obfuscate!("SELECT * FROM examples WHERE name = ''malformed';")
|
|
52
|
+
# rescue Squelch::Error => e
|
|
53
|
+
# puts e.message
|
|
54
|
+
# puts
|
|
55
|
+
# puts e.obfuscation
|
|
56
|
+
# end
|
|
57
|
+
# # Failed to squelch SQL, delimiter ' remained after obfuscation
|
|
58
|
+
# #
|
|
59
|
+
# # SELECT * FROM examples WHERE name = ?malformed';
|
|
60
|
+
#
|
|
61
|
+
# @example Using database-specific syntax
|
|
62
|
+
# Squelch.obfuscate(
|
|
63
|
+
# 'SELECT "examples".name FROM examples WHERE db = $$postgres$$;',
|
|
64
|
+
# db: :mysql,
|
|
65
|
+
# )
|
|
66
|
+
# #=> "SELECT ?.name FROM examples WHERE db = $$postgres$$;"
|
|
67
|
+
#
|
|
68
|
+
# Squelch.obfuscate(
|
|
69
|
+
# 'SELECT "examples".name FROM examples WHERE db = $$postgres$$;',
|
|
70
|
+
# db: :postgres,
|
|
71
|
+
# )
|
|
72
|
+
# #=> 'SELECT "examples".name FROM examples WHERE db = ?;'
|
|
73
|
+
module Squelch
|
|
74
|
+
# Obfuscates a SQL query.
|
|
75
|
+
#
|
|
76
|
+
# If the resulting obfuscation still has dangling delimiters left over, we
|
|
77
|
+
# return a single placeholder for the whole query, `?`. In order to get more
|
|
78
|
+
# information about such errors, you should use {.obfuscate!}.
|
|
79
|
+
#
|
|
80
|
+
# @param sql [String] an unobfuscated SQL query
|
|
81
|
+
#
|
|
82
|
+
# @param db [Symbol] the specific database syntax being used; supports
|
|
83
|
+
# `:mysql`, `:postgres`, `:sqlite`, `:oracle`, `:oracle`, or `:cassandra`,
|
|
84
|
+
# while anything else will be treated as `:default`
|
|
85
|
+
#
|
|
86
|
+
# @return [String] the obfuscated SQL query
|
|
87
|
+
def self.obfuscate(sql, db: :default)
|
|
88
|
+
obfuscate!(sql, db: db)
|
|
89
|
+
rescue Error
|
|
90
|
+
"?"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Obfuscates a SQL query, raising an error if there are issues.
|
|
94
|
+
#
|
|
95
|
+
# If the resulting obfuscation still has dangling delimiters left over, we
|
|
96
|
+
# raise {Squelch::Error} with more information about what went wrong. If you
|
|
97
|
+
# don't care about the details and just want some canonical string output,
|
|
98
|
+
# you should use {.obfuscate}.
|
|
99
|
+
#
|
|
100
|
+
# @param (see .obfuscate)
|
|
101
|
+
# @return (see .obfuscate)
|
|
102
|
+
# @raise [Squelch::Error] if obfuscation didn't remove all delimiters
|
|
103
|
+
def self.obfuscate!(sql, db: :default)
|
|
104
|
+
sql.gsub(Database.pattern(db), "?").tap do |obfuscated|
|
|
105
|
+
mismatched = obfuscated.match(Database.pairs(db))
|
|
106
|
+
raise Error.new(sql, mismatched) if mismatched
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Squelch
|
|
4
|
+
# @private
|
|
5
|
+
module Database
|
|
6
|
+
PATTERNS = {
|
|
7
|
+
mysql: Regexp.union(
|
|
8
|
+
Patterns::SINGLE_QUOTED,
|
|
9
|
+
Patterns::DOUBLE_QUOTED,
|
|
10
|
+
Patterns::NUMBER,
|
|
11
|
+
Patterns::BOOLEAN,
|
|
12
|
+
Patterns::HEXADECIMAL,
|
|
13
|
+
Patterns::LINE_COMMENT,
|
|
14
|
+
Patterns::BLOCK_COMMENT,
|
|
15
|
+
).freeze,
|
|
16
|
+
postgres: Regexp.union(
|
|
17
|
+
Patterns::SINGLE_QUOTED,
|
|
18
|
+
Patterns::DOLLAR_QUOTED,
|
|
19
|
+
Patterns::UUID,
|
|
20
|
+
Patterns::NUMBER,
|
|
21
|
+
Patterns::BOOLEAN,
|
|
22
|
+
Patterns::LINE_COMMENT,
|
|
23
|
+
Patterns::BLOCK_COMMENT,
|
|
24
|
+
).freeze,
|
|
25
|
+
sqlite: Regexp.union(
|
|
26
|
+
Patterns::SINGLE_QUOTED,
|
|
27
|
+
Patterns::NUMBER,
|
|
28
|
+
Patterns::BOOLEAN,
|
|
29
|
+
Patterns::HEXADECIMAL,
|
|
30
|
+
Patterns::LINE_COMMENT,
|
|
31
|
+
Patterns::BLOCK_COMMENT,
|
|
32
|
+
).freeze,
|
|
33
|
+
oracle: Regexp.union(
|
|
34
|
+
Patterns::SINGLE_QUOTED,
|
|
35
|
+
Patterns::ORACLE_QUOTED,
|
|
36
|
+
Patterns::NUMBER,
|
|
37
|
+
Patterns::LINE_COMMENT,
|
|
38
|
+
Patterns::BLOCK_COMMENT,
|
|
39
|
+
).freeze,
|
|
40
|
+
cassandra: Regexp.union(
|
|
41
|
+
Patterns::SINGLE_QUOTED,
|
|
42
|
+
Patterns::UUID,
|
|
43
|
+
Patterns::NUMBER,
|
|
44
|
+
Patterns::BOOLEAN,
|
|
45
|
+
Patterns::HEXADECIMAL,
|
|
46
|
+
Patterns::LINE_COMMENT,
|
|
47
|
+
Patterns::BLOCK_COMMENT,
|
|
48
|
+
).freeze,
|
|
49
|
+
default: Regexp.union(
|
|
50
|
+
Patterns::SINGLE_QUOTED,
|
|
51
|
+
Patterns::DOUBLE_QUOTED,
|
|
52
|
+
Patterns::DOLLAR_QUOTED,
|
|
53
|
+
Patterns::UUID,
|
|
54
|
+
Patterns::NUMBER,
|
|
55
|
+
Patterns::BOOLEAN,
|
|
56
|
+
Patterns::HEXADECIMAL,
|
|
57
|
+
Patterns::LINE_COMMENT,
|
|
58
|
+
Patterns::BLOCK_COMMENT,
|
|
59
|
+
Patterns::ORACLE_QUOTED,
|
|
60
|
+
).freeze,
|
|
61
|
+
}.freeze
|
|
62
|
+
|
|
63
|
+
def self.pattern(db)
|
|
64
|
+
PATTERNS[db] || PATTERNS[:default]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
PAIRS = {
|
|
68
|
+
mysql: Regexp.union(
|
|
69
|
+
Pairs::SINGLE_QUOTED,
|
|
70
|
+
Pairs::DOUBLE_QUOTED,
|
|
71
|
+
Pairs::BLOCK_COMMENT,
|
|
72
|
+
),
|
|
73
|
+
postgres: Regexp.union(
|
|
74
|
+
Pairs::SINGLE_QUOTED,
|
|
75
|
+
Pairs::DOLLAR_QUOTED,
|
|
76
|
+
Pairs::BLOCK_COMMENT,
|
|
77
|
+
),
|
|
78
|
+
sqlite: Regexp.union(
|
|
79
|
+
Pairs::SINGLE_QUOTED,
|
|
80
|
+
Pairs::BLOCK_COMMENT,
|
|
81
|
+
),
|
|
82
|
+
cassandra: Regexp.union(
|
|
83
|
+
Pairs::SINGLE_QUOTED,
|
|
84
|
+
Pairs::BLOCK_COMMENT,
|
|
85
|
+
),
|
|
86
|
+
oracle: Regexp.union(
|
|
87
|
+
Pairs::SINGLE_QUOTED,
|
|
88
|
+
Pairs::BLOCK_COMMENT,
|
|
89
|
+
),
|
|
90
|
+
default: Regexp.union(
|
|
91
|
+
Pairs::SINGLE_QUOTED,
|
|
92
|
+
Pairs::DOUBLE_QUOTED,
|
|
93
|
+
Pairs::BLOCK_COMMENT,
|
|
94
|
+
),
|
|
95
|
+
}.freeze
|
|
96
|
+
|
|
97
|
+
def self.pairs(db)
|
|
98
|
+
PAIRS[db] || PAIRS[:default]
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Squelch
|
|
4
|
+
# Raised by {Squelch.obfuscate!} if obfuscation seems to have failed.
|
|
5
|
+
#
|
|
6
|
+
# This might be raised either because the SQL was malformed in the first
|
|
7
|
+
# place or because of a bug in our parsing. See {Squelch} for more
|
|
8
|
+
# discussion.
|
|
9
|
+
class Error < StandardError
|
|
10
|
+
# @return [String] the original SQL input
|
|
11
|
+
attr_reader :sql
|
|
12
|
+
|
|
13
|
+
# @return [String] the invalid result of obfuscating {#sql}
|
|
14
|
+
attr_reader :obfuscation
|
|
15
|
+
|
|
16
|
+
# @return [String] the left over delimiter detected in {#obfuscation}
|
|
17
|
+
attr_reader :delimiter
|
|
18
|
+
|
|
19
|
+
def initialize(sql, mismatched)
|
|
20
|
+
@sql = sql
|
|
21
|
+
@obfuscation = mismatched.string
|
|
22
|
+
@delimiter = mismatched.to_s
|
|
23
|
+
super(<<~MSG.strip)
|
|
24
|
+
Failed to squelch SQL, delimiter #{delimiter} remained after obfuscation
|
|
25
|
+
MSG
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Squelch
|
|
4
|
+
# @private
|
|
5
|
+
module Patterns
|
|
6
|
+
ORACLE_QUOTED = Regexp.union(
|
|
7
|
+
/q'\<.*?\>'/m, # q'<text>'
|
|
8
|
+
/q'\[.*?\]'/m, # q'[text]'
|
|
9
|
+
/q'\{.*?\}'/m, # q'{text}'
|
|
10
|
+
/q'\(.*?\)'/m, # q'(text)'
|
|
11
|
+
).freeze
|
|
12
|
+
|
|
13
|
+
SINGLE_QUOTED = %r{
|
|
14
|
+
' # a single quote
|
|
15
|
+
(?: # followed by zero or more
|
|
16
|
+
[^'] # non-quote characters
|
|
17
|
+
| # or
|
|
18
|
+
'' # escaped quotes
|
|
19
|
+
)*? #
|
|
20
|
+
(?: # and closed by either
|
|
21
|
+
\\'.* # a literal backslash at the end of the string
|
|
22
|
+
| # or
|
|
23
|
+
'(?!') # one non-escaped quote
|
|
24
|
+
) #
|
|
25
|
+
}mx.freeze
|
|
26
|
+
|
|
27
|
+
DOUBLE_QUOTED = %r{
|
|
28
|
+
" # a double quote
|
|
29
|
+
(?: # followed by zero or more
|
|
30
|
+
[^"] # non-quote characters
|
|
31
|
+
| # or
|
|
32
|
+
"" # escaped quotes
|
|
33
|
+
)*? #
|
|
34
|
+
(?: # and closed by either
|
|
35
|
+
\\".* # a literal backslash at the end of the string
|
|
36
|
+
| # or
|
|
37
|
+
"(?!") # one non-escaped quote
|
|
38
|
+
) #
|
|
39
|
+
}mx.freeze
|
|
40
|
+
|
|
41
|
+
DOLLAR_QUOTED = %r{
|
|
42
|
+
( # a dollar quote is defined dynamically
|
|
43
|
+
\$ # the quote mark begins with a dollar sign
|
|
44
|
+
(?!\d) # unless followed by a digit, which denotes a variable
|
|
45
|
+
[^$]*? # otherwise it can can optionally contain any characters
|
|
46
|
+
\$ # up until another dollar sign
|
|
47
|
+
) #
|
|
48
|
+
.*? # there's some amount of intervening text being quoted
|
|
49
|
+
\1 # until the dollar quote mark is repeated
|
|
50
|
+
}mx.freeze
|
|
51
|
+
|
|
52
|
+
LINE_COMMENT = %r{
|
|
53
|
+
(?:\#|--) # single-line comments start with a hash or double hyphen
|
|
54
|
+
.*? # they contain arbitrary text
|
|
55
|
+
(?=\r|\n|$) # up until, but not including, the newline/carriage-return
|
|
56
|
+
}x.freeze
|
|
57
|
+
|
|
58
|
+
BLOCK_COMMENT = %r{
|
|
59
|
+
/\* # block comments open with a slash-star
|
|
60
|
+
(?> # they contain zero or more
|
|
61
|
+
[^/*] # non-star or -slash characters
|
|
62
|
+
| # or
|
|
63
|
+
/(?!\*) # a slash as long as it's not followed by a star
|
|
64
|
+
| # or
|
|
65
|
+
\*(?!/) # a star as long as it's not followed by a slash
|
|
66
|
+
| # or
|
|
67
|
+
\g<0> # recursively, a nested block comment
|
|
68
|
+
)* #
|
|
69
|
+
/? # slash followed by star is ok if star is part of close
|
|
70
|
+
\*/ # block comments close with a star-slash
|
|
71
|
+
}mx.freeze
|
|
72
|
+
|
|
73
|
+
UUID = /\{?(?:[0-9a-fA-F]-*){32}\}?/.freeze
|
|
74
|
+
|
|
75
|
+
NUMBER = /-?\b(?:[0-9]+\.)?[0-9]+([eE][+-]?[0-9]+)?\b/.freeze
|
|
76
|
+
|
|
77
|
+
BOOLEAN = /\b(?:true|false|null)\b/i.freeze
|
|
78
|
+
|
|
79
|
+
HEXADECIMAL = /0x\h+/.freeze
|
|
80
|
+
end
|
|
81
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: squelch
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Alex Vondrak
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2021-03-05 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: |
|
|
14
|
+
Squelch squelches SQL!
|
|
15
|
+
|
|
16
|
+
This gem is a purposefully simple string obfuscator. It aims to replace
|
|
17
|
+
every data literal in a SQL query with a `?` placeholder, as though it were
|
|
18
|
+
a prepared statement. The result should still be readable SQL, but without
|
|
19
|
+
the risk of leaking potentially sensitive information.
|
|
20
|
+
email: ajvondrak@gmail.com
|
|
21
|
+
executables: []
|
|
22
|
+
extensions: []
|
|
23
|
+
extra_rdoc_files: []
|
|
24
|
+
files:
|
|
25
|
+
- LICENSE
|
|
26
|
+
- README.md
|
|
27
|
+
- lib/squelch.rb
|
|
28
|
+
- lib/squelch/database.rb
|
|
29
|
+
- lib/squelch/error.rb
|
|
30
|
+
- lib/squelch/pairs.rb
|
|
31
|
+
- lib/squelch/patterns.rb
|
|
32
|
+
- lib/squelch/version.rb
|
|
33
|
+
homepage: https://github.com/ajvondrak/squelch
|
|
34
|
+
licenses:
|
|
35
|
+
- MIT
|
|
36
|
+
metadata:
|
|
37
|
+
bug_tracker_uri: https://github.com/ajvondrak/squelch/issues
|
|
38
|
+
documentation_uri: https://rubydoc.info/github/ajvondrak/squelch/main
|
|
39
|
+
homepage_uri: https://github.com/ajvondrak/squelch
|
|
40
|
+
source_code_uri: https://github.com/ajvondrak/squelch
|
|
41
|
+
post_install_message:
|
|
42
|
+
rdoc_options: []
|
|
43
|
+
require_paths:
|
|
44
|
+
- lib
|
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
46
|
+
requirements:
|
|
47
|
+
- - ">="
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: 2.6.0
|
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
requirements: []
|
|
56
|
+
rubygems_version: 3.2.3
|
|
57
|
+
signing_key:
|
|
58
|
+
specification_version: 4
|
|
59
|
+
summary: A simple SQL obfuscator
|
|
60
|
+
test_files: []
|