Code Monkey home page Code Monkey logo

request_info's Introduction

request_info

Gem Version Build Status Test Coverage Code Climate

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)

Usage

Installation

Then add this line to your application’s Gemfile:

gem 'request_info', github: 'riboseinc/request_info'

And then execute:

bundle

Or install it yourself as:

gem install request_info

Getting started

Simply set up a middleware in config/application.rb like that:

Rails.application.configure do
  config.middleware.use RequestInfo::DetectorApp
end

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:

RequestInfo.results.class # => RequestInfo::Results
RequestInfo.results.ip # => "192.0.2.27"
RequestInfo.results.timezone # => #<TZInfo::DataTimezone: Asia/Hong_Kong>

IP geolocalization

This gem can use MaxMind IP intelligence databases for IP address geolocalization. It is optional, but several detections rely on it.

  1. Make sure that libmaxminddb is available. You’ll find detailed instructions here.

  2. Add maxmind_geoip2 gem to your Gemfile.

  3. 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.

  4. Configure database path

    RequestInfo.configure do |config|
      config.geoip2_db_path = "path/to/downloaded/mmdb/database"
    end

Detections

As mentioned above, analysis results are accessible via RequestInfo.results method. The object returned by this method responds to following getters:

Field Description

Browser detections

browser

A Browser object which holds details about user agent. See browser gem documentation for more details.

IP detections

ip

Client’s remote IP address which is obtained either from ActionDispatch::RemoteIp middleware (if available), or Rack::Request object (otherwise).

ipinfo

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.

request_info's People

Contributors

jonathansr avatar kwkwan avatar ribose-jeffreylau avatar skalee avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

request_info's Issues

What is the purpose of LocaleNameMap?

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?

Insufficient documentation

Documentation is non-existent. This is unacceptable.

Document how this Gem is used, what it does and how it does them.

Add more configuration options

  • 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.

Code coverage

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.

Make Rails an optional dependency

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.

IP spoofing issues

As pointed out in xyu.io blog, and comments by @ribose-jeffreylau:

def request_ip(env)
# TODO: for testing, write tests
# return '203.198.150.195'
# Better way to look for the IP most likely to be the address of the actual remote client making this request.
# This method is provided by ActionDispatch::RemoteIp middleware
# This middleware assumes that there is at least one proxy sitting around and setting headers with the client's remote IP address.
# IF YOU DON'T USE A PROXY, THIS MAKES YOU VULNERABLE TO IP SPOOFING.
return env["action_dispatch.remote_ip"].calculate_ip if env["action_dispatch.remote_ip"]
if env['HTTP_X_FORWARDED_FOR']
# The old way, getting the first IP off X_FORWARDED_FOR stack (env['HTTP_X_FORWARDED_FOR'].split(',').first), would leave us with a security hole
# so get the entire stack instead.
# ref: http://www.xyu.io/2013/07/proxies-ip-spoofing/
return env['HTTP_X_FORWARDED_FOR']
end
env["REMOTE_ADDR"]
end
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

Write RSpec tests

There're currently no tests which makes this code base automatically legacy.

Write RSpec tests to cover as much as possible.

Deletion of the LocaleNameMap

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?

Related commits:

Ensure correct case in locales

According to http://guides.rubyonrails.org/i18n.html#configure-the-i18n-module:

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.