negroni-lite 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/README.md +63 -0
  4. data/Rakefile +64 -0
  5. data/app/mailers/negroni/mailer.rb +45 -0
  6. data/app/views/negroni/mailer/password_change.html.erb +5 -0
  7. data/app/views/negroni/mailer/reset_password_instructions.html.erb +8 -0
  8. data/app/views/negroni/mailer/unlock_instructions.html.erb +7 -0
  9. data/config/locales/en.yml +9 -0
  10. data/config/routes.rb +4 -0
  11. data/lib/negroni.rb +209 -0
  12. data/lib/negroni/configuration.rb +231 -0
  13. data/lib/negroni/controllers/helpers.rb +29 -0
  14. data/lib/negroni/controllers/token_authenticable.rb +20 -0
  15. data/lib/negroni/encryptor.rb +35 -0
  16. data/lib/negroni/engine.rb +35 -0
  17. data/lib/negroni/mailers/helpers.rb +112 -0
  18. data/lib/negroni/models.rb +138 -0
  19. data/lib/negroni/models/authenticable.rb +197 -0
  20. data/lib/negroni/models/base.rb +318 -0
  21. data/lib/negroni/models/lockable.rb +216 -0
  22. data/lib/negroni/models/omniauthable.rb +33 -0
  23. data/lib/negroni/models/recoverable.rb +204 -0
  24. data/lib/negroni/models/registerable.rb +14 -0
  25. data/lib/negroni/models/validatable.rb +63 -0
  26. data/lib/negroni/modules.rb +12 -0
  27. data/lib/negroni/omniauth.rb +25 -0
  28. data/lib/negroni/omniauth/config.rb +81 -0
  29. data/lib/negroni/orm/active_record.rb +7 -0
  30. data/lib/negroni/orm/mongoid.rb +6 -0
  31. data/lib/negroni/param_filter.rb +53 -0
  32. data/lib/negroni/resolver.rb +17 -0
  33. data/lib/negroni/token_generator.rb +58 -0
  34. data/lib/negroni/token_not_found.rb +13 -0
  35. data/lib/negroni/version.rb +6 -0
  36. data/lib/tasks/negroni_tasks.rake +5 -0
  37. metadata +169 -0
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Negroni
4
+ module Models
5
+ # Registerable is responsible for everything related to registering a new
6
+ # resource (ie user sign up).
7
+ module Registerable
8
+ # Required fields for this module (_none_)
9
+ def self.required_fields(_klass = nil)
10
+ []
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Negroni
4
+ module Models
5
+ # Validatable creates all needed validations for a user email and password.
6
+ # It's optional, given you may want to create the validations by yourself.
7
+ # Automatically validate if the email is present, unique and its format is
8
+ # valid. Also tests presence of password, confirmation and length.
9
+ #
10
+ # ## Options
11
+ #
12
+ # Validatable adds the following options to devise_for:
13
+ #
14
+ # * `email_regexp`: the regular expression used to validate e-mails
15
+ # * `password_length`: a range expressing password length. Default: 8..72
16
+ #
17
+ module Validatable
18
+ extend ActiveSupport::Concern
19
+
20
+ # Required fields for :validatable
21
+ def self.required_fields(_klass = nil)
22
+ []
23
+ end
24
+
25
+ included do
26
+ raise RuntimeError unless respond_to?(:validates)
27
+
28
+ validates :email, presence: true, if: :email_required?
29
+
30
+ with_options allow_blank: true, if: :email_changed? do |val|
31
+ val.validates :email, uniqueness: true
32
+ val.validates :email, format: { with: email_regexp }
33
+ end
34
+
35
+ validates :password, presence: true, if: :password_required?
36
+
37
+ validates :password, confirmation: true, if: :password_required?
38
+
39
+ validates :password, length: { in: password_length }, allow_blank: true
40
+
41
+ validates :password_confirmation, presence: true,
42
+ on: [:create, :update],
43
+ if: :password_required?
44
+ end
45
+
46
+ protected
47
+
48
+ def password_required?
49
+ !persisted? || !password.nil? || !password_confirmation.nil?
50
+ end
51
+
52
+ # Override this method if an email is not required for your model
53
+ def email_required?
54
+ true
55
+ end
56
+
57
+ # Class methods for Validations
58
+ module ClassMethods
59
+ Negroni::Models.config(self, :email_regexp, :password_length)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/object/with_options'
4
+
5
+ Negroni.with_options model: true do |negroni|
6
+ negroni.register_module :authenticable
7
+ negroni.register_module :registerable
8
+ negroni.register_module :lockable
9
+ negroni.register_module :omniauthable
10
+ negroni.register_module :recoverable
11
+ negroni.register_module :validatable
12
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'omniauth'
5
+ require 'omniauth/version'
6
+ rescue LoadError
7
+ warn 'Could not load `omniauth`. ' \
8
+ 'Please ensure you have the omniauth gem in your gemfile (>= 1.0.0).'
9
+ raise
10
+ end
11
+
12
+ unless OmniAuth::VERSION =~ /^1\./
13
+ raise 'You are using an old OmniAuth version, please make sure it is >= 1.0.0'
14
+ end
15
+
16
+ OmniAuth.config.path_prefix = nil
17
+ OmniAuth.config.logger = Rails.logger
18
+
19
+ module Negroni
20
+ # The `OmniAuth` module encloses configuration and providers for OmniAuth
21
+ # integration.
22
+ module OmniAuth
23
+ autoload :Config, 'negroni/omniauth/config'
24
+ end
25
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Negroni
4
+ module OmniAuth
5
+ # Raised if a strategy is unknown or not found.
6
+ class UnknownStrategy < NameError
7
+ # Raise a new error for `strategy`.
8
+ def initialize(strategy)
9
+ @strategy = strategy
10
+ super("Could not find a strategy named `#{strategy}`. " \
11
+ "Please ensure it is `require`d or explicitly set using " \
12
+ "the :strategy_class option.")
13
+ end
14
+ end
15
+
16
+ # Config encapsulates OmniAuth configuration for Negroni
17
+ class Config
18
+ # @!attribute [rw] strategy
19
+ # @return [Symbol] the strategy for OmniAuth
20
+ attr_accessor :strategy
21
+
22
+ # @!attribute [r] args
23
+ # @return [Array<Object>] arguments needed to configure the provider
24
+ attr_reader :args
25
+
26
+ # @!attribute [r] options
27
+ # @return [Hash] options needed to configure the provider
28
+ attr_reader :options
29
+
30
+ # @!attribute [r] provider
31
+ # @return [Symbol] the name of the OmniAuth provider
32
+ attr_reader :provider
33
+
34
+ # @!attribute [r] strategy_name
35
+ # @return [String, Symbol] the name of the strategy, if different from
36
+ # `provider`
37
+ attr_reader :strategy_name
38
+
39
+ # Create a new OmniAuth::Config
40
+ #
41
+ # @param provider [Symbol] the name of the provider to use
42
+ # @param args [Array<Object>] any arguments to pass to the provider
43
+ #
44
+ def initialize(provider, args)
45
+ @provider = provider
46
+ @args = args
47
+ @options = @args.last.is_a?(Hash) ? @args.last : {}
48
+ @strategy = nil
49
+ @strategy_name = options[:name] || @provider
50
+ @strategy_class = options.delete(:strategy_class)
51
+ end
52
+
53
+ # @!attribute [r] strategy_class
54
+ # @return [Class] the class for the OmniAuth strategy
55
+
56
+ # @return [Class] the class for the OmniAuth strategy
57
+ def strategy_class
58
+ @strategy_class ||= find_strategy || autoload_strategy
59
+ end
60
+
61
+ # Find a the strategy, using the name provided
62
+ def find_strategy
63
+ ::OmniAuth.strategies.find do |klass|
64
+ klass.to_s =~ /#{::OmniAuth::Utils.camelize(strategy_name)}$/ ||
65
+ klass.default_options[:name] == strategy_name
66
+ end
67
+ end
68
+
69
+ # Autoload a strategy
70
+ def autoload_strategy
71
+ name = ::OmniAuth::Utils.camelize(provider.to_s)
72
+
73
+ if ::OmniAuth::Strategies.const_defined?(name)
74
+ return ::OmniAuth::Strategies.const_get(name)
75
+ end
76
+
77
+ raise UnknownStrategy, name
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'orm_adapter/adapters/active_record'
4
+
5
+ ActiveSupport.on_load(:active_record) do
6
+ extend Negroni::Models
7
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ ActiveSupport.on_load(:mongoid) do
4
+ require 'orm_adapter/adapters/mongoid'
5
+ Mongoid::Document::ClassMethods.send :include, Negroni::Models
6
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Negroni
4
+ # ParamFilter is responsible for filtering blacklisted parameters from a
5
+ # request for validation and authentication.
6
+ class ParamFilter
7
+ # Creates a new instance of `ParamFilter`.
8
+ #
9
+ # @param case_insensitive_keys [Array<Symbol>] keys which are not case
10
+ # sensitive
11
+ # @param strip_whitespace_keys [Array<Symbol>] keys which should have
12
+ # whitespace stripped
13
+ #
14
+ def initialize(case_insensitive_keys, strip_whitespace_keys)
15
+ @case_insensitive_keys = case_insensitive_keys || []
16
+ @strip_whitespace_keys = strip_whitespace_keys || []
17
+ end
18
+
19
+ # Filter the `conditions` based on \@case_insensitive_keys and
20
+ # \@strip_whitespace_keys.
21
+ #
22
+ # @param conditions [Hash] the conditions hash to filter
23
+ #
24
+ # @return [Hash] the filtered `conditions` hash
25
+ def filter(conditions)
26
+ conditions = stringify_params(conditions.dup.to_h)
27
+
28
+ conditions.merge! filtered_hash_by_meth_for_keys(conditions.dup,
29
+ :downcase,
30
+ @case_insensitive_keys)
31
+
32
+ conditions.merge! filtered_hash_by_meth_for_keys(conditions.dup,
33
+ :strip,
34
+ @strip_whitespace_keys)
35
+ end
36
+
37
+ private
38
+
39
+ def filtered_hash_by_meth_for_keys(conditions, method, condition_keys)
40
+ condition_keys.each do |key|
41
+ value = conditions[key]
42
+ conditions[key] = value.send(method) if value.respond_to?(method)
43
+ end
44
+
45
+ conditions
46
+ end
47
+
48
+ def stringify_params(conditions)
49
+ return conditions unless conditions.is_a? Hash
50
+ conditions.each { |k, v| conditions[k] = v.to_s }
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Negroni
4
+ # @api private
5
+ # Resolver is responsible for getting and `constantizing` a string.
6
+ class Resolver
7
+ # Create a Resolver
8
+ def initialize(reference)
9
+ @reference = reference
10
+ end
11
+
12
+ # Resolve a string to a constant
13
+ def resolve
14
+ ActiveSupport::Dependencies.constantize(@reference)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openssl'
4
+
5
+ module Negroni
6
+ # Generates a secure token.
7
+ class TokenGenerator
8
+ # Creates a new token generator.
9
+ #
10
+ # @param key_generator [ActiveSupport::CachingKeyGenerator] the generator
11
+ # @param digest [String, Symbol] The digest to use. Must be a stringified
12
+ # version of an OpenSSL::Digest subclass. Default: `SHA256`.
13
+ def initialize(key_generator = nil, digest = 'SHA256', secret_key: nil)
14
+ @key_generator = if secret_key
15
+ ActiveSupport::CachingKeyGenerator.new(
16
+ ActiveSupport::KeyGenerator.new(secret_key)
17
+ )
18
+ elsif key_generator
19
+ key_generator
20
+ else
21
+ raise ArgumentError, 'Unexpected arguments!'
22
+ end
23
+ @digest = digest
24
+ end
25
+
26
+ # Digest a key.
27
+ #
28
+ # @param _klass [Class] the class for which to digest the value.
29
+ # @param column [String] the column name to digest.
30
+ # @param value [#to_s] the value to digest.
31
+ #
32
+ # @return [String] the digested value.
33
+ def digest(_klass, column, value)
34
+ return unless value.present?
35
+ OpenSSL::HMAC.hexdigest(@digest, key_for(column), value.to_s)
36
+ end
37
+
38
+ # Generate a key.
39
+ #
40
+ # @param klass [Class] the class for which to generate the key.
41
+ # @param column [String] the column name to generate a key for.
42
+ def generate(klass, column)
43
+ key = key_for(column)
44
+
45
+ loop do
46
+ raw = Negroni.friendly_token
47
+ enc = OpenSSL::HMAC.hexdigest(@digest, key, raw)
48
+ break [raw, enc] unless klass.to_adapter.find_first(column => enc)
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def key_for(column)
55
+ @key_generator.generate_key "Negroni #{column}"
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Negroni
4
+ # Raised when a token is bad
5
+ class TokenNotFound < StandardError
6
+ # Override for better `raise` calls
7
+ #
8
+ # @param object [Object] whatever you want
9
+ def self.exception(object)
10
+ super "The record #{object} could not be found."
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Negroni
4
+ # Version number
5
+ VERSION = '0.1.0'
6
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+ # desc "Explaining what the task does"
3
+ # task :api_auth do
4
+ # # Task goes here
5
+ # end
metadata ADDED
@@ -0,0 +1,169 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: negroni-lite
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - J. Morgan Lieberthal
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-12-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.0.0
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 5.0.0.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: 5.0.0
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 5.0.0.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: knock
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: orm_adapter
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.5'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.5'
61
+ - !ruby/object:Gem::Dependency
62
+ name: bcrypt
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '3.0'
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '3.0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: sqlite3
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rspec-rails
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: 3.5.0
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 3.5.0
103
+ description: Very light user management plugin for rails api apps
104
+ email:
105
+ - j.morgan.lieberthal@gmail.com
106
+ executables: []
107
+ extensions: []
108
+ extra_rdoc_files: []
109
+ files:
110
+ - LICENSE
111
+ - README.md
112
+ - Rakefile
113
+ - app/mailers/negroni/mailer.rb
114
+ - app/views/negroni/mailer/password_change.html.erb
115
+ - app/views/negroni/mailer/reset_password_instructions.html.erb
116
+ - app/views/negroni/mailer/unlock_instructions.html.erb
117
+ - config/locales/en.yml
118
+ - config/routes.rb
119
+ - lib/negroni.rb
120
+ - lib/negroni/configuration.rb
121
+ - lib/negroni/controllers/helpers.rb
122
+ - lib/negroni/controllers/token_authenticable.rb
123
+ - lib/negroni/encryptor.rb
124
+ - lib/negroni/engine.rb
125
+ - lib/negroni/mailers/helpers.rb
126
+ - lib/negroni/models.rb
127
+ - lib/negroni/models/authenticable.rb
128
+ - lib/negroni/models/base.rb
129
+ - lib/negroni/models/lockable.rb
130
+ - lib/negroni/models/omniauthable.rb
131
+ - lib/negroni/models/recoverable.rb
132
+ - lib/negroni/models/registerable.rb
133
+ - lib/negroni/models/validatable.rb
134
+ - lib/negroni/modules.rb
135
+ - lib/negroni/omniauth.rb
136
+ - lib/negroni/omniauth/config.rb
137
+ - lib/negroni/orm/active_record.rb
138
+ - lib/negroni/orm/mongoid.rb
139
+ - lib/negroni/param_filter.rb
140
+ - lib/negroni/resolver.rb
141
+ - lib/negroni/token_generator.rb
142
+ - lib/negroni/token_not_found.rb
143
+ - lib/negroni/version.rb
144
+ - lib/tasks/negroni_tasks.rake
145
+ homepage: https://github.com/baberthal/negroni
146
+ licenses:
147
+ - MIT
148
+ metadata: {}
149
+ post_install_message:
150
+ rdoc_options: []
151
+ require_paths:
152
+ - lib
153
+ required_ruby_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: 2.2.2
158
+ required_rubygems_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ requirements: []
164
+ rubyforge_project:
165
+ rubygems_version: 2.5.2
166
+ signing_key:
167
+ specification_version: 4
168
+ summary: Very light user management plugin for rails api apps
169
+ test_files: []