datadome 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec.travis +3 -0
- data/.rubocop.yml +242 -0
- data/.ruby-version +1 -0
- data/.travis.yml +11 -3
- data/Gemfile +9 -1
- data/Guardfile +16 -0
- data/README.md +27 -2
- data/Rakefile +7 -1
- data/datadome.gemspec +22 -13
- data/lib/datadome.rb +31 -1
- data/lib/datadome/client.rb +72 -0
- data/lib/datadome/configuration.rb +15 -0
- data/lib/datadome/inquirer.rb +66 -0
- data/lib/datadome/rack.rb +28 -0
- data/lib/datadome/validation_request.rb +177 -0
- data/lib/datadome/validation_response.rb +61 -0
- data/lib/datadome/version.rb +5 -1
- metadata +70 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd4a9c24ac83994e1334eaa2464593739f364382
|
4
|
+
data.tar.gz: e3fa5a184303204530187e89ac09529950900ea2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a04aefc34becc8e081797effa886865b3962383d74a6f12aeab3b5cf1272b57ea6ffa648ef06f864859381675f7eca4feee3117ac0f42dfec3afb563ebfbde1
|
7
|
+
data.tar.gz: e01baa33dd83ca39299d2c9e214a77d0b5ec050d0d8f65adbe514b0ea8a924bb481c422cdac32fad410170148413360daf0d3b837150ac78ae77f349e04bbb55
|
data/.rspec.travis
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,242 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- 'bin/*'
|
4
|
+
TargetRubyVersion: 2.3
|
5
|
+
|
6
|
+
Layout/AccessModifierIndentation:
|
7
|
+
EnforcedStyle: indent
|
8
|
+
SupportedStyles:
|
9
|
+
- outdent
|
10
|
+
- indent
|
11
|
+
|
12
|
+
Layout/AlignHash:
|
13
|
+
EnforcedHashRocketStyle: key
|
14
|
+
EnforcedColonStyle: key
|
15
|
+
EnforcedLastArgumentHashStyle: always_inspect
|
16
|
+
|
17
|
+
Layout/AlignParameters:
|
18
|
+
EnforcedStyle: with_fixed_indentation
|
19
|
+
|
20
|
+
Layout/EmptyLinesAroundClassBody:
|
21
|
+
EnforcedStyle: empty_lines_except_namespace
|
22
|
+
|
23
|
+
Layout/EmptyLinesAroundModuleBody:
|
24
|
+
EnforcedStyle: empty_lines_except_namespace
|
25
|
+
|
26
|
+
Layout/ExtraSpacing:
|
27
|
+
AllowForAlignment: false
|
28
|
+
|
29
|
+
Layout/FirstArrayElementLineBreak:
|
30
|
+
Enabled: true
|
31
|
+
|
32
|
+
Layout/FirstHashElementLineBreak:
|
33
|
+
Enabled: true
|
34
|
+
|
35
|
+
Layout/FirstMethodArgumentLineBreak:
|
36
|
+
Enabled: true
|
37
|
+
|
38
|
+
Layout/FirstParameterIndentation:
|
39
|
+
EnforcedStyle: consistent
|
40
|
+
|
41
|
+
Layout/IndentArray:
|
42
|
+
EnforcedStyle: consistent
|
43
|
+
|
44
|
+
Layout/IndentHash:
|
45
|
+
EnforcedStyle: consistent
|
46
|
+
|
47
|
+
Layout/MultilineAssignmentLayout:
|
48
|
+
Enabled: true
|
49
|
+
EnforcedStyle: new_line
|
50
|
+
|
51
|
+
Layout/MultilineMethodCallIndentation:
|
52
|
+
EnforcedStyle: indented
|
53
|
+
|
54
|
+
Layout/MultilineOperationIndentation:
|
55
|
+
EnforcedStyle: indented
|
56
|
+
|
57
|
+
Layout/SpaceAroundOperators:
|
58
|
+
AllowForAlignment: false
|
59
|
+
|
60
|
+
Layout/SpaceBeforeFirstArg:
|
61
|
+
AllowForAlignment: false
|
62
|
+
|
63
|
+
Lint/EndAlignment:
|
64
|
+
AutoCorrect: true
|
65
|
+
|
66
|
+
Lint/RedundantWithIndex:
|
67
|
+
Enabled: true
|
68
|
+
|
69
|
+
Lint/UnusedMethodArgument:
|
70
|
+
AllowUnusedKeywordArguments: true
|
71
|
+
IgnoreEmptyMethods: true
|
72
|
+
|
73
|
+
Metrics/AbcSize:
|
74
|
+
Enabled: false # todo
|
75
|
+
Max: 20 # default: 15
|
76
|
+
|
77
|
+
Metrics/BlockLength:
|
78
|
+
Enabled: false # todo
|
79
|
+
Exclude:
|
80
|
+
- "config/routes.rb"
|
81
|
+
- "config/routes/*"
|
82
|
+
- "lib/tasks/**/*"
|
83
|
+
|
84
|
+
Metrics/CyclomaticComplexity:
|
85
|
+
Enabled: false # todo
|
86
|
+
Max: 10 # default: 6
|
87
|
+
|
88
|
+
Metrics/LineLength:
|
89
|
+
Enabled: false # todo
|
90
|
+
Max: 100 # default: 80
|
91
|
+
|
92
|
+
Metrics/MethodLength:
|
93
|
+
Enabled: false # todo
|
94
|
+
Exclude:
|
95
|
+
- "db/migrate/*"
|
96
|
+
Max: 12 # default: 10
|
97
|
+
|
98
|
+
Metrics/PerceivedComplexity:
|
99
|
+
Enabled: false # todo
|
100
|
+
Max: 10 # default: 7
|
101
|
+
|
102
|
+
Naming/VariableNumber:
|
103
|
+
EnforcedStyle: snake_case
|
104
|
+
|
105
|
+
Performance/HashEachMethods:
|
106
|
+
Enabled: false
|
107
|
+
|
108
|
+
Style/AsciiComments:
|
109
|
+
Enabled: false
|
110
|
+
|
111
|
+
Style/AndOr:
|
112
|
+
Enabled: true
|
113
|
+
EnforcedStyle: conditionals
|
114
|
+
|
115
|
+
Style/BracesAroundHashParameters:
|
116
|
+
Enabled: false
|
117
|
+
|
118
|
+
Style/Dir:
|
119
|
+
Enabled: true
|
120
|
+
|
121
|
+
Style/Documentation:
|
122
|
+
Enabled: false
|
123
|
+
|
124
|
+
Style/FormatStringToken:
|
125
|
+
Exclude:
|
126
|
+
- "config/routes.rb"
|
127
|
+
- "config/routes/*"
|
128
|
+
|
129
|
+
Style/FrozenStringLiteralComment:
|
130
|
+
Enabled: false # we'll do later
|
131
|
+
|
132
|
+
Style/Lambda:
|
133
|
+
Enabled: false
|
134
|
+
|
135
|
+
|
136
|
+
Style/MethodCallWithArgsParentheses:
|
137
|
+
Enabled: true # false by default
|
138
|
+
Exclude:
|
139
|
+
- "Gemfile"
|
140
|
+
- "*.gemspec"
|
141
|
+
IgnoreMacros: true
|
142
|
+
IgnoredMethods:
|
143
|
+
- include
|
144
|
+
- load
|
145
|
+
- print
|
146
|
+
- private
|
147
|
+
- protected
|
148
|
+
- public
|
149
|
+
- puts
|
150
|
+
- raise
|
151
|
+
- require
|
152
|
+
- require_relative
|
153
|
+
# rake
|
154
|
+
- desc
|
155
|
+
- namespace
|
156
|
+
- task
|
157
|
+
# swagger
|
158
|
+
- key
|
159
|
+
- operation
|
160
|
+
- property
|
161
|
+
- response
|
162
|
+
- security_definition
|
163
|
+
- swagger_path
|
164
|
+
- swagger_schema
|
165
|
+
|
166
|
+
Style/ModuleFunction:
|
167
|
+
Enabled: false
|
168
|
+
|
169
|
+
Style/ReturnNil:
|
170
|
+
Enabled: true
|
171
|
+
|
172
|
+
Style/SignalException:
|
173
|
+
EnforcedStyle: only_raise
|
174
|
+
|
175
|
+
Style/StringLiterals:
|
176
|
+
Enabled: true
|
177
|
+
EnforcedStyle: double_quotes
|
178
|
+
|
179
|
+
Style/StringLiteralsInInterpolation:
|
180
|
+
Enabled: true
|
181
|
+
EnforcedStyle: double_quotes
|
182
|
+
|
183
|
+
Style/TrailingCommaInArguments:
|
184
|
+
EnforcedStyleForMultiline: no_comma
|
185
|
+
|
186
|
+
Style/TrailingCommaInLiteral:
|
187
|
+
EnforcedStyleForMultiline: comma
|
188
|
+
|
189
|
+
#
|
190
|
+
# Temporary disabled
|
191
|
+
#
|
192
|
+
|
193
|
+
Lint/IneffectiveAccessModifier:
|
194
|
+
Enabled: false
|
195
|
+
|
196
|
+
Lint/RescueException:
|
197
|
+
Enabled: false
|
198
|
+
|
199
|
+
Lint/RescueWithoutErrorClass:
|
200
|
+
Enabled: false
|
201
|
+
|
202
|
+
Lint/ShadowedException:
|
203
|
+
Enabled: false
|
204
|
+
|
205
|
+
Metrics/BlockNesting:
|
206
|
+
Enabled: false
|
207
|
+
|
208
|
+
Metrics/ClassLength:
|
209
|
+
Enabled: false
|
210
|
+
|
211
|
+
Metrics/ModuleLength:
|
212
|
+
Enabled: false
|
213
|
+
|
214
|
+
Metrics/ParameterLists:
|
215
|
+
Enabled: false
|
216
|
+
|
217
|
+
Naming/AccessorMethodName:
|
218
|
+
Enabled: false
|
219
|
+
|
220
|
+
Naming/PredicateName:
|
221
|
+
Enabled: false
|
222
|
+
|
223
|
+
Security/Eval:
|
224
|
+
Enabled: false
|
225
|
+
|
226
|
+
Style/ClassAndModuleChildren:
|
227
|
+
Enabled: false
|
228
|
+
|
229
|
+
Style/ClassVars:
|
230
|
+
Enabled: false
|
231
|
+
|
232
|
+
Style/GuardClause:
|
233
|
+
Enabled: false
|
234
|
+
|
235
|
+
Style/NumericPredicate:
|
236
|
+
Enabled: false
|
237
|
+
|
238
|
+
Style/SafeNavigation:
|
239
|
+
Enabled: false
|
240
|
+
|
241
|
+
Style/StructInheritance:
|
242
|
+
Enabled: false
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.3.5
|
data/.travis.yml
CHANGED
@@ -1,5 +1,13 @@
|
|
1
|
-
|
1
|
+
before_install:
|
2
|
+
- gem install bundler -v 1.15.4
|
3
|
+
before_script:
|
4
|
+
- cp -f .rspec.travis .rspec
|
5
|
+
bundler_args: --without local
|
6
|
+
dist: trusty
|
2
7
|
language: ruby
|
3
8
|
rvm:
|
4
|
-
- 2.3.
|
5
|
-
|
9
|
+
- 2.3.5
|
10
|
+
- 2.4.2
|
11
|
+
script:
|
12
|
+
- bundle exec rake ci
|
13
|
+
sudo: false
|
data/Gemfile
CHANGED
@@ -1,6 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source "https://rubygems.org"
|
2
4
|
|
3
|
-
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
5
|
+
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
4
6
|
|
5
7
|
# Specify your gem's dependencies in datadome.gemspec
|
6
8
|
gemspec
|
9
|
+
|
10
|
+
group :local do
|
11
|
+
# Guard
|
12
|
+
gem "guard-rspec", require: false
|
13
|
+
gem "terminal-notifier-guard", require: false # OS X
|
14
|
+
end
|
data/Guardfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
guard(:rspec, cmd: "bundle exec rspec") do
|
4
|
+
require "guard/rspec/dsl"
|
5
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
6
|
+
|
7
|
+
# RSpec files
|
8
|
+
rspec = dsl.rspec
|
9
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
10
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
11
|
+
watch(rspec.spec_files)
|
12
|
+
|
13
|
+
# Ruby files
|
14
|
+
ruby = dsl.ruby
|
15
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
16
|
+
end
|
data/README.md
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
# Datadome
|
2
2
|
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/datadome.svg)](https://badge.fury.io/rb/datadome) [![Build Status](https://travis-ci.org/shopmium/datadome.svg?branch=master)](https://travis-ci.org/shopmium/datadome)
|
4
|
+
|
3
5
|
Rack middleware for Datadome. https://datadome.co/
|
4
6
|
|
7
|
+
This is still an early version.
|
8
|
+
|
5
9
|
## Installation
|
6
10
|
|
7
11
|
Add this line to your application's Gemfile:
|
@@ -18,9 +22,30 @@ Or install it yourself as:
|
|
18
22
|
|
19
23
|
$ gem install datadome
|
20
24
|
|
21
|
-
## Usage
|
25
|
+
## Usage with Rails
|
26
|
+
|
27
|
+
Create a `config/initializers/datadome.rb` file:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require "datadome"
|
31
|
+
|
32
|
+
Datadome.configure do |config|
|
33
|
+
# Set the Datadome API key
|
34
|
+
config.api_key = "my-api-key"
|
35
|
+
# or use an environment variable (better)
|
36
|
+
# config.api_key = ENV["DATADOME_API_KEY"]
|
37
|
+
|
38
|
+
# Choose the closest Datadome API endpoint
|
39
|
+
# More info at https://docs.datadome.co/docs/api-server
|
40
|
+
config.api_server = "api-us-east-1.datadome.co"
|
41
|
+
end
|
42
|
+
|
43
|
+
Datadome.logger = Logger.new(STDOUT, level: :debug)
|
44
|
+
|
45
|
+
Rails.configuration.middleware.insert_after(ActionDispatch::RemoteIp, ::Datadome::Rack)
|
46
|
+
```
|
22
47
|
|
23
|
-
|
48
|
+
For the Javascript snippet, insert it directly in your layout file.
|
24
49
|
|
25
50
|
## Development
|
26
51
|
|
data/Rakefile
CHANGED
@@ -1,6 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "bundler/gem_tasks"
|
2
4
|
require "rspec/core/rake_task"
|
5
|
+
require "rubocop/rake_task"
|
3
6
|
|
4
7
|
RSpec::Core::RakeTask.new(:spec)
|
8
|
+
RuboCop::RakeTask.new
|
9
|
+
|
10
|
+
task default: :spec
|
5
11
|
|
6
|
-
task :
|
12
|
+
task ci: %i[spec rubocop]
|
data/datadome.gemspec
CHANGED
@@ -1,27 +1,36 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
lib = File.expand_path("../lib", __FILE__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require "datadome/version"
|
5
6
|
|
6
7
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name
|
8
|
-
spec.version
|
9
|
-
spec.authors
|
10
|
-
spec.email
|
8
|
+
spec.name = "datadome"
|
9
|
+
spec.version = Datadome::VERSION
|
10
|
+
spec.authors = ["Maxime Garcia"]
|
11
|
+
spec.email = ["maxime.garcia@shopmium.com"]
|
11
12
|
|
12
|
-
spec.summary
|
13
|
-
spec.description
|
14
|
-
spec.homepage
|
13
|
+
spec.summary = "Rack middleware for Datadome."
|
14
|
+
spec.description = "Rack middleware for Datadome."
|
15
|
+
spec.homepage = "https://github.com/shopmium/datadome"
|
15
16
|
spec.license = "MIT"
|
16
17
|
|
17
|
-
spec.files
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
spec.
|
18
|
+
spec.files =
|
19
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
20
|
+
f.match(%r{^(test|spec|features)/})
|
21
|
+
end
|
22
|
+
spec.bindir = "exe"
|
23
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
24
|
spec.require_paths = ["lib"]
|
23
25
|
|
26
|
+
spec.required_ruby_version = ">= 2.3.0"
|
27
|
+
|
28
|
+
spec.add_runtime_dependency "rack"
|
29
|
+
spec.add_runtime_dependency "faraday", ">= 0.9.2"
|
30
|
+
|
24
31
|
spec.add_development_dependency "bundler", "~> 1.15"
|
25
32
|
spec.add_development_dependency "rake", "~> 10.0"
|
26
33
|
spec.add_development_dependency "rspec", "~> 3.0"
|
34
|
+
spec.add_development_dependency "rubocop", "0.50.0"
|
35
|
+
spec.add_development_dependency "timecop", "~> 0.9.1"
|
27
36
|
end
|
data/lib/datadome.rb
CHANGED
@@ -1,5 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "datadome/version"
|
4
|
+
require "datadome/client"
|
5
|
+
require "datadome/configuration"
|
6
|
+
require "datadome/inquirer"
|
7
|
+
require "datadome/validation_request"
|
8
|
+
require "datadome/validation_response"
|
9
|
+
require "datadome/rack"
|
2
10
|
|
3
11
|
module Datadome
|
4
|
-
|
12
|
+
|
13
|
+
class << self
|
14
|
+
|
15
|
+
attr_writer :configuration
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.configuration
|
20
|
+
@configuration ||= Configuration.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.configure
|
24
|
+
yield(configuration)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.logger
|
28
|
+
@logger ||= Logger.new(STDOUT, level: :info)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.logger=(logger)
|
32
|
+
@logger = logger
|
33
|
+
end
|
34
|
+
|
5
35
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "faraday"
|
4
|
+
require "socket"
|
5
|
+
|
6
|
+
module Datadome
|
7
|
+
class Client
|
8
|
+
|
9
|
+
OPEN_TIMEOUT = 1
|
10
|
+
TIMEOUT = 3
|
11
|
+
|
12
|
+
class << self
|
13
|
+
|
14
|
+
def base_url
|
15
|
+
"https://#{Datadome.configuration.api_server}/"
|
16
|
+
end
|
17
|
+
|
18
|
+
def default_params
|
19
|
+
{
|
20
|
+
"Key" => Datadome.configuration.api_key,
|
21
|
+
"RequestModuleName" => "DataDome Ruby Gem",
|
22
|
+
"ModuleVersion" => ::Datadome::VERSION,
|
23
|
+
"ServerName" => hostname,
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def hostname
|
28
|
+
Socket.gethostname
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
def check
|
34
|
+
response =
|
35
|
+
connection.get do |req|
|
36
|
+
req.url("check")
|
37
|
+
end
|
38
|
+
|
39
|
+
response
|
40
|
+
end
|
41
|
+
|
42
|
+
def validate_request(data)
|
43
|
+
data = data.merge(self.class.default_params)
|
44
|
+
|
45
|
+
response =
|
46
|
+
connection.post do |req|
|
47
|
+
req.url("validate-request")
|
48
|
+
req.headers["User-Agent"] = "DataDome"
|
49
|
+
req.body = data
|
50
|
+
end
|
51
|
+
|
52
|
+
ValidationResponse.from_faraday_response(response)
|
53
|
+
rescue Faraday::Error::ConnectionFailed, Faraday::Error::TimeoutError => e
|
54
|
+
Datadome.logger.warn("Datadome: Timeout #{e}")
|
55
|
+
|
56
|
+
ValidationResponse.pass
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def connection
|
62
|
+
@connection ||=
|
63
|
+
Faraday.new(url: self.class.base_url) do |faraday|
|
64
|
+
faraday.request(:url_encoded)
|
65
|
+
faraday.adapter(Faraday.default_adapter)
|
66
|
+
faraday.options[:open_timeout] = OPEN_TIMEOUT
|
67
|
+
faraday.options[:timeout] = TIMEOUT
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rack"
|
4
|
+
|
5
|
+
module Datadome
|
6
|
+
class Inquirer
|
7
|
+
|
8
|
+
def initialize(env)
|
9
|
+
@env = env
|
10
|
+
end
|
11
|
+
|
12
|
+
def build_response
|
13
|
+
@validation_response.to_rack_response
|
14
|
+
end
|
15
|
+
|
16
|
+
def enriching
|
17
|
+
status, headers, response = yield
|
18
|
+
|
19
|
+
added_headers = ::Rack::Utils::HeaderHash.new(@validation_response.response_headers)
|
20
|
+
|
21
|
+
headers = ::Rack::Utils::HeaderHash.new(headers)
|
22
|
+
existing_set_cookie = headers["Set-Cookie"]
|
23
|
+
|
24
|
+
headers.merge!(added_headers)
|
25
|
+
|
26
|
+
if added_headers["Set-Cookie"] && existing_set_cookie
|
27
|
+
headers["Set-Cookie"] = merge_cookie(existing_set_cookie, added_headers["Set-Cookie"])
|
28
|
+
end
|
29
|
+
|
30
|
+
[status, headers, response]
|
31
|
+
end
|
32
|
+
|
33
|
+
def intercept?
|
34
|
+
@validation_response.pass == false || @validation_response.redirect
|
35
|
+
end
|
36
|
+
|
37
|
+
def inquire
|
38
|
+
@validation_response = validate_request
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def validate_request
|
44
|
+
validation_request = ValidationRequest.from_env(@env)
|
45
|
+
|
46
|
+
Datadome.logger.debug("Datadome: Validation Request: #{validation_request.inspect}")
|
47
|
+
|
48
|
+
client = Client.new
|
49
|
+
client.validate_request(validation_request.to_api_params).tap do |validation_response|
|
50
|
+
Datadome.logger.debug("Datadome: Validation Response: #{validation_response.inspect}")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def merge_cookie(old_cookie, cookie)
|
55
|
+
case old_cookie
|
56
|
+
when nil, ""
|
57
|
+
cookie
|
58
|
+
when String
|
59
|
+
[old_cookie, cookie].join("\n")
|
60
|
+
when Array
|
61
|
+
(old_cookie + [cookie]).join("\n")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rack"
|
4
|
+
|
5
|
+
module Datadome
|
6
|
+
class Rack
|
7
|
+
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
inquirer = Inquirer.new(env)
|
14
|
+
inquired = inquirer.inquire
|
15
|
+
|
16
|
+
return @app.call(env) unless inquired
|
17
|
+
|
18
|
+
if inquirer.intercept?
|
19
|
+
inquirer.build_response
|
20
|
+
else
|
21
|
+
inquirer.enriching do
|
22
|
+
@app.call(env)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadome
|
4
|
+
class ValidationRequest
|
5
|
+
|
6
|
+
@definitions = []
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
attr_reader(:definitions)
|
11
|
+
|
12
|
+
def limit_size(value, size:)
|
13
|
+
if value && size
|
14
|
+
value[0, size]
|
15
|
+
else
|
16
|
+
value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def from_env(env)
|
21
|
+
request = ::Rack::Request.new(env)
|
22
|
+
|
23
|
+
new.tap do |validation_request|
|
24
|
+
definitions.each do |definition|
|
25
|
+
value = definition[:block].call(env, request)
|
26
|
+
next if value.nil?
|
27
|
+
|
28
|
+
validation_request[definition[:param_name]] = limit_size(value, size: definition[:max_size])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def capture(param_name, max_size: nil, &block)
|
36
|
+
definitions << {
|
37
|
+
param_name: param_name,
|
38
|
+
block: block,
|
39
|
+
max_size: max_size,
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
capture("IP") do |_env, request|
|
46
|
+
request.ip
|
47
|
+
end
|
48
|
+
|
49
|
+
capture("Port") do |_env, request|
|
50
|
+
request.port
|
51
|
+
end
|
52
|
+
|
53
|
+
capture("Protocol") do |_env, request|
|
54
|
+
request.scheme && request.scheme.upcase
|
55
|
+
end
|
56
|
+
|
57
|
+
capture("Method") do |_env, request|
|
58
|
+
request.request_method
|
59
|
+
end
|
60
|
+
|
61
|
+
capture("Request", max_size: 2048) do |env, _request|
|
62
|
+
env["ORIGINAL_FULLPATH"]
|
63
|
+
end
|
64
|
+
|
65
|
+
capture("TimeRequest") do |env, _request|
|
66
|
+
usec_timestamp = (env["HTTP_X_REQUEST_START"] || "").gsub("t=", "").to_i
|
67
|
+
usec_timestamp = (Time.now.to_f * 1_000_000).round if usec_timestamp.zero?
|
68
|
+
|
69
|
+
usec_timestamp
|
70
|
+
end
|
71
|
+
|
72
|
+
capture("Accept", max_size: 512) do |env, _request|
|
73
|
+
env["HTTP_ACCEPT"]
|
74
|
+
end
|
75
|
+
|
76
|
+
capture("AcceptCharset", max_size: 128) do |env, _request|
|
77
|
+
env["HTTP_ACCEPT_CHARSET"]
|
78
|
+
end
|
79
|
+
|
80
|
+
capture("AcceptEncoding", max_size: 128) do |env, _request|
|
81
|
+
env["HTTP_ACCEPT_ENCODING"]
|
82
|
+
end
|
83
|
+
|
84
|
+
capture("AcceptLanguage", max_size: 256) do |env, _request|
|
85
|
+
env["HTTP_ACCEPT_LANGUAGE"]
|
86
|
+
end
|
87
|
+
|
88
|
+
capture("CacheControl") do |env, _request|
|
89
|
+
env["HTTP_CACHE_CONTROL"]
|
90
|
+
end
|
91
|
+
|
92
|
+
capture("Connection") do |env, _request|
|
93
|
+
env["HTTP_CONNECTION"]
|
94
|
+
end
|
95
|
+
|
96
|
+
capture("Host") do |_env, request|
|
97
|
+
request.host
|
98
|
+
end
|
99
|
+
|
100
|
+
capture("Origin", max_size: 512) do |env, _request|
|
101
|
+
env["HTTP_ORIGIN"]
|
102
|
+
end
|
103
|
+
|
104
|
+
capture("Pragma") do |env, _request|
|
105
|
+
env["HTTP_PRAGMA"]
|
106
|
+
end
|
107
|
+
|
108
|
+
capture("Referer", max_size: 1024) do |env, _request|
|
109
|
+
env["HTTP_REFERER"]
|
110
|
+
end
|
111
|
+
|
112
|
+
capture("UserAgent", max_size: 768) do |env, _request|
|
113
|
+
env["HTTP_USER_AGENT"]
|
114
|
+
end
|
115
|
+
|
116
|
+
capture("XForwaredForIP", max_size: 512) do |env, _request|
|
117
|
+
env["HTTP_X_FORWARDED_FOR"]
|
118
|
+
end
|
119
|
+
|
120
|
+
capture("X-Requested-With", max_size: 128) do |env, _request|
|
121
|
+
env["HTTP_X_REQUESTED_WITH"]
|
122
|
+
end
|
123
|
+
|
124
|
+
capture("HeadersList", max_size: 512) do |env, _request|
|
125
|
+
headers =
|
126
|
+
env.keys
|
127
|
+
.select { |key| key[0, 5] == "HTTP_" }
|
128
|
+
.map { |key| key.gsub("HTTP_", "").downcase.tr("_", "-") }
|
129
|
+
headers -= ["version"]
|
130
|
+
|
131
|
+
headers.join(",")
|
132
|
+
end
|
133
|
+
|
134
|
+
capture("CookiesLen") do |env, _request|
|
135
|
+
next(0) unless env["HTTP_COOKIE"]
|
136
|
+
|
137
|
+
env["HTTP_COOKIE"].length
|
138
|
+
end
|
139
|
+
|
140
|
+
capture("PostParamLen") do |_env, request|
|
141
|
+
raw_post_body = request.body
|
142
|
+
next(0) unless raw_post_body
|
143
|
+
|
144
|
+
data = raw_post_body.read
|
145
|
+
raw_post_body.rewind if raw_post_body.respond_to?(:rewind)
|
146
|
+
|
147
|
+
(data || "").length
|
148
|
+
end
|
149
|
+
|
150
|
+
capture("AuthorizationLen") do |env, _request|
|
151
|
+
next(0) unless env["HTTP_AUTHORIZATION"]
|
152
|
+
|
153
|
+
env["HTTP_AUTHORIZATION"].length
|
154
|
+
end
|
155
|
+
|
156
|
+
capture("ClientID", max_size: 128) do |_env, request|
|
157
|
+
request.cookies["datadome"]
|
158
|
+
end
|
159
|
+
|
160
|
+
def initialize
|
161
|
+
@data = {}
|
162
|
+
end
|
163
|
+
|
164
|
+
def [](name)
|
165
|
+
@data[name]
|
166
|
+
end
|
167
|
+
|
168
|
+
def []=(name, value)
|
169
|
+
@data[name] = value
|
170
|
+
end
|
171
|
+
|
172
|
+
def to_api_params
|
173
|
+
@data
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadome
|
4
|
+
class ValidationResponse
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def pass
|
9
|
+
new(pass: true, redirect: false)
|
10
|
+
end
|
11
|
+
|
12
|
+
def from_faraday_response(response)
|
13
|
+
validation_response =
|
14
|
+
if response.status == 403
|
15
|
+
new(pass: false, redirect: false, response_status: 403, response_body: response.body)
|
16
|
+
elsif response.status == 301 || response.status == 302
|
17
|
+
new(pass: false, redirect: true, response_status: response.status, redirection_location: response.headers["Location"])
|
18
|
+
else
|
19
|
+
pass
|
20
|
+
end
|
21
|
+
|
22
|
+
parse_headers_list(response.headers["X-DataDome-request-headers"]).each do |key|
|
23
|
+
validation_response.request_headers[key] = response.headers[key]
|
24
|
+
end
|
25
|
+
|
26
|
+
parse_headers_list(response.headers["X-DataDome-headers"]).each do |key|
|
27
|
+
validation_response.response_headers[key] = response.headers[key]
|
28
|
+
end
|
29
|
+
|
30
|
+
validation_response
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse_headers_list(list)
|
34
|
+
return [] if list.nil? || list == ""
|
35
|
+
|
36
|
+
list.split(" ")
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
attr_accessor :pass, :redirect
|
42
|
+
attr_accessor :redirection_location, :request_headers, :response_body, :response_headers, :response_status
|
43
|
+
|
44
|
+
def initialize(attrs = {})
|
45
|
+
self.request_headers = {}
|
46
|
+
self.response_headers = {}
|
47
|
+
|
48
|
+
attrs.each do |key, value|
|
49
|
+
public_send("#{key}=", value)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_rack_response
|
54
|
+
response = ::Rack::Response.new(@response_body || [], @response_status, @response_headers)
|
55
|
+
response.redirect(@redirection_location, @response_status) if @redirect
|
56
|
+
|
57
|
+
response.finish
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
data/lib/datadome/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: datadome
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maxime Garcia
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rack
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: faraday
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.9.2
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.9.2
|
13
41
|
- !ruby/object:Gem::Dependency
|
14
42
|
name: bundler
|
15
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +80,34 @@ dependencies:
|
|
52
80
|
- - "~>"
|
53
81
|
- !ruby/object:Gem::Version
|
54
82
|
version: '3.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.50.0
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.50.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: timecop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.9.1
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.9.1
|
55
111
|
description: Rack middleware for Datadome.
|
56
112
|
email:
|
57
113
|
- maxime.garcia@shopmium.com
|
@@ -61,8 +117,12 @@ extra_rdoc_files: []
|
|
61
117
|
files:
|
62
118
|
- ".gitignore"
|
63
119
|
- ".rspec"
|
120
|
+
- ".rspec.travis"
|
121
|
+
- ".rubocop.yml"
|
122
|
+
- ".ruby-version"
|
64
123
|
- ".travis.yml"
|
65
124
|
- Gemfile
|
125
|
+
- Guardfile
|
66
126
|
- LICENSE.txt
|
67
127
|
- README.md
|
68
128
|
- Rakefile
|
@@ -70,6 +130,12 @@ files:
|
|
70
130
|
- bin/setup
|
71
131
|
- datadome.gemspec
|
72
132
|
- lib/datadome.rb
|
133
|
+
- lib/datadome/client.rb
|
134
|
+
- lib/datadome/configuration.rb
|
135
|
+
- lib/datadome/inquirer.rb
|
136
|
+
- lib/datadome/rack.rb
|
137
|
+
- lib/datadome/validation_request.rb
|
138
|
+
- lib/datadome/validation_response.rb
|
73
139
|
- lib/datadome/version.rb
|
74
140
|
homepage: https://github.com/shopmium/datadome
|
75
141
|
licenses:
|
@@ -83,7 +149,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
83
149
|
requirements:
|
84
150
|
- - ">="
|
85
151
|
- !ruby/object:Gem::Version
|
86
|
-
version:
|
152
|
+
version: 2.3.0
|
87
153
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
154
|
requirements:
|
89
155
|
- - ">="
|
@@ -91,7 +157,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
157
|
version: '0'
|
92
158
|
requirements: []
|
93
159
|
rubyforge_project:
|
94
|
-
rubygems_version: 2.6.
|
160
|
+
rubygems_version: 2.6.13
|
95
161
|
signing_key:
|
96
162
|
specification_version: 4
|
97
163
|
summary: Rack middleware for Datadome.
|