datadome 0.0.0 → 0.0.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: c0193ec317042795fc99d6514150da44711346b3
4
- data.tar.gz: f6f1f6e70ce36c5604989ebfaae97fdb85da4877
3
+ metadata.gz: fd4a9c24ac83994e1334eaa2464593739f364382
4
+ data.tar.gz: e3fa5a184303204530187e89ac09529950900ea2
5
5
  SHA512:
6
- metadata.gz: c65ada26774b82db0216b980386cab3872687951ba97b7918c0fd72055ac0ee37030d39d5b1a4580a4db2305e0cc69e67bd49446d81083b17e9fefd43702f03a
7
- data.tar.gz: 39ce5894e83b65507dbd7319c50dad7f9d0a3cb81e2946e3f5eef6761a0d4edc27f1818caa341674e222d6f4edc554982edf49eeddc30f91701dbf64a9043eb8
6
+ metadata.gz: 6a04aefc34becc8e081797effa886865b3962383d74a6f12aeab3b5cf1272b57ea6ffa648ef06f864859381675f7eca4feee3117ac0f42dfec3afb563ebfbde1
7
+ data.tar.gz: e01baa33dd83ca39299d2c9e214a77d0b5ec050d0d8f65adbe514b0ea8a924bb481c422cdac32fad410170148413360daf0d3b837150ac78ae77f349e04bbb55
data/.rspec.travis ADDED
@@ -0,0 +1,3 @@
1
+ --format progress
2
+ --color
3
+ --order rand
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
- sudo: false
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.3
5
- before_install: gem install bundler -v 1.15.3
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
- TODO: Write usage instructions here
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 :default => :spec
12
+ task ci: %i[spec rubocop]
data/datadome.gemspec CHANGED
@@ -1,27 +1,36 @@
1
- # coding: utf-8
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 = "datadome"
8
- spec.version = Datadome::VERSION
9
- spec.authors = ["Maxime Garcia"]
10
- spec.email = ["maxime.garcia@shopmium.com"]
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 = "Rack middleware for Datadome."
13
- spec.description = "Rack middleware for Datadome."
14
- spec.homepage = "https://github.com/shopmium/datadome"
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 = `git ls-files -z`.split("\x0").reject do |f|
18
- f.match(%r{^(test|spec|features)/})
19
- end
20
- spec.bindir = "exe"
21
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
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
- # Your code goes here...
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,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "logger"
4
+
5
+ module Datadome
6
+ class Configuration
7
+
8
+ def initialize
9
+ @api_server = "api.datadome.co"
10
+ end
11
+
12
+ attr_accessor :api_key, :api_server
13
+
14
+ end
15
+ 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
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Datadome
2
- VERSION = "0.0.0".freeze
4
+
5
+ VERSION = "0.0.1"
6
+
3
7
  end
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.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-08-07 00:00:00.000000000 Z
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: '0'
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.12
160
+ rubygems_version: 2.6.13
95
161
  signing_key:
96
162
  specification_version: 4
97
163
  summary: Rack middleware for Datadome.