cloudflare-rails 4.1.0 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +55 -0
- data/.rubocop.yml +12 -1
- data/.rubocop_todo.yml +149 -26
- data/Appraisals +6 -6
- data/CHANGELOG.md +8 -0
- data/README.md +11 -3
- data/Rakefile +9 -9
- data/cloudflare-rails.gemspec +32 -30
- data/gemfiles/rails_6.1.gemfile +3 -3
- data/gemfiles/rails_7.0.gemfile +3 -3
- data/gemfiles/rails_7.1.gemfile +3 -3
- data/lib/cloudflare_rails/check_trusted_proxies.rb +13 -0
- data/lib/cloudflare_rails/fallback_ips.rb +41 -0
- data/lib/cloudflare_rails/importer.rb +67 -0
- data/lib/cloudflare_rails/railtie.rb +29 -0
- data/lib/cloudflare_rails/remote_ip_proxies.rb +9 -0
- data/lib/cloudflare_rails/version.rb +3 -0
- data/lib/cloudflare_rails.rb +7 -0
- metadata +99 -39
- data/.circleci/config.yml +0 -54
- data/.rubocop_airbnb.yml +0 -2
- data/lib/cloudflare/rails/railtie.rb +0 -117
- data/lib/cloudflare/rails/version.rb +0 -5
- data/lib/cloudflare/rails.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4d8ab5a9f56ae053e1647298c77b9a1616834b89d72467d09938f27ea9063d6
|
4
|
+
data.tar.gz: 123877f4dfc33b4c276cbfa91a718e14e9d92f8244ea618e21c12b57a84b203c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2814703b862fd8c88e89a40fa4d84dfcf1b71e2b90d823a74d450f54a69edc3ea14e0056f0442dcca837a460d4c253b21fa6e156b21d72148b53d47723b39ab
|
7
|
+
data.tar.gz: 66a1dbe16f14fce0562e34b4a694fc681299014afcf4d20785ea58467cc932e382c5df57a461e2cfc928c7a7aebe7ff524b29d020d759778ca2680b5ea153655
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: Ruby
|
9
|
+
|
10
|
+
on:
|
11
|
+
pull_request:
|
12
|
+
branches: [main]
|
13
|
+
|
14
|
+
jobs:
|
15
|
+
test:
|
16
|
+
runs-on: ubuntu-latest
|
17
|
+
steps:
|
18
|
+
- uses: actions/checkout@v4
|
19
|
+
- uses: ruby/setup-ruby@v1
|
20
|
+
with:
|
21
|
+
ruby-version: "3.2" # Not needed with a .ruby-version file
|
22
|
+
- uses: actions/cache@v3
|
23
|
+
with:
|
24
|
+
path: vendor/bundle
|
25
|
+
key: ${{ runner.os }}-gems-${{ hashFiles('**/cloudflare-rails.gemspec') }}
|
26
|
+
restore-keys: |
|
27
|
+
${{ runner.os }}-gems-
|
28
|
+
- name: Bundle install
|
29
|
+
run: |
|
30
|
+
bundle config path vendor/bundle
|
31
|
+
bundle install --jobs 4 --retry 3
|
32
|
+
- name: Appraisal install
|
33
|
+
run: |
|
34
|
+
bundle exec appraisal install
|
35
|
+
- name: Run tests
|
36
|
+
run: bundle exec appraisal rake
|
37
|
+
lint:
|
38
|
+
runs-on: ubuntu-latest
|
39
|
+
steps:
|
40
|
+
- uses: actions/checkout@v4
|
41
|
+
- uses: ruby/setup-ruby@v1
|
42
|
+
with:
|
43
|
+
ruby-version: "3.2" # Not needed with a .ruby-version file
|
44
|
+
- uses: actions/cache@v3
|
45
|
+
with:
|
46
|
+
path: vendor/bundle
|
47
|
+
key: ${{ runner.os }}-gems-${{ hashFiles('**/cloudflare-rails.gemspec') }}
|
48
|
+
restore-keys: |
|
49
|
+
${{ runner.os }}-gems-
|
50
|
+
- name: Bundle install
|
51
|
+
run: |
|
52
|
+
bundle config path vendor/bundle
|
53
|
+
bundle install --jobs 4 --retry 3
|
54
|
+
- name: Rubocop
|
55
|
+
run: bundle exec rubocop
|
data/.rubocop.yml
CHANGED
@@ -1,6 +1,17 @@
|
|
1
1
|
inherit_from:
|
2
|
-
- .rubocop_airbnb.yml
|
3
2
|
- .rubocop_todo.yml
|
3
|
+
require:
|
4
|
+
- rubocop-rails
|
5
|
+
- rubocop-performance
|
6
|
+
- rubocop-rspec
|
7
|
+
|
4
8
|
AllCops:
|
5
9
|
NewCops: enable
|
10
|
+
TargetRubyVersion: 2.5
|
6
11
|
SuggestExtensions: false
|
12
|
+
|
13
|
+
Style/Documentation:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
Gemspec/DevelopmentDependencies:
|
17
|
+
Enabled: false
|
data/.rubocop_todo.yml
CHANGED
@@ -1,51 +1,174 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on
|
3
|
+
# on 2023-12-11 04:03:08 UTC using RuboCop version 1.58.0.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
8
8
|
|
9
|
-
# Offense count:
|
10
|
-
#
|
11
|
-
|
9
|
+
# Offense count: 1
|
10
|
+
# Configuration parameters: AllowedMethods.
|
11
|
+
# AllowedMethods: enums
|
12
|
+
Lint/ConstantDefinitionInBlock:
|
12
13
|
Exclude:
|
13
14
|
- 'spec/cloudflare/rails_spec.rb'
|
14
15
|
|
15
|
-
# Offense count:
|
16
|
-
#
|
17
|
-
# Configuration parameters:
|
18
|
-
#
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
# Offense count: 1
|
17
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
18
|
+
# Configuration parameters: AllowedMethods.
|
19
|
+
# AllowedMethods: instance_of?, kind_of?, is_a?, eql?, respond_to?, equal?, presence, present?
|
20
|
+
Lint/RedundantSafeNavigation:
|
21
|
+
Exclude:
|
22
|
+
- 'spec/cloudflare/rails_spec.rb'
|
23
|
+
|
24
|
+
# Offense count: 1
|
25
|
+
# Configuration parameters: AllowComments, AllowNil.
|
26
|
+
Lint/SuppressedException:
|
27
|
+
Exclude:
|
28
|
+
- 'lib/cloudflare_rails/check_trusted_proxies.rb'
|
22
29
|
|
23
30
|
# Offense count: 1
|
24
|
-
#
|
31
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
|
32
|
+
Metrics/AbcSize:
|
33
|
+
Max: 18
|
34
|
+
|
35
|
+
# Offense count: 2
|
36
|
+
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
37
|
+
Metrics/MethodLength:
|
38
|
+
Max: 11
|
39
|
+
|
40
|
+
# Offense count: 2
|
41
|
+
# Configuration parameters: ForbiddenDelimiters.
|
42
|
+
# ForbiddenDelimiters: (?i-mx:(^|\s)(EO[A-Z]{1}|END)(\s|$))
|
43
|
+
Naming/HeredocDelimiterNaming:
|
44
|
+
Exclude:
|
45
|
+
- 'lib/cloudflare_rails/fallback_ips.rb'
|
46
|
+
|
47
|
+
# Offense count: 3
|
48
|
+
RSpec/AnyInstance:
|
49
|
+
Exclude:
|
50
|
+
- 'spec/cloudflare/rails_spec.rb'
|
51
|
+
|
52
|
+
# Offense count: 1
|
53
|
+
# Configuration parameters: Prefixes, AllowedPatterns.
|
54
|
+
# Prefixes: when, with, without
|
55
|
+
RSpec/ContextWording:
|
56
|
+
Exclude:
|
57
|
+
- 'spec/cloudflare/rails_spec.rb'
|
58
|
+
|
59
|
+
# Offense count: 2
|
60
|
+
# This cop supports safe autocorrection (--autocorrect).
|
61
|
+
# Configuration parameters: CustomTransform, IgnoredWords, DisallowedExamples.
|
62
|
+
# DisallowedExamples: works
|
63
|
+
RSpec/ExampleWording:
|
64
|
+
Exclude:
|
65
|
+
- 'spec/cloudflare/rails_spec.rb'
|
66
|
+
|
67
|
+
# Offense count: 1
|
68
|
+
# Configuration parameters: Include, CustomTransform, IgnoreMethods, SpecSuffixOnly.
|
69
|
+
# Include: **/*_spec*rb*, **/spec/**/*
|
70
|
+
RSpec/FilePath:
|
71
|
+
Exclude:
|
72
|
+
- 'spec/cloudflare/rails_spec.rb'
|
73
|
+
|
74
|
+
# Offense count: 1
|
75
|
+
RSpec/LeakyConstantDeclaration:
|
76
|
+
Exclude:
|
77
|
+
- 'spec/cloudflare/rails_spec.rb'
|
78
|
+
|
79
|
+
# Offense count: 5
|
80
|
+
RSpec/MultipleExpectations:
|
81
|
+
Max: 2
|
82
|
+
|
83
|
+
# Offense count: 15
|
84
|
+
# Configuration parameters: AllowSubject.
|
85
|
+
RSpec/MultipleMemoizedHelpers:
|
86
|
+
Max: 14
|
87
|
+
|
88
|
+
# Offense count: 3
|
89
|
+
# Configuration parameters: EnforcedStyle, IgnoreSharedExamples.
|
90
|
+
# SupportedStyles: always, named_only
|
91
|
+
RSpec/NamedSubject:
|
92
|
+
Exclude:
|
93
|
+
- 'spec/cloudflare/rails_spec.rb'
|
94
|
+
|
95
|
+
# Offense count: 16
|
96
|
+
# Configuration parameters: AllowedGroups.
|
97
|
+
RSpec/NestedGroups:
|
98
|
+
Max: 6
|
99
|
+
|
100
|
+
# Offense count: 1
|
101
|
+
# Configuration parameters: Include, CustomTransform, IgnoreMethods, IgnoreMetadata.
|
102
|
+
# Include: **/*_spec.rb
|
103
|
+
RSpec/SpecFilePathFormat:
|
104
|
+
Exclude:
|
105
|
+
- 'spec/cloudflare/rails_spec.rb'
|
106
|
+
|
107
|
+
# Offense count: 1
|
108
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
25
109
|
Rails/ApplicationController:
|
26
110
|
Exclude:
|
27
111
|
- 'spec/cloudflare/rails_spec.rb'
|
28
112
|
|
29
113
|
# Offense count: 1
|
30
|
-
#
|
31
|
-
Rails/
|
114
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
115
|
+
Rails/CompactBlank:
|
116
|
+
Exclude:
|
117
|
+
- 'lib/cloudflare_rails/importer.rb'
|
118
|
+
|
119
|
+
# Offense count: 3
|
120
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
121
|
+
# Configuration parameters: Include.
|
122
|
+
# Include: **/Rakefile, **/*.rake
|
123
|
+
Rails/RakeEnvironment:
|
124
|
+
Exclude:
|
125
|
+
- 'Rakefile'
|
126
|
+
|
127
|
+
# Offense count: 1
|
128
|
+
# This cop supports safe autocorrection (--autocorrect).
|
129
|
+
# Configuration parameters: AllowOnConstant, AllowOnSelfClass.
|
130
|
+
Style/CaseEquality:
|
32
131
|
Exclude:
|
33
|
-
- 'lib/
|
132
|
+
- 'lib/cloudflare_rails/check_trusted_proxies.rb'
|
133
|
+
|
134
|
+
# Offense count: 2
|
135
|
+
# This cop supports safe autocorrection (--autocorrect).
|
136
|
+
# Configuration parameters: MaxUnannotatedPlaceholdersAllowed, AllowedMethods, AllowedPatterns.
|
137
|
+
# SupportedStyles: annotated, template, unannotated
|
138
|
+
# AllowedMethods: redirect
|
139
|
+
Style/FormatStringToken:
|
140
|
+
EnforcedStyle: unannotated
|
34
141
|
|
35
|
-
# Offense count:
|
36
|
-
#
|
37
|
-
# Configuration parameters: EnforcedStyle
|
38
|
-
# SupportedStyles:
|
39
|
-
|
40
|
-
# FunctionalMethods: let, let!, subject, watch
|
41
|
-
# IgnoredMethods: lambda, proc, it
|
42
|
-
Style/BlockDelimiters:
|
142
|
+
# Offense count: 15
|
143
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
144
|
+
# Configuration parameters: EnforcedStyle.
|
145
|
+
# SupportedStyles: always, always_true, never
|
146
|
+
Style/FrozenStringLiteralComment:
|
43
147
|
Exclude:
|
148
|
+
- 'Appraisals'
|
149
|
+
- 'Gemfile'
|
150
|
+
- 'Rakefile'
|
151
|
+
- 'cloudflare-rails.gemspec'
|
152
|
+
- 'gemfiles/rails_6.1.gemfile'
|
153
|
+
- 'gemfiles/rails_7.0.gemfile'
|
154
|
+
- 'gemfiles/rails_7.1.gemfile'
|
155
|
+
- 'lib/cloudflare_rails.rb'
|
156
|
+
- 'lib/cloudflare_rails/check_trusted_proxies.rb'
|
157
|
+
- 'lib/cloudflare_rails/importer.rb'
|
158
|
+
- 'lib/cloudflare_rails/railtie.rb'
|
159
|
+
- 'lib/cloudflare_rails/remote_ip_proxies.rb'
|
160
|
+
- 'lib/cloudflare_rails/version.rb'
|
44
161
|
- 'spec/cloudflare/rails_spec.rb'
|
162
|
+
- 'spec/spec_helper.rb'
|
163
|
+
|
164
|
+
# Offense count: 1
|
165
|
+
Style/MultilineBlockChain:
|
166
|
+
Exclude:
|
167
|
+
- 'lib/cloudflare_rails/railtie.rb'
|
45
168
|
|
46
|
-
# Offense count:
|
47
|
-
#
|
48
|
-
# Configuration parameters:
|
169
|
+
# Offense count: 2
|
170
|
+
# This cop supports safe autocorrection (--autocorrect).
|
171
|
+
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns.
|
49
172
|
# URISchemes: http, https
|
50
173
|
Layout/LineLength:
|
51
174
|
Max: 126
|
data/Appraisals
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
appraise
|
2
|
-
gem
|
1
|
+
appraise 'rails-6.1' do
|
2
|
+
gem 'rails', '~> 6.1.0'
|
3
3
|
end
|
4
4
|
|
5
|
-
appraise
|
6
|
-
gem
|
5
|
+
appraise 'rails-7.0' do
|
6
|
+
gem 'rails', '~> 7.0.0'
|
7
7
|
end
|
8
8
|
|
9
|
-
appraise
|
10
|
-
gem
|
9
|
+
appraise 'rails-7.1' do
|
10
|
+
gem 'rails', '~> 7.1.0'
|
11
11
|
end
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## [5.0.0] - 2023-12-15
|
8
|
+
### Breaking Changes
|
9
|
+
- Change namespace from `Cloudflare::Rails` to `CloudflareRails`. This avoids issues with the [cloudflare](https://github.com/socketry/cloudflare) gem as well as the global `Rails` namespace.
|
10
|
+
- A static set of Cloudflare IP addresses will now be used as a fallback value in the case of Cloudflare API failures. These will not be stored in `Rails.cache` so each subsequent result will retry the Cloudflare calls. Once one suceeds the response will be cached and used.
|
11
|
+
|
12
|
+
### Added
|
13
|
+
- Use `zeitwerk` to manage file loading.
|
14
|
+
|
7
15
|
## [4.1.0] - 2023-10-06
|
8
16
|
- Add support for `rails` version `7.1.0`
|
9
17
|
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# CloudflareRails [![Gem Version](https://badge.fury.io/rb/cloudflare-rails.svg)](https://badge.fury.io/rb/cloudflare-rails)
|
2
2
|
This gem correctly configures Rails for [CloudFlare](https://www.cloudflare.com) so that `request.remote_ip` / `request.ip` both work correctly.
|
3
3
|
|
4
4
|
## Rails Compatibility
|
@@ -36,9 +36,17 @@ Using Cloudflare means it's hard to identify the IP address of incoming requests
|
|
36
36
|
|
37
37
|
`cloudflare-rails` mitigates this attack by checking that the originating ip address of any incoming connection is from one of Cloudflare's ip address ranges. If so, the incoming `X-Forwarded-For` header is trusted and used as the ip address provided to `rack` and `rails` (via `request.ip` and `request.remote_ip`). If the incoming connection does not originate from a Cloudflare server then the `X-Forwarded-For` header is ignored and the actual remote ip address is used.
|
38
38
|
|
39
|
-
##
|
40
|
-
This code
|
39
|
+
## How it works
|
40
|
+
This code fetches and caches CloudFlare's current [IPv4](https://www.cloudflare.com/ips-v4) and [IPv6](https://www.cloudflare.com/ips-v6) lists. It then patches `Rack::Request::Helpers` and `ActionDispatch::RemoteIP` to treat these addresses as trusted proxies. The `X-Forwarded-For` header will then be trusted only from those ip addresses.
|
41
|
+
|
42
|
+
### Why not use `config.action_dispatch.trusted_proxies` or `Rack::Request.ip_filter?`
|
43
|
+
By default Rails includes the [ActionDispatch::RemoteIp](https://api.rubyonrails.org/classes/ActionDispatch/RemoteIp.html) middleware. This middleware uses a default list of [trusted proxies](https://github.com/rails/rails/blob/6b93fff8af32ef5e91f4ec3cfffb081d0553faf0/actionpack/lib/action_dispatch/middleware/remote_ip.rb#L36C5-L42). Any values from `config.action_dispatch.trusted_proxies` are appended to this list. If you were to set `config.action_dispatch.trusted_proxies` to the current list of Cloudflare IP addresses `request.remote_ip` would work correctly.
|
44
|
+
|
45
|
+
Unfortunately this does not fix `request.ip`. This method comes from the [Rack::Request](https://github.com/rack/rack/blob/main/lib/rack/request.rb) middleware. It has a separate implementation of [trusted proxies](https://github.com/rack/rack/blob/main/lib/rack/request.rb#L48-L56) and [ip filtering](https://github.com/rack/rack/blob/main/lib/rack/request.rb#L58C1-L59C1). The only way to use a different implementation is to set `Rack::Request.ip_filter` which expects a callable value. Providing a new one will override the old one so you'd lose the default values (all of which should be there). Those values aren't exported anywhere so your callable would now have to maintain _that_ list on top of the Cloudflare IPs.
|
41
46
|
|
47
|
+
These issues are why this gem patches both `Rack::Request::Helpers` and `ActionDispatch::RemoteIP` rather than using the built-in configuration methods.
|
48
|
+
|
49
|
+
## Usage
|
42
50
|
You can configure the HTTP `timeout` and `expires_in` cache parameters inside of your rails config:
|
43
51
|
```ruby
|
44
52
|
config.cloudflare.expires_in = 12.hours # default value
|
data/Rakefile
CHANGED
@@ -1,24 +1,24 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
3
|
|
4
4
|
RSpec::Core::RakeTask.new(:spec)
|
5
5
|
|
6
6
|
task :without_rack_attack do
|
7
7
|
ENV.delete 'RACK_ATTACK'
|
8
|
-
Rake::Task[
|
9
|
-
Rake::Task[
|
8
|
+
Rake::Task['spec'].reenable
|
9
|
+
Rake::Task['spec'].invoke
|
10
10
|
end
|
11
11
|
|
12
12
|
task :with_rack_attack_first do
|
13
13
|
ENV['RACK_ATTACK'] = 'first'
|
14
|
-
Rake::Task[
|
15
|
-
Rake::Task[
|
14
|
+
Rake::Task['spec'].reenable
|
15
|
+
Rake::Task['spec'].invoke
|
16
16
|
end
|
17
17
|
|
18
18
|
task :with_rack_attack_last do
|
19
19
|
ENV['RACK_ATTACK'] = 'last'
|
20
|
-
Rake::Task[
|
21
|
-
Rake::Task[
|
20
|
+
Rake::Task['spec'].reenable
|
21
|
+
Rake::Task['spec'].invoke
|
22
22
|
end
|
23
23
|
|
24
|
-
task :
|
24
|
+
task default: %i[without_rack_attack with_rack_attack_first with_rack_attack_last]
|
data/cloudflare-rails.gemspec
CHANGED
@@ -1,40 +1,42 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
lib = File.expand_path('../lib', __FILE__)
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
4
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
-
require '
|
3
|
+
require 'cloudflare_rails/version'
|
6
4
|
|
7
5
|
Gem::Specification.new do |spec|
|
8
|
-
spec.name =
|
9
|
-
spec.version =
|
10
|
-
spec.authors = [
|
11
|
-
spec.email = [
|
12
|
-
|
13
|
-
spec.
|
14
|
-
spec.
|
15
|
-
spec.
|
16
|
-
spec.license = "MIT"
|
6
|
+
spec.name = 'cloudflare-rails'
|
7
|
+
spec.version = CloudflareRails::VERSION
|
8
|
+
spec.authors = ['jonathan schatz']
|
9
|
+
spec.email = ['modosc@users.noreply.github.com']
|
10
|
+
spec.summary = 'This gem configures Rails for CloudFlare so that request.ip and request.remote_ip and work correctly.'
|
11
|
+
spec.description = ''
|
12
|
+
spec.homepage = 'https://github.com/modosc/cloudflare-rails'
|
13
|
+
spec.license = 'MIT'
|
17
14
|
|
18
15
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
19
|
-
spec.bindir =
|
16
|
+
spec.bindir = 'exe'
|
20
17
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
-
spec.require_paths = [
|
18
|
+
spec.require_paths = ['lib']
|
22
19
|
|
23
|
-
spec.add_development_dependency
|
24
|
-
spec.add_development_dependency
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
27
|
-
spec.add_development_dependency
|
28
|
-
spec.add_development_dependency
|
29
|
-
spec.add_development_dependency
|
30
|
-
spec.add_development_dependency
|
31
|
-
spec.add_development_dependency
|
32
|
-
spec.add_development_dependency
|
20
|
+
spec.add_development_dependency 'appraisal', '~> 2.5.0'
|
21
|
+
spec.add_development_dependency 'bundler', '>= 2.1.2'
|
22
|
+
spec.add_development_dependency 'pry-byebug'
|
23
|
+
spec.add_development_dependency 'rack-attack', '~> 6.7.0'
|
24
|
+
spec.add_development_dependency 'rake', '~> 13.1.0'
|
25
|
+
spec.add_development_dependency 'rspec', '~> 3.12.0'
|
26
|
+
spec.add_development_dependency 'rspec_junit_formatter', '~> 0.6.0'
|
27
|
+
spec.add_development_dependency 'rspec-rails', '~> 6.1.0'
|
28
|
+
spec.add_development_dependency 'rubocop', '~> 1.58.0'
|
29
|
+
spec.add_development_dependency 'rubocop-performance', '~> 1.19.1'
|
30
|
+
spec.add_development_dependency 'rubocop-rails', '~> 2.22.2'
|
31
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 2.25.0'
|
32
|
+
spec.add_development_dependency 'webmock', '~> 3.19.1'
|
33
33
|
|
34
|
-
spec.add_dependency
|
35
|
-
spec.add_dependency
|
36
|
-
spec.add_dependency
|
34
|
+
spec.add_dependency 'actionpack', '>= 6.1', '< 7.2.0'
|
35
|
+
spec.add_dependency 'activesupport', '>= 6.1', '< 7.2.0'
|
36
|
+
spec.add_dependency 'railties', '>= 6.1', '< 7.2.0'
|
37
|
+
spec.add_dependency 'zeitwerk', '>= 2.5.0'
|
37
38
|
|
38
|
-
#
|
39
|
-
spec.required_ruby_version = '>= 2.0'
|
39
|
+
# rails 6.1 lists this as the minimum
|
40
|
+
spec.required_ruby_version = '>= 2.5.0'
|
41
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
40
42
|
end
|
data/gemfiles/rails_6.1.gemfile
CHANGED
data/gemfiles/rails_7.0.gemfile
CHANGED
data/gemfiles/rails_7.1.gemfile
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
module CloudflareRails
|
2
|
+
# patch rack::request::helpers to use our cloudflare ips - this way request.ip is
|
3
|
+
# correct inside of rack and rails
|
4
|
+
module CheckTrustedProxies
|
5
|
+
def trusted_proxy?(ip)
|
6
|
+
matching = Importer.cloudflare_ips.any? do |proxy|
|
7
|
+
proxy === ip
|
8
|
+
rescue IPAddr::InvalidAddressError
|
9
|
+
end
|
10
|
+
matching || super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CloudflareRails
|
4
|
+
module FallbackIps
|
5
|
+
# fetched from https://www.cloudflare.com/ips-v4/ on 2023-12-10
|
6
|
+
IPS_V4_BODY = <<~EOM
|
7
|
+
173.245.48.0/20
|
8
|
+
103.21.244.0/22
|
9
|
+
103.22.200.0/22
|
10
|
+
103.31.4.0/22
|
11
|
+
141.101.64.0/18
|
12
|
+
108.162.192.0/18
|
13
|
+
190.93.240.0/20
|
14
|
+
188.114.96.0/20
|
15
|
+
197.234.240.0/22
|
16
|
+
198.41.128.0/17
|
17
|
+
162.158.0.0/15
|
18
|
+
104.16.0.0/13
|
19
|
+
104.24.0.0/14
|
20
|
+
172.64.0.0/13
|
21
|
+
131.0.72.0/22
|
22
|
+
EOM
|
23
|
+
|
24
|
+
# convert our body into a list of IpAddrs
|
25
|
+
IPS_V4 = IPS_V4_BODY.split("\n").map { |ip| IPAddr.new ip }.freeze
|
26
|
+
|
27
|
+
# from https://www.cloudflare.com/ips-v6/ on 2023-12-10
|
28
|
+
IPS_V6_BODY = <<~EOM
|
29
|
+
2400:cb00::/32
|
30
|
+
2606:4700::/32
|
31
|
+
2803:f800::/32
|
32
|
+
2405:b500::/32
|
33
|
+
2405:8100::/32
|
34
|
+
2a06:98c0::/29
|
35
|
+
2c0f:f248::/32
|
36
|
+
EOM
|
37
|
+
|
38
|
+
# convert our body into a list of IpAddrs
|
39
|
+
IPS_V6 = IPS_V6_BODY.split("\n").map { |ip| IPAddr.new ip }.freeze
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module CloudflareRails
|
5
|
+
class Importer
|
6
|
+
# Exceptions contain the Net::HTTP
|
7
|
+
# response object accessible via the {#response} method.
|
8
|
+
class ResponseError < StandardError
|
9
|
+
# Returns the response of the last request
|
10
|
+
# @return [Net::HTTPResponse] A subclass of Net::HTTPResponse, e.g.
|
11
|
+
# Net::HTTPOK
|
12
|
+
attr_reader :response
|
13
|
+
|
14
|
+
# Instantiate an instance of ResponseError with a Net::HTTPResponse object
|
15
|
+
# @param [Net::HTTPResponse]
|
16
|
+
def initialize(response)
|
17
|
+
@response = response
|
18
|
+
super(response)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
BASE_URL = 'https://www.cloudflare.com'.freeze
|
23
|
+
IPS_V4_URL = '/ips-v4/'.freeze
|
24
|
+
IPS_V6_URL = '/ips-v6/'.freeze
|
25
|
+
|
26
|
+
class << self
|
27
|
+
def ips_v6
|
28
|
+
fetch IPS_V6_URL
|
29
|
+
end
|
30
|
+
|
31
|
+
def ips_v4
|
32
|
+
fetch IPS_V4_URL
|
33
|
+
end
|
34
|
+
|
35
|
+
def fetch(url)
|
36
|
+
uri = URI("#{BASE_URL}#{url}")
|
37
|
+
|
38
|
+
resp = Net::HTTP.start(uri.host,
|
39
|
+
uri.port,
|
40
|
+
use_ssl: true,
|
41
|
+
read_timeout: Rails.application.config.cloudflare.timeout) do |http|
|
42
|
+
req = Net::HTTP::Get.new(uri)
|
43
|
+
|
44
|
+
http.request(req)
|
45
|
+
end
|
46
|
+
|
47
|
+
raise ResponseError, resp unless resp.is_a?(Net::HTTPSuccess)
|
48
|
+
|
49
|
+
resp.body.split("\n").reject(&:blank?).map { |ip| IPAddr.new ip }
|
50
|
+
end
|
51
|
+
|
52
|
+
def fetch_with_cache(type)
|
53
|
+
Rails.cache.fetch("cloudflare-rails:#{type}", expires_in: Rails.application.config.cloudflare.expires_in) do
|
54
|
+
send type
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def cloudflare_ips(refresh: false)
|
59
|
+
@ips = nil if refresh
|
60
|
+
@ips ||= (Importer.fetch_with_cache(:ips_v4) + Importer.fetch_with_cache(:ips_v6)).freeze
|
61
|
+
rescue StandardError => e
|
62
|
+
Rails.logger.error "cloudflare-rails: error fetching ip addresses from Cloudflare (#{e}), falling back to defaults"
|
63
|
+
CloudflareRails::FallbackIps::IPS_V4 + CloudflareRails::FallbackIps::IPS_V6
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'active_support/core_ext/integer/time'
|
2
|
+
|
3
|
+
module CloudflareRails
|
4
|
+
class Railtie < Rails::Railtie
|
5
|
+
# setup defaults before we configure our app.
|
6
|
+
DEFAULTS = {
|
7
|
+
expires_in: 12.hours,
|
8
|
+
timeout: 5.seconds
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
config.before_configuration do |app|
|
12
|
+
app.config.cloudflare = ActiveSupport::OrderedOptions.new
|
13
|
+
app.config.cloudflare.reverse_merge! DEFAULTS
|
14
|
+
end
|
15
|
+
|
16
|
+
initializer 'cloudflare_rails.configure_rails_initialization' do
|
17
|
+
Rack::Request::Helpers.prepend CheckTrustedProxies
|
18
|
+
|
19
|
+
ObjectSpace.each_object(Class)
|
20
|
+
.select do |c|
|
21
|
+
c.included_modules.include?(Rack::Request::Helpers) &&
|
22
|
+
c.included_modules.exclude?(CheckTrustedProxies)
|
23
|
+
end
|
24
|
+
.map { |c| c.prepend CheckTrustedProxies }
|
25
|
+
|
26
|
+
ActionDispatch::RemoteIp.prepend RemoteIpProxies
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudflare-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jonathan schatz
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-12-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: appraisal
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.5.0
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.5.0
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -25,47 +39,47 @@ dependencies:
|
|
25
39
|
- !ruby/object:Gem::Version
|
26
40
|
version: 2.1.2
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
42
|
+
name: pry-byebug
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
|
-
- - "
|
45
|
+
- - ">="
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
47
|
+
version: '0'
|
34
48
|
type: :development
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
|
-
- - "
|
52
|
+
- - ">="
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
56
|
+
name: rack-attack
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
59
|
- - "~>"
|
46
60
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
61
|
+
version: 6.7.0
|
48
62
|
type: :development
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
66
|
- - "~>"
|
53
67
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
68
|
+
version: 6.7.0
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
70
|
+
name: rake
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
73
|
- - "~>"
|
60
74
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
75
|
+
version: 13.1.0
|
62
76
|
type: :development
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
80
|
- - "~>"
|
67
81
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
82
|
+
version: 13.1.0
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: rspec
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,77 +95,105 @@ dependencies:
|
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: 3.12.0
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
98
|
+
name: rspec_junit_formatter
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
86
100
|
requirements:
|
87
101
|
- - "~>"
|
88
102
|
- !ruby/object:Gem::Version
|
89
|
-
version: 6.0
|
103
|
+
version: 0.6.0
|
90
104
|
type: :development
|
91
105
|
prerelease: false
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
93
107
|
requirements:
|
94
108
|
- - "~>"
|
95
109
|
- !ruby/object:Gem::Version
|
96
|
-
version: 6.0
|
110
|
+
version: 0.6.0
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
112
|
+
name: rspec-rails
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
100
114
|
requirements:
|
101
115
|
- - "~>"
|
102
116
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
117
|
+
version: 6.1.0
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
122
|
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
124
|
+
version: 6.1.0
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
126
|
+
name: rubocop
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
114
128
|
requirements:
|
115
129
|
- - "~>"
|
116
130
|
- !ruby/object:Gem::Version
|
117
|
-
version:
|
131
|
+
version: 1.58.0
|
118
132
|
type: :development
|
119
133
|
prerelease: false
|
120
134
|
version_requirements: !ruby/object:Gem::Requirement
|
121
135
|
requirements:
|
122
136
|
- - "~>"
|
123
137
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
138
|
+
version: 1.58.0
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
140
|
+
name: rubocop-performance
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
128
142
|
requirements:
|
129
|
-
- - "
|
143
|
+
- - "~>"
|
130
144
|
- !ruby/object:Gem::Version
|
131
|
-
version:
|
145
|
+
version: 1.19.1
|
132
146
|
type: :development
|
133
147
|
prerelease: false
|
134
148
|
version_requirements: !ruby/object:Gem::Requirement
|
135
149
|
requirements:
|
136
|
-
- - "
|
150
|
+
- - "~>"
|
137
151
|
- !ruby/object:Gem::Version
|
138
|
-
version:
|
152
|
+
version: 1.19.1
|
139
153
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
154
|
+
name: rubocop-rails
|
141
155
|
requirement: !ruby/object:Gem::Requirement
|
142
156
|
requirements:
|
143
157
|
- - "~>"
|
144
158
|
- !ruby/object:Gem::Version
|
145
|
-
version: 2.
|
159
|
+
version: 2.22.2
|
146
160
|
type: :development
|
147
161
|
prerelease: false
|
148
162
|
version_requirements: !ruby/object:Gem::Requirement
|
149
163
|
requirements:
|
150
164
|
- - "~>"
|
151
165
|
- !ruby/object:Gem::Version
|
152
|
-
version: 2.
|
166
|
+
version: 2.22.2
|
153
167
|
- !ruby/object:Gem::Dependency
|
154
|
-
name:
|
168
|
+
name: rubocop-rspec
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 2.25.0
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: 2.25.0
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: webmock
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - "~>"
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: 3.19.1
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - "~>"
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: 3.19.1
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: actionpack
|
155
197
|
requirement: !ruby/object:Gem::Requirement
|
156
198
|
requirements:
|
157
199
|
- - ">="
|
@@ -191,7 +233,7 @@ dependencies:
|
|
191
233
|
- !ruby/object:Gem::Version
|
192
234
|
version: 7.2.0
|
193
235
|
- !ruby/object:Gem::Dependency
|
194
|
-
name:
|
236
|
+
name: railties
|
195
237
|
requirement: !ruby/object:Gem::Requirement
|
196
238
|
requirements:
|
197
239
|
- - ">="
|
@@ -210,6 +252,20 @@ dependencies:
|
|
210
252
|
- - "<"
|
211
253
|
- !ruby/object:Gem::Version
|
212
254
|
version: 7.2.0
|
255
|
+
- !ruby/object:Gem::Dependency
|
256
|
+
name: zeitwerk
|
257
|
+
requirement: !ruby/object:Gem::Requirement
|
258
|
+
requirements:
|
259
|
+
- - ">="
|
260
|
+
- !ruby/object:Gem::Version
|
261
|
+
version: 2.5.0
|
262
|
+
type: :runtime
|
263
|
+
prerelease: false
|
264
|
+
version_requirements: !ruby/object:Gem::Requirement
|
265
|
+
requirements:
|
266
|
+
- - ">="
|
267
|
+
- !ruby/object:Gem::Version
|
268
|
+
version: 2.5.0
|
213
269
|
description: ''
|
214
270
|
email:
|
215
271
|
- modosc@users.noreply.github.com
|
@@ -217,12 +273,11 @@ executables: []
|
|
217
273
|
extensions: []
|
218
274
|
extra_rdoc_files: []
|
219
275
|
files:
|
220
|
-
- ".circleci/config.yml"
|
221
276
|
- ".github/dependabot.yml"
|
277
|
+
- ".github/workflows/ruby.yml"
|
222
278
|
- ".gitignore"
|
223
279
|
- ".rspec"
|
224
280
|
- ".rubocop.yml"
|
225
|
-
- ".rubocop_airbnb.yml"
|
226
281
|
- ".rubocop_todo.yml"
|
227
282
|
- ".ruby-version"
|
228
283
|
- Appraisals
|
@@ -238,13 +293,18 @@ files:
|
|
238
293
|
- gemfiles/rails_6.1.gemfile
|
239
294
|
- gemfiles/rails_7.0.gemfile
|
240
295
|
- gemfiles/rails_7.1.gemfile
|
241
|
-
- lib/
|
242
|
-
- lib/
|
243
|
-
- lib/
|
296
|
+
- lib/cloudflare_rails.rb
|
297
|
+
- lib/cloudflare_rails/check_trusted_proxies.rb
|
298
|
+
- lib/cloudflare_rails/fallback_ips.rb
|
299
|
+
- lib/cloudflare_rails/importer.rb
|
300
|
+
- lib/cloudflare_rails/railtie.rb
|
301
|
+
- lib/cloudflare_rails/remote_ip_proxies.rb
|
302
|
+
- lib/cloudflare_rails/version.rb
|
244
303
|
homepage: https://github.com/modosc/cloudflare-rails
|
245
304
|
licenses:
|
246
305
|
- MIT
|
247
|
-
metadata:
|
306
|
+
metadata:
|
307
|
+
rubygems_mfa_required: 'true'
|
248
308
|
post_install_message:
|
249
309
|
rdoc_options: []
|
250
310
|
require_paths:
|
@@ -253,7 +313,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
253
313
|
requirements:
|
254
314
|
- - ">="
|
255
315
|
- !ruby/object:Gem::Version
|
256
|
-
version:
|
316
|
+
version: 2.5.0
|
257
317
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
258
318
|
requirements:
|
259
319
|
- - ">="
|
data/.circleci/config.yml
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
# Ruby CircleCI 2.0 configuration file
|
2
|
-
#
|
3
|
-
# Check https://circleci.com/docs/2.0/language-ruby/ for more details
|
4
|
-
#
|
5
|
-
version: 2
|
6
|
-
jobs:
|
7
|
-
build:
|
8
|
-
docker:
|
9
|
-
# specify the version you desire here
|
10
|
-
- image: cimg/ruby:2.7
|
11
|
-
|
12
|
-
working_directory: ~/repo
|
13
|
-
|
14
|
-
steps:
|
15
|
-
- checkout
|
16
|
-
|
17
|
-
# Download and cache dependencies
|
18
|
-
- restore_cache:
|
19
|
-
keys:
|
20
|
-
- v1-dependencies-{{ checksum "cloudflare-rails.gemspec" }}-{{ checksum "Appraisals" }}
|
21
|
-
# fallback to using the latest cache if no exact match is found
|
22
|
-
- v1-dependencies-
|
23
|
-
|
24
|
-
- run:
|
25
|
-
name: install bundler
|
26
|
-
command: |
|
27
|
-
gem install bundler -v $(grep bundler cloudflare-rails.gemspec |awk {'print $4'}|sed 's/"//g')
|
28
|
-
|
29
|
-
- run:
|
30
|
-
name: install dependencies
|
31
|
-
command: |
|
32
|
-
bundle install --jobs=4 --retry=3 --path vendor/bundle
|
33
|
-
|
34
|
-
- run:
|
35
|
-
name: install appraisal versions
|
36
|
-
command: |
|
37
|
-
bundle exec appraisal install
|
38
|
-
|
39
|
-
- save_cache:
|
40
|
-
paths:
|
41
|
-
- ./vendor/bundle
|
42
|
-
key: v1-dependencies-{{ checksum "cloudflare-rails.gemspec" }}-{{ checksum "Appraisals" }}
|
43
|
-
|
44
|
-
# run tests!
|
45
|
-
- run:
|
46
|
-
name: run tests
|
47
|
-
command: |
|
48
|
-
bundle exec appraisal rake
|
49
|
-
# collect reports
|
50
|
-
- store_test_results:
|
51
|
-
path: tmp/rspec
|
52
|
-
- store_artifacts:
|
53
|
-
path: tmp/rspec
|
54
|
-
destination: test-results
|
data/.rubocop_airbnb.yml
DELETED
@@ -1,117 +0,0 @@
|
|
1
|
-
require "active_support/core_ext/integer/time"
|
2
|
-
|
3
|
-
module Cloudflare
|
4
|
-
module Rails
|
5
|
-
class Railtie < ::Rails::Railtie
|
6
|
-
# patch rack::request::helpers to use our cloudflare ips - this way request.ip is
|
7
|
-
# correct inside of rack and rails
|
8
|
-
module CheckTrustedProxies
|
9
|
-
def trusted_proxy?(ip)
|
10
|
-
matching = Importer.cloudflare_ips.any? do |proxy|
|
11
|
-
proxy === ip
|
12
|
-
rescue IPAddr::InvalidAddressError
|
13
|
-
end
|
14
|
-
matching || super
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
# patch ActionDispatch::RemoteIP to use our cloudflare ips - this way
|
19
|
-
# request.remote_ip is correct inside of rails
|
20
|
-
module RemoteIpProxies
|
21
|
-
def proxies
|
22
|
-
super + Importer.cloudflare_ips
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
class Importer
|
27
|
-
# Exceptions contain the Net::HTTP
|
28
|
-
# response object accessible via the {#response} method.
|
29
|
-
class ResponseError < StandardError
|
30
|
-
# Returns the response of the last request
|
31
|
-
# @return [Net::HTTPResponse] A subclass of Net::HTTPResponse, e.g.
|
32
|
-
# Net::HTTPOK
|
33
|
-
attr_reader :response
|
34
|
-
|
35
|
-
# Instantiate an instance of ResponseError with a Net::HTTPResponse object
|
36
|
-
# @param [Net::HTTPResponse]
|
37
|
-
def initialize(response)
|
38
|
-
@response = response
|
39
|
-
super(response)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
BASE_URL = 'https://www.cloudflare.com'.freeze
|
44
|
-
IPS_V4_URL = '/ips-v4/'.freeze
|
45
|
-
IPS_V6_URL = '/ips-v6/'.freeze
|
46
|
-
|
47
|
-
class << self
|
48
|
-
def ips_v6
|
49
|
-
fetch IPS_V6_URL
|
50
|
-
end
|
51
|
-
|
52
|
-
def ips_v4
|
53
|
-
fetch IPS_V4_URL
|
54
|
-
end
|
55
|
-
|
56
|
-
def fetch(url)
|
57
|
-
uri = URI("#{BASE_URL}#{url}")
|
58
|
-
|
59
|
-
resp = Net::HTTP.start(uri.host,
|
60
|
-
uri.port,
|
61
|
-
use_ssl: true,
|
62
|
-
read_timeout: ::Rails.application.config.cloudflare.timeout) do |http|
|
63
|
-
req = Net::HTTP::Get.new(uri)
|
64
|
-
|
65
|
-
http.request(req)
|
66
|
-
end
|
67
|
-
|
68
|
-
if resp.is_a?(Net::HTTPSuccess)
|
69
|
-
resp.body.split("\n").reject(&:blank?).map { |ip| IPAddr.new ip }
|
70
|
-
else
|
71
|
-
raise ResponseError, resp
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def fetch_with_cache(type)
|
76
|
-
::Rails.cache.fetch("cloudflare-rails:#{type}", expires_in: ::Rails.application.config.cloudflare.expires_in) do
|
77
|
-
send type
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def cloudflare_ips(refresh: false)
|
82
|
-
@ips = nil if refresh
|
83
|
-
@ips ||= (Importer.fetch_with_cache(:ips_v4) + Importer.fetch_with_cache(:ips_v6)).freeze
|
84
|
-
rescue StandardError => e
|
85
|
-
::Rails.logger.error(e)
|
86
|
-
[]
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
# setup defaults before we configure our app.
|
92
|
-
DEFAULTS = {
|
93
|
-
expires_in: 12.hours,
|
94
|
-
timeout: 5.seconds,
|
95
|
-
ips: [],
|
96
|
-
}.freeze
|
97
|
-
|
98
|
-
config.before_configuration do |app|
|
99
|
-
app.config.cloudflare = ActiveSupport::OrderedOptions.new
|
100
|
-
app.config.cloudflare.reverse_merge! DEFAULTS
|
101
|
-
end
|
102
|
-
|
103
|
-
initializer "cloudflare_rails.configure_rails_initialization" do
|
104
|
-
Rack::Request::Helpers.prepend CheckTrustedProxies
|
105
|
-
|
106
|
-
ObjectSpace.each_object(Class).
|
107
|
-
select do |c|
|
108
|
-
c.included_modules.include?(Rack::Request::Helpers) &&
|
109
|
-
!c.included_modules.include?(CheckTrustedProxies)
|
110
|
-
end.
|
111
|
-
map { |c| c .prepend CheckTrustedProxies }
|
112
|
-
|
113
|
-
ActionDispatch::RemoteIp.prepend RemoteIpProxies
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|