groovestack-auth 0.1.4 → 0.1.6

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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile +8 -1
  4. data/Gemfile.lock +121 -21
  5. data/{lib/groovestack/auth/action_cable.rb → app/channels/groovestack/auth/action_cable/connection.rb} +2 -2
  6. data/app/controllers/concerns/groovestack/auth/graphql/controllers/auth_helpers.rb +69 -0
  7. data/app/controllers/concerns/groovestack/auth/graphql/controllers/authed_execute.rb +16 -0
  8. data/app/controllers/groovestack/auth/authenticated_api_controller.rb +10 -0
  9. data/app/controllers/groovestack/auth/omniauth_callbacks_controller.rb +138 -0
  10. data/app/controllers/groovestack/auth/passwordless/magic_links_controller.rb +58 -0
  11. data/app/controllers/groovestack/auth/passwordless/sessions_controller.rb +75 -0
  12. data/app/graphql/graphql/identity_extensions.rb +11 -0
  13. data/app/graphql/graphql/user_extensions.rb +14 -0
  14. data/app/models/concerns/groovestack/auth/authorized_fields_for_serialization.rb +21 -0
  15. data/app/models/concerns/groovestack/auth/identity.rb +39 -0
  16. data/app/models/concerns/groovestack/auth/user.rb +14 -0
  17. data/app/views/devise/mailer/magic_link.html.erb +9 -0
  18. data/config/initializers/core_config.rb +0 -6
  19. data/config/initializers/devise.rb +387 -302
  20. data/config/initializers/omniauth.rb +0 -19
  21. data/config/locales/devise.en.yml +71 -0
  22. data/db/migrate/20231103174050_add_devise_to_users_and_identities.rb +59 -0
  23. data/groovestack-auth.gemspec +7 -7
  24. data/lib/groovestack/auth/{railtie.rb → engine.rb} +13 -2
  25. data/lib/groovestack/auth/graphql/authorized_field.rb +19 -0
  26. data/lib/groovestack/auth/graphql/authorized_object.rb +11 -0
  27. data/lib/groovestack/auth/graphql/schema_visibility.rb +40 -0
  28. data/lib/groovestack/auth/graphql/visible_field.rb +21 -0
  29. data/lib/groovestack/auth/graphql/visible_object.rb +17 -0
  30. data/lib/groovestack/auth/passwordless/t_otp_tokenizer.rb +89 -0
  31. data/lib/groovestack/auth/provider.rb +7 -0
  32. data/lib/groovestack/auth/providers/apple.rb +5 -5
  33. data/lib/groovestack/auth/providers/facebook.rb +17 -0
  34. data/lib/groovestack/auth/providers/google.rb +1 -1
  35. data/lib/groovestack/auth/providers/omni_auth.rb +2 -2
  36. data/lib/groovestack/auth/routes.rb +26 -0
  37. data/lib/groovestack/auth/settings.rb +43 -0
  38. data/lib/groovestack/auth/version.rb +1 -1
  39. data/lib/groovestack/auth.rb +33 -83
  40. metadata +53 -49
  41. data/config/initializers/devise_token_auth.rb +0 -72
  42. data/config/initializers/graphql_devise.rb +0 -58
  43. data/config/routes.rb +0 -11
  44. data/db/migrate/20231103172517_create_users.rb +0 -54
  45. data/db/migrate/20231103174037_create_identities.rb +0 -19
  46. data/lib/fabricators/user_fabricator.rb +0 -17
  47. data/lib/graphql/identity/filter.rb +0 -13
  48. data/lib/graphql/identity/mutations.rb +0 -27
  49. data/lib/graphql/identity/queries.rb +0 -25
  50. data/lib/graphql/identity/type.rb +0 -22
  51. data/lib/graphql/user/filter.rb +0 -15
  52. data/lib/graphql/user/mutations.rb +0 -63
  53. data/lib/graphql/user/queries.rb +0 -40
  54. data/lib/graphql/user/type.rb +0 -30
  55. data/lib/groovestack/auth/authenticated_api_controller.rb +0 -13
  56. data/lib/groovestack/auth/omniauth_callbacks_controller.rb +0 -111
  57. data/lib/groovestack/auth/schema_plugin.rb +0 -19
  58. data/lib/identity.rb +0 -31
  59. data/lib/user.rb +0 -53
  60. data/lib/users/roles.rb +0 -42
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Groovestack
4
+ module Auth
5
+ module Passwordless
6
+ class SessionsController < ::Devise::SessionsController
7
+ skip_before_action :verify_authenticity_token # , only: :destroy
8
+
9
+ def create
10
+ self.resource = resource_class.find_for_authentication(email: create_params[:email])
11
+
12
+ if resource.blank?
13
+ # register a new account
14
+
15
+ u = ::User.new(email: create_params[:email], password: ::Devise.friendly_token[0, 20])
16
+ # u.skip_confirmation_notification!
17
+ u.save!
18
+
19
+ self.resource = u
20
+ end
21
+
22
+ send_magic_link(resource)
23
+
24
+ respond_to do |format|
25
+ format.html { redirect_to(after_magic_link_sent_path_for(resource), status: devise_redirect_status) }
26
+ format.json do
27
+ render json: { success: true, resource: resource.as_json, message: 'Magic link sent.' }, status: :ok
28
+ end
29
+ end
30
+ rescue StandardError => e
31
+ msg = "Passwordless Magic Link Send Failure for #{create_params[:email]}: #{e}"
32
+ ::Groovestack::Base.notify_error('Groovestack::Auth::Passwordless::SessionsController', msg)
33
+
34
+ respond_to do |format|
35
+ format.html { render :new, status: devise_error_status }
36
+ format.json do
37
+ render json: { error: 'User not found or unable to register account. Our team has been notified.' },
38
+ status: :not_found
39
+ end
40
+ end
41
+ end
42
+
43
+ protected
44
+
45
+ def send_magic_link(resource)
46
+ resource.send_magic_link(remember_me: create_params[:remember_me])
47
+ end
48
+
49
+ def translation_scope
50
+ if action_name == 'create'
51
+ 'devise.passwordless'
52
+ else
53
+ super
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def create_params
60
+ resource_params.permit(:email, :remember_me)
61
+ end
62
+
63
+ # Devise < 4.9 fallback support
64
+ # See: https://github.com/heartcombo/devise/wiki/How-To:-Upgrade-to-Devise-4.9.0-%5BHotwire-Turbo-integration%5D
65
+ def devise_redirect_status
66
+ ::Devise.try(:responder).try(:redirect_status) || :found
67
+ end
68
+
69
+ def devise_error_status
70
+ ::Devise.try(:responder).try(:error_status) || :ok
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module IdentityExtensions
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ field :omniauth_data, ::GraphQL::Types::JSON, null: true, description: 'omniauth data'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module UserExtensions
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ # devise fields
9
+ field :last_login_at, ::GraphQL::Types::ISO8601DateTime, null: true, description: 'last login in at',
10
+ method: :last_sign_in_at
11
+ field :sign_in_count, Integer, null: true, description: 'sign in count'
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Groovestack
4
+ module Auth
5
+ module AuthorizedFieldsForSerialization
6
+ extend ActiveSupport::Concern
7
+
8
+ # required for memoization during graphql serialization
9
+ def authorized_fields_for_serialization(user)
10
+ @authorized_fields_for_serialization ||= begin
11
+ Pundit.policy!(user, self).permitted_attributes_for_show
12
+ rescue StandardError => e
13
+ # NOTE: this is a fallback for when Pundit is not available
14
+ ::Groovestack::Base.notify_error(e)
15
+
16
+ []
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Groovestack
4
+ module Auth
5
+ module Identity
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ end
10
+
11
+ class_methods do
12
+ def find_or_create_from_omniauth!(auth:, current_user: nil, user_attrs: {}) # rubocop:disable Metrics/AbcSize
13
+ where(provider: auth.provider, uid: auth.uid).first_or_create! do |identity|
14
+ # TODO
15
+ # possible cases
16
+ # 1. user exists in the system (i.e. we found an email for them)
17
+ # 2. user does not exist in the system (i.e. oauth email doesn't match anything in the system
18
+
19
+ user = current_user || ::User.find_by(email: auth.info.email)
20
+ user_attrs_to_assign = user_attrs[:priority] || {}
21
+
22
+ if user.nil?
23
+ user_attrs_to_assign = user_attrs_to_assign.merge(user_attrs[:defaults] || {})
24
+ user = User.new
25
+ end
26
+
27
+ attrs = auth['info'].to_hash.slice(*user.attribute_names)
28
+ user.assign_attributes(attrs.merge(user_attrs_to_assign))
29
+
30
+ user.save!
31
+
32
+ identity.omniauth_data = auth
33
+ identity.user = user
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Groovestack
4
+ module Auth
5
+ module User
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ # Include default devise modules.
10
+ devise(*Groovestack::Auth.devise_modules)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ <p>Hello <%= @resource.email %>!</p>
2
+
3
+ <p>You can login using the code below:</p>
4
+
5
+ <center>
6
+ <p style="font-size: 40px; font-weight: bold;"><%= @token %></p>
7
+ </center>
8
+
9
+ <p>Note that the code will expire in <%= Devise.passwordless_login_within.inspect %>.</p>
@@ -2,9 +2,6 @@
2
2
 
3
3
  ActiveSupport.on_load(:after_initialize) do # rubocop:disable Metrics/BlockLength
4
4
  if defined?(Groovestack::Config)
5
- Groovestack::Config::App.dynamic_config << { key: :has_admins, build: proc { User.admins.count.positive? } }
6
- Groovestack::Config::App.dynamic_config << { key: :user_roles, build: proc { User::ROLES } }
7
-
8
5
  Groovestack::Config::App.dynamic_config << {
9
6
  key: :oauth_providers,
10
7
  build: proc do
@@ -34,8 +31,5 @@ ActiveSupport.on_load(:after_initialize) do # rubocop:disable Metrics/BlockLengt
34
31
  }
35
32
  end
36
33
  }
37
-
38
- # make AppConfig query public
39
- ::Types::QueryType.fields['AppConfig'].instance_variable_set(:@authenticate, false) if defined?(::Types::QueryType)
40
34
  end
41
35
  end