authenticatable 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.md +19 -0
  3. data/README.md +144 -0
  4. data/app/controllers/authenticatable/passwords_controller.rb +51 -0
  5. data/app/controllers/authenticatable/registrations_controller.rb +28 -0
  6. data/app/controllers/authenticatable/sessions_controller.rb +49 -0
  7. data/app/controllers/authenticatable_controller.rb +101 -0
  8. data/app/mailers/authenticatable/mailer.rb +17 -0
  9. data/app/views/authenticatable/mailer/reset_password.html.erb +8 -0
  10. data/app/views/authenticatable/passwords/_edit_form.html.erb +6 -0
  11. data/app/views/authenticatable/passwords/_new_form.html.erb +6 -0
  12. data/app/views/authenticatable/passwords/edit.html.erb +7 -0
  13. data/app/views/authenticatable/passwords/new.html.erb +7 -0
  14. data/app/views/authenticatable/registrations/_form.html.erb +12 -0
  15. data/app/views/authenticatable/registrations/new.html.erb +5 -0
  16. data/app/views/authenticatable/sessions/_form.html.erb +5 -0
  17. data/app/views/authenticatable/sessions/new.html.erb +7 -0
  18. data/app/views/authenticatable/shared/_errors.html.erb +7 -0
  19. data/app/views/authenticatable/shared/_flash_messages.html.erb +3 -0
  20. data/app/views/authenticatable/shared/_links.html.erb +12 -0
  21. data/config/locales/en.yml +14 -0
  22. data/lib/authenticatable/controllers/helpers.rb +72 -0
  23. data/lib/authenticatable/controllers/url_helpers.rb +67 -0
  24. data/lib/authenticatable/controllers.rb +9 -0
  25. data/lib/authenticatable/engine.rb +17 -0
  26. data/lib/authenticatable/errors/unauthenticated_error.rb +6 -0
  27. data/lib/authenticatable/errors.rb +6 -0
  28. data/lib/authenticatable/manager.rb +16 -0
  29. data/lib/authenticatable/models/email_validator.rb +17 -0
  30. data/lib/authenticatable/models/identifier.rb +43 -0
  31. data/lib/authenticatable/models/password.rb +73 -0
  32. data/lib/authenticatable/models.rb +67 -0
  33. data/lib/authenticatable/proxy.rb +103 -0
  34. data/lib/authenticatable/rails/routes.rb +61 -0
  35. data/lib/authenticatable/rspec.rb +8 -0
  36. data/lib/authenticatable/scope.rb +110 -0
  37. data/lib/authenticatable/serializers/base.rb +39 -0
  38. data/lib/authenticatable/serializers/session.rb +36 -0
  39. data/lib/authenticatable/serializers.rb +9 -0
  40. data/lib/authenticatable/testing/controller_helpers.rb +31 -0
  41. data/lib/authenticatable/token.rb +13 -0
  42. data/lib/authenticatable/version.rb +5 -0
  43. data/lib/authenticatable.rb +100 -0
  44. data/lib/generators/active_record/authenticatable_generator.rb +63 -0
  45. data/lib/generators/active_record/templates/migration.tt +15 -0
  46. data/lib/generators/active_record/templates/migration_existing.tt +23 -0
  47. data/lib/generators/authenticatable/authenticatable_generator.rb +18 -0
  48. data/lib/generators/authenticatable/orm_helpers.rb +30 -0
  49. data/lib/generators/authenticatable/views_generator.rb +19 -0
  50. metadata +136 -0
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "authenticatable/serializers/base"
4
+ require "authenticatable/serializers/session"
5
+
6
+ module Authenticatable
7
+ module Serializers
8
+ end
9
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Authenticatable
4
+ module Testing
5
+ module ControllerHelpers
6
+ def setup_controller_request_and_response
7
+ super
8
+ @request.env["authenticatable"] = Authenticatable::Proxy.new(@request.env)
9
+
10
+ # Set default testing scope to :users
11
+ @request.env["authenticatable.scope"] = Authenticatable.add_scope(:users, {})
12
+ end
13
+
14
+ def sign_in(resource, store = nil)
15
+ @request.env["authenticatable"].sign_in(resource, store)
16
+ end
17
+
18
+ # def sign_out(resource, store = nil)
19
+ # @request.env["authenticatable"].sign_out(resource, store)
20
+ # end
21
+
22
+ def authenticatable_scope(scope, options = {})
23
+ @request.env["authenticatable.scope"] = Authenticatable.add_scope(scope, options)
24
+ end
25
+
26
+ def authenticatable
27
+ @request.env["authenticatable"]
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Authenticatable
4
+ # Random token used for password reset and remember tokens.
5
+ class Token
6
+ # Generate a new random hex token.
7
+ class << self
8
+ def new(bytes = 20)
9
+ SecureRandom.hex(bytes)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Authenticatable
4
+ VERSION = "1.0.0"
5
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "authenticatable/controllers"
4
+ require "authenticatable/errors"
5
+ require "authenticatable/manager"
6
+ require "authenticatable/models"
7
+ require "authenticatable/rails/routes"
8
+ require "authenticatable/scope"
9
+ require "authenticatable/proxy"
10
+ require "authenticatable/serializers"
11
+ require "authenticatable/token"
12
+ require "authenticatable/version"
13
+ require "authenticatable/engine"
14
+
15
+ require "dry-configurable"
16
+
17
+ # Authenticatable is an authentication solution for Rails. All related modules,
18
+ # classes and methods will be namespaced under the namespace 'Authenticatable':
19
+ module Authenticatable
20
+ extend Dry::Configurable
21
+
22
+ # Store authenticatable resources as scopes.
23
+ @scopes = {}
24
+
25
+ # Default extensions to load into your authenticatable models. This can for example
26
+ # be a custom Warden strategy, concerns with validations, or basically anything that
27
+ # modifies the default behavior of your authenticatable model. Feel free to develop
28
+ # add publish your own extensions online. We'd be happy to see what you can accomplish.
29
+ #
30
+ # email_validator: Validates emails with the valid_email2 gem. You can remove this
31
+ # if you want to implement your own email validations or if you
32
+ # don't want to validate emails at all.
33
+ #
34
+ # password: Enables password authentication with has_secure_password. This extension
35
+ # includes a Warden Strategy for authentication with password. It does also
36
+ # add password validations to your authenticatable model.
37
+ #
38
+ setting :default_extensions, %i[password]
39
+
40
+ # Default column to use when looking up an authenticatable record in the database.
41
+ # Can be for example email or a username. Default is :email. This can also be changed
42
+ # for an individual resource/scope by passing :identifier to the authentication
43
+ # method in your model:
44
+ #
45
+ # authenticatable identifier: :username
46
+ #
47
+ setting :default_identifier, :email
48
+
49
+ # The controller class that all Authenticatable controllers will inherit from.
50
+ # Defaults to `ApplicationController`.
51
+ setting :parent_controller, "ApplicationController"
52
+
53
+ # The mailer class that all Authenticatable mailers will inherit from.
54
+ # Defaults to `ApplicationMailer`.
55
+ setting :parent_mailer, "ApplicationMailer"
56
+
57
+ # Range validation for password length
58
+ setting :password_length, 6..128
59
+
60
+ # Requests method(s) allowed for sign out. You can for example add :get
61
+ # to enable sign out by visiting /users/sign_out.
62
+ setting :allowed_sign_out_methods, %i[delete]
63
+
64
+ # Which formats should be treated as navigational. Navigational formats
65
+ # like :html & :turbo_stream should redirect and show flash messages,
66
+ # but other formats like :xml or :json, should return 401. The "*/*"
67
+ # format below is required to match Internet Explorer.
68
+ setting :navigational_formats, ["*/*", :html, :turbo_stream]
69
+
70
+ # Email regex used to validate email formats. It simply asserts that
71
+ # one (and only one) @ exists in the given string. This is mainly
72
+ # to give user feedback and not to assert the e-mail validity.
73
+ setting :email_regexp, /\A[^@\s]+@[^@\s]+\z/
74
+
75
+ # Specify for how long a reset_password_token will be valid.
76
+ # When the time expires, their token will be invalid and they
77
+ # have to request a "reset password link" to recover their account.
78
+ setting :reset_password_expiration_time, 1.hour
79
+
80
+ class << self
81
+ attr_reader :scopes
82
+
83
+ def reset_default_values!
84
+ remove_instance_variable :@config
85
+ end
86
+
87
+ # Add a authenticatable model to list of scopes. It could be for example
88
+ # :users, :admins, :subscribers or any other model that should be authenticatable.
89
+ def add_scope(resource, options = {})
90
+ scope = Authenticatable::Scope.new(resource, options)
91
+ @scopes[scope.singular_name.to_sym] = scope
92
+
93
+ # Define helpers like current_{scope}, authenticate_{scope}!
94
+ # {scope}_signed_in? etc for the given scope that can be accessed from all controllers.
95
+ Authenticatable::Controllers::Helpers.define_helpers(scope.singular_name)
96
+
97
+ scope
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/active_record"
4
+ require "generators/authenticatable/orm_helpers"
5
+
6
+ module ActiveRecord
7
+ module Generators
8
+ class AuthenticatableGenerator < ActiveRecord::Generators::Base
9
+ argument :attributes, type: :array, default: [], banner: "field:type field:type"
10
+
11
+ include Authenticatable::Generators::OrmHelpers
12
+ source_root File.expand_path("templates", __dir__)
13
+
14
+ def copy_authenticatable_migration
15
+ if (behavior == :invoke && model_exists?) || (behavior == :revoke && migration_exists?(table_name))
16
+ migration_template "migration_existing.tt", "#{db_migrate_path}/add_authenticatable_to_#{table_name}.rb",
17
+ migration_version: migration_version
18
+ else
19
+ migration_template "migration.tt", "#{db_migrate_path}/authenticatable_create_#{table_name}.rb",
20
+ migration_version: migration_version
21
+ end
22
+ end
23
+
24
+ def generate_model
25
+ invoke "active_record:model", [name], migration: false unless model_exists? && behavior == :invoke
26
+ end
27
+
28
+ # rubocop:disable Metrics/AbcSize
29
+ def inject_authenticatable
30
+ content = model_contents
31
+ class_path = (namespaced? ? class_name.to_s.split("::") : [class_name])
32
+ indent_depth = class_path.size - 1
33
+ content = content.split("\n").map { |line| (" " * indent_depth) + line }.join("\n") << "\n"
34
+
35
+ inject_into_class(model_path, class_path.last, content) if model_exists?
36
+ end
37
+ # rubocop:enable Metrics/AbcSize
38
+
39
+ def add_route
40
+ route_content = "authenticatable :#{plural_name}"
41
+ route route_content
42
+ end
43
+
44
+ private
45
+
46
+ def model_contents
47
+ " authenticatable\n"
48
+ end
49
+
50
+ # rubocop:disable Layout/IndentationWidth
51
+ def migration_data
52
+ <<RUBY
53
+ ## Authenticatable
54
+ t.string :email, null: false, default: ""
55
+ t.string :password_digest, null: false, default: ""
56
+ t.string :reset_password_token, null: false, default: ""
57
+ t.datetime :reset_password_sent_at
58
+ RUBY
59
+ end
60
+ # rubocop:enable Layout/IndentationWidth
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AuthenticatableCreate<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
4
+ def change
5
+ create_table :<%= table_name %><%= primary_key_type %> do |t|
6
+ <%= migration_data -%>
7
+ <% attributes.each do |attribute| -%>
8
+ t.<%= attribute.type %> :<%= attribute.name %>
9
+ <% end -%>
10
+ t.timestamps null: false
11
+ end
12
+ add_index :<%= table_name %>, :email, unique: true
13
+ add_index :<%= table_name %>, :reset_password_token
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddAuthenticatableTo<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
4
+ def self.up
5
+ change_table :<%= table_name %> do |t|
6
+ <%= migration_data -%>
7
+
8
+ <% attributes.each do |attribute| -%>
9
+ t.<%= attribute.type %> :<%= attribute.name %>
10
+ <% end -%>
11
+ # Uncomment below if timestamps were not included in your original model.
12
+ # t.timestamps null: false
13
+ end
14
+ add_index :<%= table_name %>, :email, unique: true
15
+ add_index :<%= table_name %>, :reset_password_token
16
+ end
17
+
18
+ def self.down
19
+ # By default, we don't want to make any assumption about how to roll back a migration when your
20
+ # model already existed. Please edit below which fields you would like to remove in this migration.
21
+ raise ActiveRecord::IrreversibleMigration
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/named_base"
4
+
5
+ module Authenticatable
6
+ module Generators
7
+ class AuthenticatableGenerator < Rails::Generators::NamedBase
8
+ include Rails::Generators::ResourceHelpers
9
+
10
+ namespace "authenticatable"
11
+
12
+ desc "Generates a model with the given NAME (if one does not exist) with authenticatable " \
13
+ "configuration plus a migration file and authentication routes."
14
+
15
+ hook_for :orm, required: true
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Authenticatable
4
+ module Generators
5
+ module OrmHelpers
6
+ private
7
+
8
+ def model_exists?
9
+ File.exist?(File.join(destination_root, model_path))
10
+ end
11
+
12
+ def migration_exists?(table_name)
13
+ Dir.glob("#{File.join(destination_root, db_migrate_path)}/[0-9]*_*.rb")
14
+ .grep(/\d+_add_authenticatable_to_#{table_name}.rb$/).first
15
+ end
16
+
17
+ def model_path
18
+ @model_path ||= File.join("app", "models", "#{file_path}.rb")
19
+ end
20
+
21
+ def migration_version
22
+ "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]" if rails5_and_up?
23
+ end
24
+
25
+ def rails5_and_up?
26
+ Rails::VERSION::MAJOR >= 5
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/base"
4
+ require "active_support/core_ext/string/inflections"
5
+
6
+ module Authenticatable
7
+ module Generators
8
+ class ViewsGenerator < Rails::Generators::Base
9
+ desc "Copy view files to app/views"
10
+ source_root Authenticatable::Engine.root
11
+ argument :scope, default: "authenticatable", type: :string
12
+
13
+ def copy_views
14
+ scope_directory = (scope == "authenticatable" ? "authenticatable" : ActiveSupport::Inflector.pluralize(scope))
15
+ directory "app/views/authenticatable", "app/views/#{scope_directory}"
16
+ end
17
+ end
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: authenticatable
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Rasmus Kjellberg
8
+ - KIQR
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2021-10-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bcrypt
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: 3.1.16
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: 3.1.16
28
+ - !ruby/object:Gem::Dependency
29
+ name: dry-configurable
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: 0.11.0
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: 0.11.0
42
+ - !ruby/object:Gem::Dependency
43
+ name: valid_email2
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: 4.0.0
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: 4.0.0
56
+ description:
57
+ email: hello@kiqr.dev
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - LICENSE.md
63
+ - README.md
64
+ - app/controllers/authenticatable/passwords_controller.rb
65
+ - app/controllers/authenticatable/registrations_controller.rb
66
+ - app/controllers/authenticatable/sessions_controller.rb
67
+ - app/controllers/authenticatable_controller.rb
68
+ - app/mailers/authenticatable/mailer.rb
69
+ - app/views/authenticatable/mailer/reset_password.html.erb
70
+ - app/views/authenticatable/passwords/_edit_form.html.erb
71
+ - app/views/authenticatable/passwords/_new_form.html.erb
72
+ - app/views/authenticatable/passwords/edit.html.erb
73
+ - app/views/authenticatable/passwords/new.html.erb
74
+ - app/views/authenticatable/registrations/_form.html.erb
75
+ - app/views/authenticatable/registrations/new.html.erb
76
+ - app/views/authenticatable/sessions/_form.html.erb
77
+ - app/views/authenticatable/sessions/new.html.erb
78
+ - app/views/authenticatable/shared/_errors.html.erb
79
+ - app/views/authenticatable/shared/_flash_messages.html.erb
80
+ - app/views/authenticatable/shared/_links.html.erb
81
+ - config/locales/en.yml
82
+ - lib/authenticatable.rb
83
+ - lib/authenticatable/controllers.rb
84
+ - lib/authenticatable/controllers/helpers.rb
85
+ - lib/authenticatable/controllers/url_helpers.rb
86
+ - lib/authenticatable/engine.rb
87
+ - lib/authenticatable/errors.rb
88
+ - lib/authenticatable/errors/unauthenticated_error.rb
89
+ - lib/authenticatable/manager.rb
90
+ - lib/authenticatable/models.rb
91
+ - lib/authenticatable/models/email_validator.rb
92
+ - lib/authenticatable/models/identifier.rb
93
+ - lib/authenticatable/models/password.rb
94
+ - lib/authenticatable/proxy.rb
95
+ - lib/authenticatable/rails/routes.rb
96
+ - lib/authenticatable/rspec.rb
97
+ - lib/authenticatable/scope.rb
98
+ - lib/authenticatable/serializers.rb
99
+ - lib/authenticatable/serializers/base.rb
100
+ - lib/authenticatable/serializers/session.rb
101
+ - lib/authenticatable/testing/controller_helpers.rb
102
+ - lib/authenticatable/token.rb
103
+ - lib/authenticatable/version.rb
104
+ - lib/generators/active_record/authenticatable_generator.rb
105
+ - lib/generators/active_record/templates/migration.tt
106
+ - lib/generators/active_record/templates/migration_existing.tt
107
+ - lib/generators/authenticatable/authenticatable_generator.rb
108
+ - lib/generators/authenticatable/orm_helpers.rb
109
+ - lib/generators/authenticatable/views_generator.rb
110
+ homepage: https://github.com/kiqr/authenticatable
111
+ licenses:
112
+ - MIT
113
+ metadata:
114
+ bug_tracker_uri: https://github.com/kiqr/authenticatable/issues
115
+ documentation_uri: https://github.com/kiqr/authenticatable/issues
116
+ source_code_uri: https://github.com/kiqr/authenticatable
117
+ post_install_message:
118
+ rdoc_options: []
119
+ require_paths:
120
+ - lib
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '2.6'
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ requirements: []
132
+ rubygems_version: 3.2.26
133
+ signing_key:
134
+ specification_version: 4
135
+ summary: Authentication solution for Ruby on Rails
136
+ test_files: []