request_info 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ # This project follows the Ribose OSS style guide.
2
+ # https://github.com/riboseinc/oss-guides
3
+ # All project-specific additions and overrides should be specified in this file.
4
+
5
+ inherit_from:
6
+ # Thoughtbot's style guide from: https://github.com/thoughtbot/guides
7
+ - ".rubocop.tb.yml"
8
+ # Overrides from Ribose
9
+ - ".rubocop.ribose.yml"
10
+ AllCops:
11
+ DisplayCopNames: false
12
+ StyleGuideCopsOnly: false
13
+ TargetRubyVersion: 2.2
14
+ Rails:
15
+ Enabled: false
@@ -0,0 +1,45 @@
1
+ dist: trusty
2
+ sudo: required
3
+ language: ruby
4
+
5
+ addons:
6
+ apt:
7
+ sources:
8
+ - sourceline: ppa:maxmind/ppa
9
+ packages:
10
+ - libmaxminddb0
11
+ - libmaxminddb-dev
12
+ - mmdb-bin
13
+
14
+ cache:
15
+ - bundler
16
+
17
+ before_install:
18
+ - gem install bundler -v 1.16.1
19
+
20
+ rvm:
21
+ - "2.2"
22
+ - "2.3"
23
+ - "2.4"
24
+ - "2.5"
25
+ - "ruby-head"
26
+
27
+ gemfile:
28
+ - "gemfiles/Rails-5.1.gemfile"
29
+
30
+ matrix:
31
+ include:
32
+ - rvm: "2.5"
33
+ gemfile: "gemfiles/Rails-5.0.gemfile"
34
+ - rvm: "2.3"
35
+ gemfile: "gemfiles/Rails-4.2.gemfile"
36
+ - rvm: "2.3"
37
+ gemfile: "gemfiles/Rails-4.1.gemfile"
38
+ - rvm: "2.5"
39
+ gemfile: "gemfiles/Rails-head.gemfile"
40
+ - rvm: "2.5"
41
+ env: DISABLE_GEOIP2=1
42
+
43
+ allow_failures:
44
+ - rvm: "ruby-head"
45
+ - gemfile: "gemfiles/Rails-head.gemfile"
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at jeffrey.lau@ribose.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+ # Specify your gem's dependencies in request_info.gemspec
3
+ gemspec
4
+
5
+ gem "maxmind_geoip2"
6
+ gem "simplecov", require: false
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Ribose Inc.
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.
@@ -0,0 +1,178 @@
1
+ = request_info
2
+ :source-highlighter: pygments
3
+
4
+ image:https://img.shields.io/gem/v/request_info.svg["Gem Version", link="https://rubygems.org/gems/request_info"]
5
+ image:https://img.shields.io/travis/riboseinc/request_info/master.svg["Build Status", link="https://travis-ci.org/riboseinc/request_info"]
6
+ image:https://img.shields.io/codecov/c/github/riboseinc/request_info.svg["Test Coverage", link="https://codecov.io/gh/riboseinc/request_info"]
7
+ image:https://img.shields.io/codeclimate/github/riboseinc/request_info.svg["Code Climate", link="https://codeclimate.com/github/riboseinc/request_info"]
8
+
9
+ Request Info is a Rack middleware which analyzes client's IP address and HTTP
10
+ headers in order to provide detailed information about that client,
11
+ particularly:
12
+
13
+ - IP address
14
+ - approximated location (basing on IP)
15
+ - time zone (basing on location)
16
+ - preferred locale (basing on `Accept-Language` header and location)
17
+
18
+ == Usage
19
+
20
+ === Installation
21
+
22
+ Then add this line to your application's `Gemfile`:
23
+
24
+ [source,ruby]
25
+ ----
26
+ gem 'request_info', github: 'riboseinc/request_info'
27
+ ----
28
+
29
+ And then execute:
30
+
31
+ ----
32
+ bundle
33
+ ----
34
+
35
+ Or install it yourself as:
36
+
37
+ ----
38
+ gem install request_info
39
+ ----
40
+
41
+ === Getting started
42
+
43
+ Simply set up a middleware in `config/application.rb` like that:
44
+
45
+ [source,ruby]
46
+ ----
47
+ Rails.application.configure do
48
+ config.middleware.use RequestInfo::DetectorApp
49
+ end
50
+ ----
51
+
52
+ If you have `ActionDispatch::RemoteIp` in your middleware stack, then the
53
+ `RequestInfo::DetectorApp` should be inserted after it. Please do not add
54
+ `ActionDispatch::RemoteIp` to your middleware stack without considering
55
+ potential security issues described in
56
+ http://api.rubyonrails.org/classes/ActionDispatch/RemoteIp.html[Rails documentation].
57
+
58
+ Read more about configuring the middleware stack in
59
+ http://guides.rubyonrails.org/rails_on_rack.html[Rails Guides].
60
+
61
+ Detection results are saved as fiber-local variable which can be conveniently
62
+ accessed later via `RequestInfo.results` method:
63
+
64
+ [source,ruby]
65
+ ----
66
+ RequestInfo.results.class # => RequestInfo::Results
67
+ RequestInfo.results.ip # => "192.0.2.27"
68
+ RequestInfo.results.timezone # => #<TZInfo::DataTimezone: Asia/Hong_Kong>
69
+ ----
70
+
71
+ === IP geolocalization
72
+
73
+ This gem can use MaxMind IP intelligence databases for IP address
74
+ geolocalization. It is optional, but several detections rely on it.
75
+
76
+ 1. Make sure that `libmaxminddb` is available. You'll find detailed
77
+ instructions https://github.com/maxmind/libmaxminddb[here].
78
+
79
+ 2. Add https://rubygems.org/gems/maxmind_geoip2[`maxmind_geoip2`] gem to your
80
+ Gemfile.
81
+
82
+ 3. Download a City or Country database in binary format from
83
+ https://dev.maxmind.com/geoip[Maxmind]. Both free of charge GeoLite2, and more
84
+ detailed but paid GeoIP2 databases will work.
85
+
86
+ 4. Configure database path
87
+ +
88
+ [source,ruby]
89
+ ----
90
+ RequestInfo.configure do |config|
91
+ config.geoip2_db_path = "path/to/downloaded/mmdb/database"
92
+ end
93
+ ----
94
+
95
+ === Detections
96
+
97
+ As mentioned above, analysis results are accessible via `RequestInfo.results`
98
+ method. The object returned by this method responds to following getters:
99
+
100
+ [cols="1,3" options="header"]
101
+ |===============================================================================
102
+ | Field
103
+ | Description
104
+
105
+ 2+^h| Browser detections
106
+
107
+ | `browser`
108
+ | A `Browser` object which holds details about user agent. See `browser` gem
109
+ https://github.com/fnando/browser[documentation] for more details.
110
+
111
+ 2+^h| IP detections
112
+
113
+ | `ip`
114
+ | Client's remote IP address which is obtained either from
115
+ http://api.rubyonrails.org/classes/ActionDispatch/RemoteIp.html[`ActionDispatch::RemoteIp`]
116
+ middleware (if available), or
117
+ http://www.rubydoc.info/gems/rack/Rack/Request/Helpers#ip-instance_method[`Rack::Request`]
118
+ object (otherwise).
119
+
120
+ | `ipinfo`
121
+ | A hash with detailed information about user location which is guessed by
122
+ looking at client's IP address (requires GeoIP2 or GeoLite2).
123
+
124
+ 2+^h| Locale detections
125
+
126
+ | `locale`
127
+ | Best-matching locale from available ones. First `Accept-Language` header is
128
+ checked, then locales popular in client's country (according to IP address,
129
+ requires GeoIP2 or GeoLite2). If neither matching locale is available,
130
+ then the default one is used.
131
+
132
+ 2+^h| Time zone detections
133
+
134
+ | `timezone`
135
+ | An instance of `TZInfo::Timezone` respective to detected time zone (requires
136
+ GeoIP2 or GeoLite2).
137
+
138
+ | `timezone_id`
139
+ | An identifier of detected time zone, e.g. `"Europe/Warsaw"` (requires GeoIP2
140
+ or GeoLite2).
141
+
142
+ | `timezone_offset`
143
+ | Detected time zone offset as a floating point number, e.g. `1.0`. In other
144
+ words, how many hours UTC is behind the detected time zone (requires GeoIP2 or
145
+ GeoLite2).
146
+
147
+ | `timezone_desc`
148
+ | Human-readable time zone description, e.g. `"GMT(+1.0) Europe - Warsaw"`
149
+ (requires GeoIP2 or GeoLite2).
150
+
151
+ |===============================================================================
152
+
153
+ == Development
154
+
155
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
156
+ `rake spec` to run the tests. You can also run `bin/console` for an interactive
157
+ prompt that will allow you to experiment.
158
+
159
+ You will need to have gem libmaxminddb installed in your machine before running 'bin/setup'.
160
+ If you do not have it setup please follow the steps outlined in this gist
161
+ https://gist.github.com/leonardteo/9a128bc8ca983fa728aa08d8209e714a, as as homebrew install
162
+ will not work.
163
+
164
+ === Contributing
165
+
166
+ Bug reports and pull requests are welcome on GitHub at
167
+ https://github.com/riboseinc/request_info. This project is intended to be a
168
+ safe, welcoming space for collaboration, and contributors are expected to
169
+ adhere to the http://contributor-covenant.org[Contributor Covenant] code of
170
+ conduct.
171
+
172
+ == License
173
+
174
+ The gem is available as open source under the terms of the
175
+ http://opensource.org/licenses/MIT[MIT License].
176
+
177
+ This repository contains a copy of GeoLite2 City database created by Maxmind,
178
+ and licensed on https://creativecommons.org/licenses/by-sa/4.0[CC BY-SA 4.0].
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec # rubocop:disable Style/HashSyntax
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'bundle' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "rubygems"
12
+
13
+ m = Module.new do
14
+ module_function
15
+
16
+ def invoked_as_script?
17
+ File.expand_path($0) == File.expand_path(__FILE__)
18
+ end
19
+
20
+ def env_var_version
21
+ ENV["BUNDLER_VERSION"]
22
+ end
23
+
24
+ def cli_arg_version
25
+ return unless invoked_as_script? # don't want to hijack other binstubs
26
+ return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
27
+ bundler_version = nil
28
+ update_index = nil
29
+ ARGV.each_with_index do |a, i|
30
+ if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
31
+ bundler_version = a
32
+ end
33
+ next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
34
+ bundler_version = $1 || ">= 0.a"
35
+ update_index = i
36
+ end
37
+ bundler_version
38
+ end
39
+
40
+ def gemfile
41
+ gemfile = ENV["BUNDLE_GEMFILE"]
42
+ return gemfile if gemfile && !gemfile.empty?
43
+
44
+ File.expand_path("../../Gemfile", __FILE__)
45
+ end
46
+
47
+ def lockfile
48
+ lockfile =
49
+ case File.basename(gemfile)
50
+ when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
51
+ else "#{gemfile}.lock"
52
+ end
53
+ File.expand_path(lockfile)
54
+ end
55
+
56
+ def lockfile_version
57
+ return unless File.file?(lockfile)
58
+ lockfile_contents = File.read(lockfile)
59
+ return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
60
+ Regexp.last_match(1)
61
+ end
62
+
63
+ def bundler_version
64
+ @bundler_version ||= begin
65
+ env_var_version || cli_arg_version ||
66
+ lockfile_version || "#{Gem::Requirement.default}.a"
67
+ end
68
+ end
69
+
70
+ def load_bundler!
71
+ ENV["BUNDLE_GEMFILE"] ||= gemfile
72
+
73
+ # must dup string for RG < 1.8 compatibility
74
+ activate_bundler(bundler_version.dup)
75
+ end
76
+
77
+ def activate_bundler(bundler_version)
78
+ if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0")
79
+ bundler_version = "< 2"
80
+ end
81
+ gem_error = activation_error_handling do
82
+ gem "bundler", bundler_version
83
+ end
84
+ return if gem_error.nil?
85
+ require_error = activation_error_handling do
86
+ require "bundler/version"
87
+ end
88
+ return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION))
89
+ warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`"
90
+ exit 42
91
+ end
92
+
93
+ def activation_error_handling
94
+ yield
95
+ nil
96
+ rescue StandardError, LoadError => e
97
+ e
98
+ end
99
+ end
100
+
101
+ m.load_bundler!
102
+
103
+ if m.invoked_as_script?
104
+ load Gem.bin_path("bundler", "bundle")
105
+ end