devise_sqreener 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c8483e2152547f35ade4e0b7b592e87851a15804
4
+ data.tar.gz: 42ed8c93d34c07d2009831782306a5a4fa45a512
5
+ SHA512:
6
+ metadata.gz: 39e855247d68eff1ec23d0ddb00cd00821baaa702986aa79050a954234c3db48adb0646903ca1df155c71534f9d58c84a67578524a36f7263a4dc99f5db07f40
7
+ data.tar.gz: d5453a6319134d598a4bf50894aa20c32225f321ffad5d36b7da67ef47b42bf8a6b31eeb65c6f1e873c5216d6446d7d63c10458f87f4350919ed0b4b6005695b
@@ -0,0 +1,34 @@
1
+ # Sqreen open source code of conduct
2
+
3
+
4
+ ## Introduction
5
+ Diversity and inclusion make our community strong. We encourage participation from the most varied and diverse backgrounds possible and want to be very clear about where we stand.
6
+
7
+ Our goal is to maintain a safe, helpful and friendly community for everyone, regardless of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other defining characteristic.
8
+
9
+ This code and related procedures also apply to unacceptable behavior occurring outside the scope of community activities, in all community venues (online and in-person) as well as in all one-on-one communications, and anywhere such behavior has the potential to adversely affect the safety and well-being of community members.
10
+
11
+ ## Expected Behavior
12
+ * Be welcoming.
13
+ * Be kind.
14
+ * Look out for each other.
15
+
16
+ ## Unacceptable Behavior
17
+ * Conduct or speech which might be considered sexist, racist, homophobic, transphobic, ableist or otherwise discriminatory or offensive in nature.
18
+ * Unwelcome, suggestive, derogatory or inappropriate nicknames or terms.
19
+ * Disrespect towards others. (Jokes, innuendo, dismissive attitudes.)
20
+ * Intimidation or harassment (online or in-person). Please read the [Citizen Code of Conduct](http://citizencodeofconduct.org/) for how we interpret harassment.
21
+ * Disrespect towards differences of opinion.
22
+ * Inappropriate attention or contact. Be aware of how your actions affect others. If it makes someone uncomfortable, stop.
23
+ * Not understanding the differences between constructive criticism and disparagement.
24
+ * Sustained disruptions.
25
+ * Violence, threats of violence or violent language.
26
+
27
+ ## Enforcement
28
+ Understand that speech and actions have consequences, and unacceptable behavior will not be tolerated.
29
+
30
+ If you are the subject of, or witness to any violations of this Code of Conduct, please contact us by [sending us an email](mailto:hey@sqreen.io).
31
+
32
+ If violations occur, organizers will take any action they deem appropriate for the infraction, up to and including expulsion.
33
+
34
+ _Thanks to the [Django Code of Conduct](https://www.djangoproject.com/conduct/), [The Citizen Code of Conduct](http://citizencodeofconduct.org/), [The Rust Code of Conduct](https://www.rust-lang.org/conduct.html) and [The Ada Initiative](http://adainitiative.org/2014/02/18/howto-design-a-code-of-conduct-for-your-community/)._
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Sqreen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,120 @@
1
+ # devise\_sqreener
2
+
3
+ Add Sqreen API integration to Devise. Whenever a new user sign up or sign in its IP address and email addressed will be sqreened with security metadata. This plugin also provides the ability to block the said sign in/up using simple rules. Blocking people with disposable email, using TOR or geographically has never been easier.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application Gemfile:
8
+
9
+ ```ruby
10
+ gem 'devise_sqreener'
11
+ ```
12
+
13
+ and then execute
14
+ ```bash
15
+ $ bundle
16
+ ```
17
+
18
+ ## Automatic Installation
19
+
20
+ First if you want IP addresses to be sqreened (as it were) ensure your model use Devise `:trackable`.
21
+
22
+ Add devise\_sqreener to any or you Devise models using the following generator:
23
+
24
+ ```bash
25
+ $ rails generate devise_sqreener MODEL
26
+ ```
27
+
28
+ Replace `MODEL` with the class name you want to add devise\_sqreener. This will add the `:sqreenable` flag to your model's Devise modules. The generator will also create a migration file. Currently only ActiveRecord is supported. Then run:
29
+
30
+ ```bash
31
+ $ rails db:migrate
32
+ ```
33
+
34
+ For the automatic sqreening to work you need to provide [your API token](https://my.sqreen.io) into you devise configuration (in `config/initializers/devise.rb`):
35
+ ```ruby
36
+ Devise.setup do |config|
37
+ #...
38
+ config.sqreen_api_token="TOKEN"
39
+ #...
40
+ end
41
+ ```
42
+
43
+ ## Manual Installation
44
+
45
+ First if you want IP addresses to be sqreened (as it were) ensure your model use Devise `:trackable`.
46
+
47
+ Add `:sqreenable` to the devise call in your model:
48
+
49
+ ```ruby
50
+ class User < ActiveRecord
51
+ devise :database_authenticable, :confirmable, :sqreenable
52
+ end
53
+ ```
54
+ Add the necessary fields to your Devise model migration:
55
+
56
+ ```ruby
57
+ class DeviseSqreenerAddToUser < ActiveRecord::Migration
58
+ def change
59
+ add_column :user, :sqreened_email, :text
60
+ # only if you use devise's :trackable
61
+ add_column :user, :current_sqreened_sign_in_ip, :text
62
+ # only if you use devise's :trackable
63
+ add_column :user, :last_sqreened_sign_in_ip, :text
64
+ end
65
+ end
66
+ ```
67
+ Then run:
68
+
69
+ ```bash
70
+ $ rails db:migrate
71
+ ```
72
+
73
+ For the automatic sqreening to work you need to provide [your API token](https://my.sqreen.io) into you devise configuration (in `config/initializers/devise.rb`):
74
+ ```ruby
75
+ Devise.setup do |config|
76
+ #...
77
+ config.sqreen_api_token="TOKEN"
78
+ #...
79
+ end
80
+ ```
81
+
82
+ ## Usage
83
+
84
+ Signups and Signins are automatically sqreened whenever needed. [Sqreened metada](https://www.sqreen.io/developers.html) are automatically added to your model as serialized fields.
85
+ ![Activeadmin Screenshor](/doc/activeadmin.png)
86
+
87
+ ## Blocking signups or signins
88
+
89
+ Blocking sign up or sign in is as easy as adding a predicate in your devise configuration.
90
+
91
+ ```ruby
92
+ Devise.setup do |config|
93
+ #...
94
+ # Block signing in from TOR
95
+ config.sqreen_block_sign_in = -> (email, ip, user) {ip && ip["is_tor"] }
96
+ # Block signing up with a disposable email address
97
+ config.sqreen_block_sign_up = -> (email, ip, user) {email && email["is_disposable"] }
98
+ #...
99
+ end
100
+ ```
101
+
102
+ The arguments always are:
103
+ * `email`: Current email sqreened metadata (a Hash or nil)
104
+ * `ip`: Current ip address sqreened metadata (a Hash or nil)
105
+ * `user`: The current instance of your MODEL class trying to sign in/up.
106
+
107
+ ## Contributing to devise\_sqreener
108
+
109
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
110
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
111
+ * Fork the project.
112
+ * Start a feature/bugfix branch.
113
+ * Commit and push until you are happy with your contribution.
114
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
115
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
116
+
117
+ ## Copyright
118
+
119
+ Copyright (c) 2017 Sqreen. See LICENSE.txt for further details.
120
+
data/Rakefile ADDED
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
17
+ gem.name = "devise_sqreener"
18
+ gem.homepage = "http://github.com/sqreen/devise_sqreener"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{TODO: one-line summary of your gem}
21
+ gem.description = %Q{TODO: longer description of your gem}
22
+ gem.email = "benoit@sqreen.io"
23
+ gem.authors = ["Benoit Larroque"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ desc "Code coverage detail"
36
+ task :simplecov do
37
+ ENV['COVERAGE'] = "true"
38
+ Rake::Task['test'].execute
39
+ end
40
+
41
+ task :default => :test
42
+
43
+ require 'yard'
44
+ YARD::Rake::YardocTask.new
@@ -0,0 +1,16 @@
1
+ # After each authentication check if sign_in should have been authorized.
2
+ # This is only triggered when the user is explicitly set (with set_user)
3
+ # and on authentication. Retrieving the user from session (:fetch) does
4
+ # not trigger it.
5
+ Warden::Manager.prepend_after_set_user :except => :fetch do |record, warden, options|
6
+ if warden.authenticated?(options[:scope]) &&
7
+ record.respond_to?(:current_ip_address=)
8
+ record.current_ip_address = warden.request.remote_ip
9
+ if record.respond_to?(:sqreen_block_sign_in?) &&
10
+ record.sqreen_block_sign_in?
11
+ scope = options[:scope]
12
+ warden.logout(scope)
13
+ throw :warden, :scope => scope, :message => record.inactive_message
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,93 @@
1
+ require 'devise_sqreener/sqreen'
2
+ module Devise
3
+ module Models
4
+ # Sqreen model module, add all necessary behavior to a devise model
5
+ module Sqreenable
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ serialize :sqreened_email
10
+ serialize :current_sqreened_sign_in_ip
11
+ serialize :last_sqreened_sign_in_ip
12
+ before_save :sqreen_email
13
+
14
+ validate :sqreen_block_sign_up?, :on => :create
15
+
16
+ attr_accessor :current_ip_address
17
+ end
18
+
19
+ # DB fields that are needed
20
+ def self.required_fields(klass)
21
+ required_fields = %i(sqreened_email)
22
+ return required_fields unless klass.devise_modules.include?(:trackable)
23
+ required_fields + %i(current_sign_in_ip last_sign_in_ip
24
+ current_sqreened_sign_in_ip
25
+ last_sqreened_sign_in_ip)
26
+ end
27
+
28
+ # The current ip address lazily sqreened
29
+ def current_sqreened_ip_address
30
+ if current_ip_address.present?
31
+ @current_sqreened_ip ||= self.class.sqreener.sqreen_ip(current_ip_address)
32
+ end
33
+ end
34
+
35
+ # The curren email address lazily sqreened
36
+ def current_sqreened_email
37
+ if email.present?
38
+ @current_sqreened_email ||= self.class.sqreener.sqreen_email(email)
39
+ end
40
+ end
41
+
42
+ # Add sqreening behavior to trackable
43
+ # Save last sqreened_ip info
44
+ def update_tracked_fields(request)
45
+ return unless self.class.devise_modules.include?(:trackable)
46
+ self.last_sqreened_sign_in_ip = current_sqreened_sign_in_ip
47
+ self.current_sqreened_sign_in_ip = current_sqreened_ip_address
48
+ super(request)
49
+ end
50
+
51
+ # Should the current sign in be blocked
52
+ def sqreen_block_sign_in?
53
+ oracle = Devise.sqreen_block_sign_in
54
+ return false if oracle.blank? || !oracle.respond_to?(:call)
55
+ oracle.call(current_sqreened_email, current_sqreened_ip_address, self)
56
+ end
57
+
58
+ # Should the current sign up be blocked
59
+ # used as a on_create validation
60
+ def sqreen_block_sign_up?
61
+ return false unless email_changed?
62
+ oracle = Devise.sqreen_block_sign_up
63
+ return false if oracle.blank? || !oracle.respond_to?(:call)
64
+ if oracle.call(current_sqreened_email,
65
+ current_sqreened_ip_address, self)
66
+ errors[:base] = I18n.t(:forbidden, :scope => %i(devise registrations))
67
+ return true
68
+ end
69
+ false
70
+ end
71
+
72
+ # When sign_in was refuse get the correct message
73
+ def inactive_message
74
+ sqreen_block_sign_in? ? :forbidden : super
75
+ end
76
+
77
+ # save sqreened email
78
+ def sqreen_email
79
+ return if email.blank? || !email_changed?
80
+ self.sqreened_email = current_sqreened_email
81
+ end
82
+
83
+ # Class methods
84
+ module ClassMethods
85
+ def sqreener
86
+ DeviseSqreener::Sqreen.new(Devise.sqreen_api_token)
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ require 'devise_sqreener/hook'
@@ -0,0 +1,51 @@
1
+ require 'net/http'
2
+ module DeviseSqreener
3
+ # sqreen an email of ip
4
+ class Sqreen
5
+ BASE_URL = 'https://api.sqreen.io/v1/%s/%s'.freeze
6
+
7
+ attr_accessor :sqreen_api_token
8
+
9
+ def initialize(token)
10
+ self.sqreen_api_token = token
11
+ end
12
+
13
+ # Sqreen an email address
14
+ # @param [String] email address to sqreen
15
+ # @return [String, nil] nil (on any error) or the metadata hash
16
+ def sqreen_email(email)
17
+ sqreen(:emails, email)
18
+ end
19
+
20
+ # Sqreen an ip address
21
+ # @param [String] ip address to sqreen
22
+ # @return [] nil (on any error) or the metadata hash
23
+ def sqreen_ip(ip)
24
+ sqreen(:ips, ip)
25
+ end
26
+
27
+ protected
28
+
29
+ def sqreen(kind, value)
30
+ uri = URI(format(BASE_URL, kind, value))
31
+ response = Net::HTTP.start(uri.hostname, uri.port,
32
+ :use_ssl => uri.scheme == 'https') do |http|
33
+ http.request_get(uri, 'x-api-key' => sqreen_api_token.to_s)
34
+ end
35
+
36
+ handle_response(kind, value, response)
37
+ end
38
+
39
+ def handle_response(kind, value, response)
40
+ case response
41
+ when Net::HTTPSuccess then
42
+ return JSON.load(response.body)
43
+ else
44
+ Rails.logger.debug do
45
+ "Cannot sqreen #{kind} #{value} #{response.inspect}"
46
+ end
47
+ nil
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,3 @@
1
+ module DeviseSqreener
2
+ VERSION="0.1.0"
3
+ end
@@ -0,0 +1,25 @@
1
+ require 'devise_sqreener/version'
2
+ require 'devise'
3
+
4
+ module Devise # :nodoc:
5
+ # Token that will be used to call Sqreen API
6
+ mattr_accessor :sqreen_api_token
7
+ @sqreen_api_token = nil
8
+
9
+ # callable that will be used to authorize sign ins
10
+ mattr_accessor :sqreen_block_sign_in
11
+ @sqreen_block_sign_in = nil
12
+
13
+ # callable that will be used to authorize sign ups
14
+ mattr_accessor :sqreen_block_sign_up
15
+ @sqreen_block_sign_up = nil
16
+
17
+ add_module :sqreenable, :model => 'devise_sqreener/model',
18
+ :insert_at => Devise::ALL.size
19
+ end
20
+
21
+ module DeviseSqreener
22
+ # Rails engine declaration (to pick up locales)
23
+ class Engine < ::Rails::Engine
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ require 'rails/generators/active_record'
2
+
3
+ module ActiveRecord
4
+ module Generators
5
+ class DeviseSqreenerGenerator < ActiveRecord::Generators::Base
6
+ source_root File.expand_path("../", __FILE__)
7
+
8
+ def copy_devise_migration
9
+ migration_template "migration.rb", "db/migrate/devise_sqreener_add_to_#{table_name}.rb"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ class DeviseSqreenerAddTo<%= table_name.camelize %> < ActiveRecord::Migration
2
+ def change
3
+ add_column :<%= table_name %>, :sqreened_email, :text
4
+ if <%= class_name %>.devise_modules.include?(:trackable)
5
+ add_column :<%= table_name %>, :current_sqreened_sign_in_ip, :text
6
+ add_column :<%= table_name %>, :last_sqreened_sign_in_ip, :text
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ module DeviseSqreener
2
+ module Generators
3
+ class DeviseSqreenerGenerator < Rails::Generators::NamedBase
4
+ namespace "devise_sqreener"
5
+
6
+ desc "Add :sqreenable directive in the given model. Also generate migration for ActiveRecord"
7
+
8
+ def inject_devise_sqreenable_content
9
+ path = File.join("app", "models", "#{file_path}.rb")
10
+ inject_into_file(path, "sqreenable, :", :after => "devise :") if File.exists?(path)
11
+ end
12
+
13
+ hook_for :orm
14
+ end
15
+ end
16
+ end
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: devise_sqreener
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Benoit Larroque
8
+ - D.E. Goodman-Wilson
9
+ - Sqreen
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2017-06-01 00:00:00.000000000 Z
14
+ dependencies: []
15
+ description: Sqreen emails/ips that are seen by Devise through the Sqreen API, and
16
+ block bad actors from signing up to your Rails app.
17
+ email: hey@sqreen.io
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - CODE_OF_CONDUCT.md
23
+ - LICENSE
24
+ - README.md
25
+ - Rakefile
26
+ - lib/devise_sqreener.rb
27
+ - lib/devise_sqreener/hook.rb
28
+ - lib/devise_sqreener/model.rb
29
+ - lib/devise_sqreener/sqreen.rb
30
+ - lib/devise_sqreener/version.rb
31
+ - lib/generators/active_record/devise_sqreener_generator.rb
32
+ - lib/generators/active_record/migration.rb
33
+ - lib/generators/devise_sqreener/devise_enricher_generator.rb
34
+ homepage: https://github.com/sqreen/devise_sqreener
35
+ licenses:
36
+ - MIT
37
+ metadata: {}
38
+ post_install_message:
39
+ rdoc_options: []
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ requirements: []
53
+ rubyforge_project:
54
+ rubygems_version: 2.5.2
55
+ signing_key:
56
+ specification_version: 4
57
+ summary: Sqreen - Devise integration
58
+ test_files: []