negroni 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 +7 -0
- data/LICENSE +20 -0
- data/README.md +59 -0
- data/Rakefile +64 -0
- data/app/mailers/negroni/mailer.rb +45 -0
- data/app/views/negroni/mailer/password_change.html.erb +5 -0
- data/app/views/negroni/mailer/reset_password_instructions.html.erb +8 -0
- data/app/views/negroni/mailer/unlock_instructions.html.erb +7 -0
- data/config/locales/en.yml +9 -0
- data/config/routes.rb +4 -0
- data/lib/negroni.rb +209 -0
- data/lib/negroni/configuration.rb +231 -0
- data/lib/negroni/controllers/helpers.rb +29 -0
- data/lib/negroni/controllers/token_authenticable.rb +20 -0
- data/lib/negroni/encryptor.rb +35 -0
- data/lib/negroni/engine.rb +35 -0
- data/lib/negroni/mailers/helpers.rb +112 -0
- data/lib/negroni/models.rb +138 -0
- data/lib/negroni/models/authenticable.rb +197 -0
- data/lib/negroni/models/base.rb +318 -0
- data/lib/negroni/models/lockable.rb +216 -0
- data/lib/negroni/models/omniauthable.rb +33 -0
- data/lib/negroni/models/recoverable.rb +204 -0
- data/lib/negroni/models/registerable.rb +14 -0
- data/lib/negroni/models/validatable.rb +63 -0
- data/lib/negroni/modules.rb +12 -0
- data/lib/negroni/omniauth.rb +25 -0
- data/lib/negroni/omniauth/config.rb +81 -0
- data/lib/negroni/orm/active_record.rb +7 -0
- data/lib/negroni/orm/mongoid.rb +6 -0
- data/lib/negroni/param_filter.rb +53 -0
- data/lib/negroni/resolver.rb +17 -0
- data/lib/negroni/token_generator.rb +58 -0
- data/lib/negroni/token_not_found.rb +13 -0
- data/lib/negroni/version.rb +6 -0
- data/lib/tasks/negroni_tasks.rake +5 -0
- 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,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
|
metadata
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: negroni
|
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-12 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: []
|