firebase_hosting_client_ip 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.release-please-config.json +12 -0
- data/.release-please-manifest.json +3 -0
- data/CHANGELOG.md +107 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/LICENSE +21 -0
- data/LICENSE.txt +21 -0
- data/README.md +113 -0
- data/Rakefile +26 -0
- data/lib/firebase_hosting_client_ip/middleware.rb +48 -0
- data/lib/firebase_hosting_client_ip/railtie.rb +21 -0
- data/lib/firebase_hosting_client_ip/version.rb +5 -0
- data/lib/firebase_hosting_client_ip.rb +10 -0
- data/sig/firebase_hosting_client_ip.rbs +4 -0
- metadata +77 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: b012d81af7631be9a9551d6114c7bf2a29d08e973fdea0a057461fec07de7911
|
|
4
|
+
data.tar.gz: fc91c590d8f7549d650e4558052f42440c4824a87092d2ed87e64114c3f38451
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 8f744b0bcd86c4c70108ed012809706881f9889cebddacc7ce5333d7f480c8429e7eae2f0bda311022f0eaed3432044b5777fb56e6b8b1d3ee70d0ef3cee40a5
|
|
7
|
+
data.tar.gz: c3ab68b3ed07823de0f76a20edd8431f906a99f1d50c0ddd1512c85620921d779232bc0f966f64fc529a24a433b4dce649be5f23bd7ac09e0dbe1689d593605b
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
|
|
3
|
+
"packages": {
|
|
4
|
+
".": {
|
|
5
|
+
"release-type": "ruby",
|
|
6
|
+
"version-file": "lib/firebase_hosting_client_ip/version.rb",
|
|
7
|
+
"changelog-path": "CHANGELOG.md",
|
|
8
|
+
"bump-minor-pre-major": false,
|
|
9
|
+
"bump-patch-for-minor-pre-major": false
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
## [Unreleased]
|
|
2
|
+
|
|
3
|
+
## [0.3.0](https://github.com/quintsys/firebase_hosting_client_ip/compare/v0.2.2...v0.3.0) (2025-12-13)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add Rails 8 support ([#26](https://github.com/quintsys/firebase_hosting_client_ip/issues/26)) ([b65d462](https://github.com/quintsys/firebase_hosting_client_ip/commit/b65d4624a3e0a8a185fa0aeabaca581f10fdc7c1))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* add explicit permissions to CI workflow ([#12](https://github.com/quintsys/firebase_hosting_client_ip/issues/12)) ([0cd88a1](https://github.com/quintsys/firebase_hosting_client_ip/commit/0cd88a135ed01aeb4e9bf122c6e864f75d647565))
|
|
14
|
+
* add workflow_dispatch to publish-gem workflow ([3da9e8f](https://github.com/quintsys/firebase_hosting_client_ip/commit/3da9e8f933d132bd50b758dc20570e8fdd6299f8))
|
|
15
|
+
* exclude development and test groups in publish workflow ([#34](https://github.com/quintsys/firebase_hosting_client_ip/issues/34)) ([323a631](https://github.com/quintsys/firebase_hosting_client_ip/commit/323a63136691054ac24e4067664b8bdf2cfbfb8f))
|
|
16
|
+
* make Rakefile conditional to avoid requiring dev dependencies ([#32](https://github.com/quintsys/firebase_hosting_client_ip/issues/32)) ([86c6b3e](https://github.com/quintsys/firebase_hosting_client_ip/commit/86c6b3ee025c6b4395a4447cf1f090503a989bb7))
|
|
17
|
+
* move Rails to development group to exclude from publishing ([#28](https://github.com/quintsys/firebase_hosting_client_ip/issues/28)) ([3e66e2c](https://github.com/quintsys/firebase_hosting_client_ip/commit/3e66e2c17a49c4b564018844163f046637224688))
|
|
18
|
+
* remove double trigger and install dependencies for release-gem ([#21](https://github.com/quintsys/firebase_hosting_client_ip/issues/21)) ([01aa104](https://github.com/quintsys/firebase_hosting_client_ip/commit/01aa104633df849f0ade5d89e94b3ad010e47434))
|
|
19
|
+
* replace non-existent gem-push-action with standard gem commands ([#11](https://github.com/quintsys/firebase_hosting_client_ip/issues/11)) ([0bf888a](https://github.com/quintsys/firebase_hosting_client_ip/commit/0bf888a3f9a5e2d6ce15accc1b4f422bda0d711f))
|
|
20
|
+
* trigger publish workflow after release-please creates release ([#16](https://github.com/quintsys/firebase_hosting_client_ip/issues/16)) ([551ff18](https://github.com/quintsys/firebase_hosting_client_ip/commit/551ff1867ad7d28600fe94876f551015d6294fe3))
|
|
21
|
+
* update release-please action to non-deprecated version ([#8](https://github.com/quintsys/firebase_hosting_client_ip/issues/8)) ([1463650](https://github.com/quintsys/firebase_hosting_client_ip/commit/14636502355a7a387c561ca38c9fb64f00aa0265))
|
|
22
|
+
* use official rubygems/release-gem action for publishing ([#18](https://github.com/quintsys/firebase_hosting_client_ip/issues/18)) ([4532dac](https://github.com/quintsys/firebase_hosting_client_ip/commit/4532dacfb193ae0aa553366468e9f1448cb5cc5f))
|
|
23
|
+
* use PAT instead of GITHUB_TOKEN for release-please ([#20](https://github.com/quintsys/firebase_hosting_client_ip/issues/20)) ([c87d8e6](https://github.com/quintsys/firebase_hosting_client_ip/commit/c87d8e623ea4ddb75b39ba20a8a9ffa4a9865be6))
|
|
24
|
+
* use published event and OIDC auth for gem publishing ([#13](https://github.com/quintsys/firebase_hosting_client_ip/issues/13)) ([a1a9472](https://github.com/quintsys/firebase_hosting_client_ip/commit/a1a9472637302d6a655e864e9e530931c24bc1dd))
|
|
25
|
+
|
|
26
|
+
## [0.2.2](https://github.com/quintsys/firebase_hosting_client_ip/compare/v0.2.1...v0.2.2) (2025-12-13)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### Bug Fixes
|
|
30
|
+
|
|
31
|
+
* make Rakefile conditional to avoid requiring dev dependencies ([#32](https://github.com/quintsys/firebase_hosting_client_ip/issues/32)) ([86c6b3e](https://github.com/quintsys/firebase_hosting_client_ip/commit/86c6b3ee025c6b4395a4447cf1f090503a989bb7))
|
|
32
|
+
|
|
33
|
+
## [0.2.1](https://github.com/quintsys/firebase_hosting_client_ip/compare/v0.2.0...v0.2.1) (2025-12-13)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
### Bug Fixes
|
|
37
|
+
|
|
38
|
+
* move Rails to development group to exclude from publishing ([#28](https://github.com/quintsys/firebase_hosting_client_ip/issues/28)) ([3e66e2c](https://github.com/quintsys/firebase_hosting_client_ip/commit/3e66e2c17a49c4b564018844163f046637224688))
|
|
39
|
+
|
|
40
|
+
## [0.2.0](https://github.com/quintsys/firebase_hosting_client_ip/compare/v0.1.6...v0.2.0) (2025-12-12)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
### Features
|
|
44
|
+
|
|
45
|
+
* add Rails 8 support ([#26](https://github.com/quintsys/firebase_hosting_client_ip/issues/26)) ([b65d462](https://github.com/quintsys/firebase_hosting_client_ip/commit/b65d4624a3e0a8a185fa0aeabaca581f10fdc7c1))
|
|
46
|
+
|
|
47
|
+
## [0.1.6](https://github.com/quintsys/firebase_hosting_client_ip/compare/v0.1.5...v0.1.6) (2025-12-12)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
### Bug Fixes
|
|
51
|
+
|
|
52
|
+
* remove double trigger and install dependencies for release-gem ([#21](https://github.com/quintsys/firebase_hosting_client_ip/issues/21)) ([01aa104](https://github.com/quintsys/firebase_hosting_client_ip/commit/01aa104633df849f0ade5d89e94b3ad010e47434))
|
|
53
|
+
|
|
54
|
+
## [0.1.5](https://github.com/quintsys/firebase_hosting_client_ip/compare/v0.1.4...v0.1.5) (2025-12-12)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
### Bug Fixes
|
|
58
|
+
|
|
59
|
+
* use official rubygems/release-gem action for publishing ([#18](https://github.com/quintsys/firebase_hosting_client_ip/issues/18)) ([4532dac](https://github.com/quintsys/firebase_hosting_client_ip/commit/4532dacfb193ae0aa553366468e9f1448cb5cc5f))
|
|
60
|
+
* use PAT instead of GITHUB_TOKEN for release-please ([#20](https://github.com/quintsys/firebase_hosting_client_ip/issues/20)) ([c87d8e6](https://github.com/quintsys/firebase_hosting_client_ip/commit/c87d8e623ea4ddb75b39ba20a8a9ffa4a9865be6))
|
|
61
|
+
|
|
62
|
+
## [0.1.4](https://github.com/quintsys/firebase_hosting_client_ip/compare/v0.1.3...v0.1.4) (2025-12-12)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
### Bug Fixes
|
|
66
|
+
|
|
67
|
+
* trigger publish workflow after release-please creates release ([#16](https://github.com/quintsys/firebase_hosting_client_ip/issues/16)) ([551ff18](https://github.com/quintsys/firebase_hosting_client_ip/commit/551ff1867ad7d28600fe94876f551015d6294fe3))
|
|
68
|
+
|
|
69
|
+
## [0.1.3](https://github.com/quintsys/firebase_hosting_client_ip/compare/v0.1.2...v0.1.3) (2025-12-12)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
### Bug Fixes
|
|
73
|
+
|
|
74
|
+
* use published event and OIDC auth for gem publishing ([#13](https://github.com/quintsys/firebase_hosting_client_ip/issues/13)) ([a1a9472](https://github.com/quintsys/firebase_hosting_client_ip/commit/a1a9472637302d6a655e864e9e530931c24bc1dd))
|
|
75
|
+
|
|
76
|
+
## [0.1.2](https://github.com/quintsys/firebase_hosting_client_ip/compare/v0.1.1...v0.1.2) (2025-12-12)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
### Bug Fixes
|
|
80
|
+
|
|
81
|
+
* add explicit permissions to CI workflow ([#12](https://github.com/quintsys/firebase_hosting_client_ip/issues/12)) ([0cd88a1](https://github.com/quintsys/firebase_hosting_client_ip/commit/0cd88a135ed01aeb4e9bf122c6e864f75d647565))
|
|
82
|
+
* add workflow_dispatch to publish-gem workflow ([3da9e8f](https://github.com/quintsys/firebase_hosting_client_ip/commit/3da9e8f933d132bd50b758dc20570e8fdd6299f8))
|
|
83
|
+
* replace non-existent gem-push-action with standard gem commands ([#11](https://github.com/quintsys/firebase_hosting_client_ip/issues/11)) ([0bf888a](https://github.com/quintsys/firebase_hosting_client_ip/commit/0bf888a3f9a5e2d6ce15accc1b4f422bda0d711f))
|
|
84
|
+
|
|
85
|
+
## [0.1.1](https://github.com/quintsys/firebase_hosting_client_ip/compare/v0.1.0...v0.1.1) (2025-12-12)
|
|
86
|
+
|
|
87
|
+
### Bug Fixes
|
|
88
|
+
|
|
89
|
+
* update release-please action to non-deprecated version ([#8](https://github.com/quintsys/firebase_hosting_client_ip/issues/8)) ([1463650](https://github.com/quintsys/firebase_hosting_client_ip/commit/14636502355a7a387c561ca38c9fb64f00aa0265))
|
|
90
|
+
|
|
91
|
+
### Features
|
|
92
|
+
|
|
93
|
+
* implement Rails middleware to normalize client IP behind Firebase Hosting ([#5](https://github.com/quintsys/firebase_hosting_client_ip/pull/5))
|
|
94
|
+
* add release-please workflow for automated versioning and publishing ([#7](https://github.com/quintsys/firebase_hosting_client_ip/pull/7))
|
|
95
|
+
|
|
96
|
+
### Documentation
|
|
97
|
+
|
|
98
|
+
* add comprehensive README with usage examples and security disclaimers ([#6](https://github.com/quintsys/firebase_hosting_client_ip/pull/6))
|
|
99
|
+
|
|
100
|
+
### Testing
|
|
101
|
+
|
|
102
|
+
* add RSpec test coverage for middleware and Rails integration ([#6](https://github.com/quintsys/firebase_hosting_client_ip/pull/6))
|
|
103
|
+
* add GitHub Actions CI workflow for automated testing ([#6](https://github.com/quintsys/firebase_hosting_client_ip/pull/6))
|
|
104
|
+
|
|
105
|
+
## [0.1.0] - 2025-12-12
|
|
106
|
+
|
|
107
|
+
- Initial release
|
data/CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
"firebase_hosting_client_ip" follows [The Ruby Community Conduct Guideline](https://www.ruby-lang.org/en/conduct) in all "collaborative space", which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.):
|
|
4
|
+
|
|
5
|
+
* Participants will be tolerant of opposing views.
|
|
6
|
+
* Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
|
|
7
|
+
* When interpreting the words and actions of others, participants should always assume good intentions.
|
|
8
|
+
* Behaviour which can be reasonably considered harassment will not be tolerated.
|
|
9
|
+
|
|
10
|
+
If you have any concerns about behaviour within this project, please contact us at [qbantek@gmail.com](mailto:qbantek@gmail.com).
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Quintero Systems Incorporated
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Erich N Quintero
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# FirebaseHostingClientIp
|
|
2
|
+
|
|
3
|
+
A Rails middleware gem that normalizes client IP addresses when your Rails application is deployed behind Firebase Hosting.
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
When a Rails application is deployed behind Firebase Hosting, the original client IP address is obscured by proxy layers. Rails' default `ActionDispatch::RemoteIp` middleware may not correctly identify the true client IP due to the specific header precedence used by Firebase Hosting's infrastructure.
|
|
8
|
+
|
|
9
|
+
This gem provides a middleware that implements a heuristic precedence order specifically designed for Firebase Hosting's proxy chain, ensuring `request.remote_ip` returns the correct client IP address.
|
|
10
|
+
|
|
11
|
+
## Supported Architecture
|
|
12
|
+
|
|
13
|
+
This gem is designed for the following architecture:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
Client → Firebase Hosting → Rails Application
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Firebase Hosting uses Fastly CDN behind the scenes (this is not a documented feature and is not configurable - all Firebase Hosting users get Fastly CDN automatically). The middleware handles the `HTTP_FASTLY_CLIENT_IP` header that Fastly provides, as well as the `HTTP_X_FORWARDED_FOR` header from the proxy chain.
|
|
20
|
+
|
|
21
|
+
## Intended Use Cases
|
|
22
|
+
|
|
23
|
+
This middleware is useful for:
|
|
24
|
+
|
|
25
|
+
- **Logging**: Accurately log client IP addresses for audit trails and debugging
|
|
26
|
+
- **Analytics**: Track user locations and behavior based on correct IP geolocation
|
|
27
|
+
- **User Experience**: Personalize content based on user location
|
|
28
|
+
- **Security**: Implement IP-based rate limiting or access controls
|
|
29
|
+
|
|
30
|
+
## Security Disclaimer
|
|
31
|
+
|
|
32
|
+
**IMPORTANT**: This middleware trusts HTTP headers (`HTTP_FASTLY_CLIENT_IP` and `HTTP_X_FORWARDED_FOR`) to determine the client IP address. These headers can be spoofed by clients if they have direct access to your application.
|
|
33
|
+
|
|
34
|
+
**This middleware is only safe to use when:**
|
|
35
|
+
- Your Rails application is deployed behind Firebase Hosting (or a trusted proxy/CDN)
|
|
36
|
+
- Direct access to your application is blocked (e.g., via firewall rules)
|
|
37
|
+
- You trust the proxy infrastructure to set these headers correctly
|
|
38
|
+
|
|
39
|
+
**Do not use this middleware if:**
|
|
40
|
+
- Your application is directly accessible from the internet
|
|
41
|
+
- You cannot guarantee that requests pass through Firebase Hosting
|
|
42
|
+
- You need strict security guarantees about IP address authenticity
|
|
43
|
+
|
|
44
|
+
For production deployments, ensure your application only accepts traffic through Firebase Hosting and cannot be accessed directly.
|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
Add this line to your application's Gemfile:
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
gem 'firebase_hosting_client_ip'
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
And then execute:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
bundle install
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Requirements
|
|
61
|
+
|
|
62
|
+
- Ruby >= 3.2.0
|
|
63
|
+
- Rails >= 7.0 (Rails 7, Rails 8, and future versions are supported)
|
|
64
|
+
|
|
65
|
+
The gem automatically works with whatever Rails version is specified in your application's Gemfile.
|
|
66
|
+
|
|
67
|
+
## Usage
|
|
68
|
+
|
|
69
|
+
The middleware is automatically loaded when Rails is detected. No additional configuration is required.
|
|
70
|
+
|
|
71
|
+
The middleware is inserted into the Rails middleware stack after `ActionDispatch::RemoteIp`, ensuring proper precedence in the request processing chain.
|
|
72
|
+
|
|
73
|
+
### Expected Behavior
|
|
74
|
+
|
|
75
|
+
After the middleware processes a request, `request.remote_ip` will return the normalized client IP address according to the following precedence:
|
|
76
|
+
|
|
77
|
+
1. `HTTP_FASTLY_CLIENT_IP` header (if present and not empty)
|
|
78
|
+
2. Left-most value from `HTTP_X_FORWARDED_FOR` header (if present and not empty)
|
|
79
|
+
3. `REMOTE_ADDR` (the direct connection address)
|
|
80
|
+
|
|
81
|
+
### Example
|
|
82
|
+
|
|
83
|
+
```ruby
|
|
84
|
+
class ApplicationController < ActionController::Base
|
|
85
|
+
def index
|
|
86
|
+
# This will return the correct client IP even behind Firebase Hosting
|
|
87
|
+
client_ip = request.remote_ip
|
|
88
|
+
Rails.logger.info "Request from: #{client_ip}"
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Testing the Middleware
|
|
94
|
+
|
|
95
|
+
You can verify the middleware is working by checking the `request.remote_ip` value in your controllers or by inspecting the `REMOTE_ADDR` environment variable in your middleware stack.
|
|
96
|
+
|
|
97
|
+
## Development
|
|
98
|
+
|
|
99
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
100
|
+
|
|
101
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
102
|
+
|
|
103
|
+
## Contributing
|
|
104
|
+
|
|
105
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/quintsys/firebase_hosting_client_ip. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/quintsys/firebase_hosting_client_ip/blob/master/CODE_OF_CONDUCT.md).
|
|
106
|
+
|
|
107
|
+
## License
|
|
108
|
+
|
|
109
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
110
|
+
|
|
111
|
+
## Code of Conduct
|
|
112
|
+
|
|
113
|
+
Everyone interacting in the FirebaseHostingClientIp project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/quintsys/firebase_hosting_client_ip/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
|
|
5
|
+
unless ENV["BUNDLE_WITHOUT"]&.include?("development")
|
|
6
|
+
begin
|
|
7
|
+
require "rspec/core/rake_task"
|
|
8
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
9
|
+
rescue LoadError
|
|
10
|
+
# RSpec is in development group, may not be available
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
begin
|
|
14
|
+
require "rubocop/rake_task"
|
|
15
|
+
RuboCop::RakeTask.new do |task|
|
|
16
|
+
task.options = ["--config", ".rubocop.yml"]
|
|
17
|
+
end
|
|
18
|
+
rescue LoadError
|
|
19
|
+
# RuboCop is in development group, may not be available
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
default_tasks = []
|
|
24
|
+
default_tasks << :spec if Rake::Task.task_defined?(:spec)
|
|
25
|
+
default_tasks << :rubocop if Rake::Task.task_defined?(:rubocop)
|
|
26
|
+
task default: default_tasks unless default_tasks.empty?
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FirebaseHostingClientIp
|
|
4
|
+
class Middleware
|
|
5
|
+
def initialize(app)
|
|
6
|
+
@app = app
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def call(env)
|
|
10
|
+
# Extract the normalized client IP using the precedence rules
|
|
11
|
+
normalized_ip = extract_client_ip(env)
|
|
12
|
+
|
|
13
|
+
# Store the normalized IP in the REMOTE_ADDR so that Rails' request.remote_ip
|
|
14
|
+
# will return it without needing ActionDispatch::RemoteIp to reprocess
|
|
15
|
+
env["REMOTE_ADDR"] = normalized_ip if normalized_ip
|
|
16
|
+
|
|
17
|
+
@app.call(env)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def extract_client_ip(env)
|
|
23
|
+
# Precedence:
|
|
24
|
+
# 1. HTTP_FASTLY_CLIENT_IP (if present and not empty)
|
|
25
|
+
# 2. Left-most value from HTTP_X_FORWARDED_FOR (if present and not empty)
|
|
26
|
+
# 3. Fallback to REMOTE_ADDR (already processed by ActionDispatch::RemoteIp)
|
|
27
|
+
|
|
28
|
+
extract_fastly_ip(env) || extract_forwarded_for_ip(env) || env["REMOTE_ADDR"]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def extract_fastly_ip(env)
|
|
32
|
+
fastly_ip = env["HTTP_FASTLY_CLIENT_IP"]
|
|
33
|
+
fastly_ip = fastly_ip.strip if fastly_ip
|
|
34
|
+
fastly_ip if fastly_ip&.length&.positive?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def extract_forwarded_for_ip(env)
|
|
38
|
+
x_forwarded_for = env["HTTP_X_FORWARDED_FOR"]
|
|
39
|
+
return nil unless x_forwarded_for&.length&.positive?
|
|
40
|
+
|
|
41
|
+
# X-Forwarded-For can contain multiple IPs separated by commas
|
|
42
|
+
# The left-most (first) IP is the original client IP
|
|
43
|
+
ips = x_forwarded_for.split(",").map(&:strip)
|
|
44
|
+
first_ip = ips.first
|
|
45
|
+
first_ip if first_ip&.length&.positive?
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails"
|
|
4
|
+
require_relative "middleware"
|
|
5
|
+
|
|
6
|
+
module FirebaseHostingClientIp
|
|
7
|
+
# Railtie for automatic middleware insertion in Rails applications.
|
|
8
|
+
# Supports Rails 7, Rails 8, and future versions.
|
|
9
|
+
class Railtie < ::Rails::Railtie
|
|
10
|
+
initializer "firebase_hosting_client_ip.insert_middleware",
|
|
11
|
+
after: "action_dispatch.remote_ip" do |app|
|
|
12
|
+
# Insert the middleware after ActionDispatch::RemoteIp
|
|
13
|
+
# This ensures ActionDispatch::RemoteIp has already processed the request
|
|
14
|
+
# and we can normalize the IP accordingly
|
|
15
|
+
app.middleware.insert_after(
|
|
16
|
+
ActionDispatch::RemoteIp,
|
|
17
|
+
FirebaseHostingClientIp::Middleware
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "firebase_hosting_client_ip/version"
|
|
4
|
+
require_relative "firebase_hosting_client_ip/middleware"
|
|
5
|
+
|
|
6
|
+
module FirebaseHostingClientIp
|
|
7
|
+
class Error < StandardError; end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
require_relative "firebase_hosting_client_ip/railtie" if defined?(Rails)
|
metadata
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: firebase_hosting_client_ip
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.3.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Erich N Quintero
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2025-12-13 00:00:00.000000000 Z
|
|
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: '3.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '3.0'
|
|
27
|
+
description: Provides a Rails middleware that resolves the correct client IP when
|
|
28
|
+
an application is deployed behind Firebase Hosting, using a heuristic precedence
|
|
29
|
+
of headers.
|
|
30
|
+
email:
|
|
31
|
+
- qbantek@gmail.com
|
|
32
|
+
executables: []
|
|
33
|
+
extensions: []
|
|
34
|
+
extra_rdoc_files: []
|
|
35
|
+
files:
|
|
36
|
+
- ".release-please-config.json"
|
|
37
|
+
- ".release-please-manifest.json"
|
|
38
|
+
- CHANGELOG.md
|
|
39
|
+
- CODE_OF_CONDUCT.md
|
|
40
|
+
- LICENSE
|
|
41
|
+
- LICENSE.txt
|
|
42
|
+
- README.md
|
|
43
|
+
- Rakefile
|
|
44
|
+
- lib/firebase_hosting_client_ip.rb
|
|
45
|
+
- lib/firebase_hosting_client_ip/middleware.rb
|
|
46
|
+
- lib/firebase_hosting_client_ip/railtie.rb
|
|
47
|
+
- lib/firebase_hosting_client_ip/version.rb
|
|
48
|
+
- sig/firebase_hosting_client_ip.rbs
|
|
49
|
+
homepage: https://github.com/quintsys/firebase_hosting_client_ip
|
|
50
|
+
licenses:
|
|
51
|
+
- MIT
|
|
52
|
+
metadata:
|
|
53
|
+
allowed_push_host: https://rubygems.org
|
|
54
|
+
homepage_uri: https://github.com/quintsys/firebase_hosting_client_ip
|
|
55
|
+
source_code_uri: https://github.com/quintsys/firebase_hosting_client_ip
|
|
56
|
+
changelog_uri: https://github.com/quintsys/firebase_hosting_client_ip/blob/master/CHANGELOG.md
|
|
57
|
+
rubygems_mfa_required: 'true'
|
|
58
|
+
post_install_message:
|
|
59
|
+
rdoc_options: []
|
|
60
|
+
require_paths:
|
|
61
|
+
- lib
|
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
63
|
+
requirements:
|
|
64
|
+
- - ">="
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: 3.2.0
|
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
68
|
+
requirements:
|
|
69
|
+
- - ">="
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
version: '0'
|
|
72
|
+
requirements: []
|
|
73
|
+
rubygems_version: 3.4.19
|
|
74
|
+
signing_key:
|
|
75
|
+
specification_version: 4
|
|
76
|
+
summary: Rails middleware to normalize client IP behind Firebase Hosting
|
|
77
|
+
test_files: []
|