Request Info is a Rack middleware which analyzes client’s IP address and HTTP
headers in order to provide detailed information about that client,
particularly:
IP address
approximated location (basing on IP)
time zone (basing on location)
preferred locale (basing on Accept-Language header and location)
If you have ActionDispatch::RemoteIp in your middleware stack, then the
RequestInfo::DetectorApp should be inserted after it. Please do not add
ActionDispatch::RemoteIp to your middleware stack without considering
potential security issues described in
Rails documentation.
Read more about configuring the middleware stack in
Rails Guides.
Detection results are saved as fiber-local variable which can be conveniently
accessed later via RequestInfo.results method:
Download a City or Country database in binary format from
Maxmind. Both free of charge GeoLite2, and more
detailed but paid GeoIP2 databases will work.
A hash with detailed information about user location which is guessed by
looking at client’s IP address (requires GeoIP2 or GeoLite2).
Locale detections
locale
Best-matching locale from available ones. First Accept-Language header is
checked, then locales popular in client’s country (according to IP address,
requires GeoIP2 or GeoLite2). If neither matching locale is available,
then the default one is used.
Time zone detections
timezone
An instance of TZInfo::Timezone respective to detected time zone (requires
GeoIP2 or GeoLite2).
timezone_id
An identifier of detected time zone, e.g. "Europe/Warsaw" (requires GeoIP2
or GeoLite2).
timezone_offset
Detected time zone offset as a floating point number, e.g. 1.0. In other
words, how many hours UTC is behind the detected time zone (requires GeoIP2 or
GeoLite2).
timezone_desc
Human-readable time zone description, e.g. "GMT(+1.0) Europe - Warsaw"
(requires GeoIP2 or GeoLite2).
Development
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.
You will need to have gem libmaxminddb installed in your machine before running 'bin/setup'.
If you do not have it setup please follow the steps outlined in this gist
https://gist.github.com/leonardteo/9a128bc8ca983fa728aa08d8209e714a, as as homebrew install
will not work.
Contributing
Bug reports and pull requests are welcome on GitHub at
https://github.com/riboseinc/request_info. This project is intended to be a
safe, welcoming space for collaboration, and contributors are expected to
adhere to the Contributor Covenant code of
conduct.
License
The gem is available as open source under the terms of the
MIT License.
This repository contains a copy of GeoLite2 City database created by Maxmind,
and licensed on CC BY-SA 4.0.
There is a class named RequestInfo::LocaleNameMap. It is never referenced, neither it was before my first commit in this project. I am going to delete it, but perhaps it's for some work-in-progress feature?
Depending on new configuration option, set current time zone with Time.zone = detected_time_zone. Currently not done at all.
Depending on new configuration option, set current locale with I18n.locale = detected_locale. Currently always performed, cannot be disabled.
Depending on new configuration option, set Content-Language HTTP header on response to detected locale. Currently always performed, cannot be disabled.
There is a class RequestInfo::CountryLocaleMap which provides mapping between countries and locales popular there. Let's consider moving that mapping into a separate gem as it is generally useful.
Attach some service for test coverage measurement. I suppose CodeCov. Note that there's a Coverity badge in README, but I doubt it was ever working right. I'll replace it with CodeCov badge (or another respective one) when coverage is available for this project.
This gem does not really have much to do with Ruby on Rails, however Rails is a hard dependency right now. We should change it. Also, limiting the dependencies to parts of Rails we actually use is an acceptable temporary solution.
it is easy to spoof IP and lie about client's location.
Currently, the best countermeasure is to rely on Rails' ActionDispatch::RemoteIp middleware. However, (again, as posted in above comments) it requires proper configuration to work correctly. Furthermore, whilst aforementioned middleware is an optional dependency, the gem may produce incorrect results without it, like returning a series of IPs instead of one.
Add README section about IP spoofing, and how to countermeasure it
Provide a more robust way of guessing client IP independent from ActionDispatch::RemoteIp middleware, or skip IP detection when this middleware is missing
I just realised that the LocaleNameMap has been deleted, but we are actually using it in our code. Is there a specific reason for deleting it? Or is it better to move it into a separate gem/repo?
The i18n library takes a pragmatic approach to locale keys (after some discussion), including only the locale ("language") part, like :en, :pl, not the region part, like :en-US or :en-GB, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as :cs, :th or :es (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the :en-US locale you would have $ as a currency symbol, while in :en-GB, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a :en-GB dictionary. Few gems such as Globalize3 may help you implement it.
If locale detected by RequestInfo includes region part (like in :en-GB), make sure that it's in correct case (not :en-gb), be it coming from Accept-Language locales or IP locales.