devise_token_auth_multi_email 0.9.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.
Files changed (183) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +13 -0
  3. data/README.md +97 -0
  4. data/Rakefile +42 -0
  5. data/app/controllers/devise_token_auth/application_controller.rb +100 -0
  6. data/app/controllers/devise_token_auth/concerns/resource_finder.rb +68 -0
  7. data/app/controllers/devise_token_auth/concerns/set_user_by_token.rb +199 -0
  8. data/app/controllers/devise_token_auth/confirmations_controller.rb +89 -0
  9. data/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb +284 -0
  10. data/app/controllers/devise_token_auth/passwords_controller.rb +216 -0
  11. data/app/controllers/devise_token_auth/registrations_controller.rb +205 -0
  12. data/app/controllers/devise_token_auth/sessions_controller.rb +153 -0
  13. data/app/controllers/devise_token_auth/token_validations_controller.rb +31 -0
  14. data/app/controllers/devise_token_auth/unlocks_controller.rb +94 -0
  15. data/app/models/devise_token_auth/concerns/active_record_support.rb +18 -0
  16. data/app/models/devise_token_auth/concerns/confirmable_support.rb +28 -0
  17. data/app/models/devise_token_auth/concerns/mongoid_support.rb +19 -0
  18. data/app/models/devise_token_auth/concerns/tokens_serialization.rb +31 -0
  19. data/app/models/devise_token_auth/concerns/user.rb +282 -0
  20. data/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb +39 -0
  21. data/app/validators/devise_token_auth_email_validator.rb +31 -0
  22. data/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
  23. data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
  24. data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
  25. data/app/views/devise_token_auth/omniauth_external_window.html.erb +38 -0
  26. data/config/locales/da-DK.yml +52 -0
  27. data/config/locales/de.yml +51 -0
  28. data/config/locales/en.yml +60 -0
  29. data/config/locales/es.yml +51 -0
  30. data/config/locales/fa.yml +60 -0
  31. data/config/locales/fr.yml +51 -0
  32. data/config/locales/he.yml +52 -0
  33. data/config/locales/it.yml +48 -0
  34. data/config/locales/ja.yml +60 -0
  35. data/config/locales/ko.yml +51 -0
  36. data/config/locales/nl.yml +32 -0
  37. data/config/locales/pl.yml +51 -0
  38. data/config/locales/pt-BR.yml +48 -0
  39. data/config/locales/pt.yml +51 -0
  40. data/config/locales/ro.yml +48 -0
  41. data/config/locales/ru.yml +52 -0
  42. data/config/locales/sq.yml +48 -0
  43. data/config/locales/sv.yml +52 -0
  44. data/config/locales/uk.yml +61 -0
  45. data/config/locales/vi.yml +52 -0
  46. data/config/locales/zh-CN.yml +48 -0
  47. data/config/locales/zh-HK.yml +50 -0
  48. data/config/locales/zh-TW.yml +50 -0
  49. data/lib/devise_token_auth/blacklist.rb +6 -0
  50. data/lib/devise_token_auth/controllers/helpers.rb +157 -0
  51. data/lib/devise_token_auth/controllers/url_helpers.rb +10 -0
  52. data/lib/devise_token_auth/engine.rb +105 -0
  53. data/lib/devise_token_auth/errors.rb +8 -0
  54. data/lib/devise_token_auth/rails/routes.rb +122 -0
  55. data/lib/devise_token_auth/token_factory.rb +126 -0
  56. data/lib/devise_token_auth/url.rb +44 -0
  57. data/lib/devise_token_auth/version.rb +5 -0
  58. data/lib/devise_token_auth.rb +14 -0
  59. data/lib/generators/devise_token_auth/USAGE +31 -0
  60. data/lib/generators/devise_token_auth/install_generator.rb +91 -0
  61. data/lib/generators/devise_token_auth/install_generator_helpers.rb +98 -0
  62. data/lib/generators/devise_token_auth/install_mongoid_generator.rb +46 -0
  63. data/lib/generators/devise_token_auth/install_views_generator.rb +18 -0
  64. data/lib/generators/devise_token_auth/templates/devise_token_auth.rb +66 -0
  65. data/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb +49 -0
  66. data/lib/generators/devise_token_auth/templates/user.rb.erb +9 -0
  67. data/lib/generators/devise_token_auth/templates/user_mongoid.rb.erb +56 -0
  68. data/lib/tasks/devise_token_auth_tasks.rake +6 -0
  69. data/test/controllers/custom/custom_confirmations_controller_test.rb +25 -0
  70. data/test/controllers/custom/custom_omniauth_callbacks_controller_test.rb +33 -0
  71. data/test/controllers/custom/custom_passwords_controller_test.rb +79 -0
  72. data/test/controllers/custom/custom_registrations_controller_test.rb +63 -0
  73. data/test/controllers/custom/custom_sessions_controller_test.rb +39 -0
  74. data/test/controllers/custom/custom_token_validations_controller_test.rb +42 -0
  75. data/test/controllers/demo_group_controller_test.rb +151 -0
  76. data/test/controllers/demo_mang_controller_test.rb +313 -0
  77. data/test/controllers/demo_user_controller_test.rb +658 -0
  78. data/test/controllers/devise_token_auth/confirmations_controller_test.rb +275 -0
  79. data/test/controllers/devise_token_auth/omniauth_callbacks_controller_test.rb +438 -0
  80. data/test/controllers/devise_token_auth/passwords_controller_test.rb +893 -0
  81. data/test/controllers/devise_token_auth/registrations_controller_test.rb +920 -0
  82. data/test/controllers/devise_token_auth/sessions_controller_test.rb +605 -0
  83. data/test/controllers/devise_token_auth/token_validations_controller_test.rb +142 -0
  84. data/test/controllers/devise_token_auth/unlocks_controller_test.rb +235 -0
  85. data/test/controllers/overrides/confirmations_controller_test.rb +47 -0
  86. data/test/controllers/overrides/omniauth_callbacks_controller_test.rb +53 -0
  87. data/test/controllers/overrides/passwords_controller_test.rb +64 -0
  88. data/test/controllers/overrides/registrations_controller_test.rb +46 -0
  89. data/test/controllers/overrides/sessions_controller_test.rb +35 -0
  90. data/test/controllers/overrides/token_validations_controller_test.rb +43 -0
  91. data/test/dummy/README.rdoc +28 -0
  92. data/test/dummy/app/active_record/confirmable_user.rb +11 -0
  93. data/test/dummy/app/active_record/lockable_user.rb +7 -0
  94. data/test/dummy/app/active_record/mang.rb +5 -0
  95. data/test/dummy/app/active_record/only_email_user.rb +7 -0
  96. data/test/dummy/app/active_record/scoped_user.rb +9 -0
  97. data/test/dummy/app/active_record/unconfirmable_user.rb +9 -0
  98. data/test/dummy/app/active_record/unregisterable_user.rb +9 -0
  99. data/test/dummy/app/active_record/user.rb +6 -0
  100. data/test/dummy/app/controllers/application_controller.rb +14 -0
  101. data/test/dummy/app/controllers/auth_origin_controller.rb +7 -0
  102. data/test/dummy/app/controllers/custom/confirmations_controller.rb +13 -0
  103. data/test/dummy/app/controllers/custom/omniauth_callbacks_controller.rb +13 -0
  104. data/test/dummy/app/controllers/custom/passwords_controller.rb +39 -0
  105. data/test/dummy/app/controllers/custom/registrations_controller.rb +39 -0
  106. data/test/dummy/app/controllers/custom/sessions_controller.rb +29 -0
  107. data/test/dummy/app/controllers/custom/token_validations_controller.rb +19 -0
  108. data/test/dummy/app/controllers/demo_group_controller.rb +15 -0
  109. data/test/dummy/app/controllers/demo_mang_controller.rb +14 -0
  110. data/test/dummy/app/controllers/demo_user_controller.rb +27 -0
  111. data/test/dummy/app/controllers/overrides/confirmations_controller.rb +29 -0
  112. data/test/dummy/app/controllers/overrides/omniauth_callbacks_controller.rb +16 -0
  113. data/test/dummy/app/controllers/overrides/passwords_controller.rb +36 -0
  114. data/test/dummy/app/controllers/overrides/registrations_controller.rb +29 -0
  115. data/test/dummy/app/controllers/overrides/sessions_controller.rb +36 -0
  116. data/test/dummy/app/controllers/overrides/token_validations_controller.rb +23 -0
  117. data/test/dummy/app/helpers/application_helper.rb +1058 -0
  118. data/test/dummy/app/models/concerns/favorite_color.rb +19 -0
  119. data/test/dummy/app/mongoid/confirmable_user.rb +52 -0
  120. data/test/dummy/app/mongoid/lockable_user.rb +38 -0
  121. data/test/dummy/app/mongoid/mang.rb +46 -0
  122. data/test/dummy/app/mongoid/only_email_user.rb +33 -0
  123. data/test/dummy/app/mongoid/scoped_user.rb +50 -0
  124. data/test/dummy/app/mongoid/unconfirmable_user.rb +44 -0
  125. data/test/dummy/app/mongoid/unregisterable_user.rb +47 -0
  126. data/test/dummy/app/mongoid/user.rb +49 -0
  127. data/test/dummy/app/views/layouts/application.html.erb +12 -0
  128. data/test/dummy/config/application.rb +50 -0
  129. data/test/dummy/config/application.yml.bk +0 -0
  130. data/test/dummy/config/boot.rb +11 -0
  131. data/test/dummy/config/environment.rb +7 -0
  132. data/test/dummy/config/environments/development.rb +36 -0
  133. data/test/dummy/config/environments/production.rb +68 -0
  134. data/test/dummy/config/environments/test.rb +58 -0
  135. data/test/dummy/config/initializers/backtrace_silencers.rb +9 -0
  136. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  137. data/test/dummy/config/initializers/devise.rb +290 -0
  138. data/test/dummy/config/initializers/devise_token_auth.rb +55 -0
  139. data/test/dummy/config/initializers/figaro.rb +3 -0
  140. data/test/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  141. data/test/dummy/config/initializers/inflections.rb +18 -0
  142. data/test/dummy/config/initializers/mime_types.rb +6 -0
  143. data/test/dummy/config/initializers/omniauth.rb +11 -0
  144. data/test/dummy/config/initializers/session_store.rb +5 -0
  145. data/test/dummy/config/initializers/wrap_parameters.rb +16 -0
  146. data/test/dummy/config/routes.rb +57 -0
  147. data/test/dummy/config/spring.rb +3 -0
  148. data/test/dummy/config.ru +18 -0
  149. data/test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb +58 -0
  150. data/test/dummy/db/migrate/20140715061805_devise_token_auth_create_mangs.rb +57 -0
  151. data/test/dummy/db/migrate/20140829044006_add_operating_thetan_to_user.rb +8 -0
  152. data/test/dummy/db/migrate/20140916224624_add_favorite_color_to_mangs.rb +7 -0
  153. data/test/dummy/db/migrate/20141222035835_devise_token_auth_create_only_email_users.rb +55 -0
  154. data/test/dummy/db/migrate/20141222053502_devise_token_auth_create_unregisterable_users.rb +56 -0
  155. data/test/dummy/db/migrate/20150708104536_devise_token_auth_create_unconfirmable_users.rb +56 -0
  156. data/test/dummy/db/migrate/20160103235141_devise_token_auth_create_scoped_users.rb +56 -0
  157. data/test/dummy/db/migrate/20160629184441_devise_token_auth_create_lockable_users.rb +56 -0
  158. data/test/dummy/db/migrate/20190924101113_devise_token_auth_create_confirmable_users.rb +49 -0
  159. data/test/dummy/db/schema.rb +198 -0
  160. data/test/dummy/lib/migration_database_helper.rb +43 -0
  161. data/test/dummy/tmp/generators/app/models/mang.rb +9 -0
  162. data/test/dummy/tmp/generators/app/models/user.rb +9 -0
  163. data/test/dummy/tmp/generators/config/initializers/devise_token_auth.rb +60 -0
  164. data/test/dummy/tmp/generators/config/routes.rb +9 -0
  165. data/test/dummy/tmp/generators/db/migrate/20210305040222_devise_token_auth_create_mangs.rb +49 -0
  166. data/test/dummy/tmp/generators/db/migrate/20210305040222_devise_token_auth_create_users.rb +49 -0
  167. data/test/factories/users.rb +41 -0
  168. data/test/lib/devise_token_auth/blacklist_test.rb +19 -0
  169. data/test/lib/devise_token_auth/rails/custom_routes_test.rb +29 -0
  170. data/test/lib/devise_token_auth/rails/routes_test.rb +87 -0
  171. data/test/lib/devise_token_auth/token_factory_test.rb +191 -0
  172. data/test/lib/devise_token_auth/url_test.rb +26 -0
  173. data/test/lib/generators/devise_token_auth/install_generator_test.rb +217 -0
  174. data/test/lib/generators/devise_token_auth/install_generator_with_namespace_test.rb +222 -0
  175. data/test/lib/generators/devise_token_auth/install_views_generator_test.rb +25 -0
  176. data/test/models/concerns/mongoid_support_test.rb +31 -0
  177. data/test/models/concerns/tokens_serialization_test.rb +104 -0
  178. data/test/models/confirmable_user_test.rb +35 -0
  179. data/test/models/only_email_user_test.rb +29 -0
  180. data/test/models/user_test.rb +224 -0
  181. data/test/support/controllers/routes.rb +43 -0
  182. data/test/test_helper.rb +134 -0
  183. metadata +502 -0
@@ -0,0 +1,50 @@
1
+ # Additional translations at https://github.com/plataformatec/devise/wiki/I18n
2
+
3
+ zh-TW:
4
+ devise_token_auth:
5
+ sessions:
6
+ not_confirmed: "您將在幾分鐘後收到一封電子郵件'%{email}',內有驗證帳號的步驟說明。"
7
+ bad_credentials: "不正確的登入資料。請重試。"
8
+ not_supported: "請使用 POST /sign_in 進行登入. GET 是不支援的."
9
+ user_not_found: "未能找到帳號或未能成功登入。"
10
+ token_validations:
11
+ invalid: "不正確的登入資料。"
12
+ registrations:
13
+ missing_confirm_success_url: "欠缺數值 'confirm_success_url'"
14
+ redirect_url_not_allowed: "不支援轉向到'%{redirect_url}'"
15
+ email_already_exists: "電郵'%{email}'已被使用"
16
+ account_with_uid_destroyed: "帳號 '%{uid}' 已被移除。"
17
+ account_to_destroy_not_found: "無法找到目標帳號。"
18
+ user_not_found: "找不到帳號。"
19
+ omniauth:
20
+ not_allowed_redirect_url: "不支援轉向到 '%{redirect_url}'"
21
+ passwords:
22
+ missing_email: "必需提供電郵。"
23
+ missing_redirect_url: "欠缺 redirect URL."
24
+ not_allowed_redirect_url: "不支援轉向到 '%{redirect_url}'"
25
+ sended: "您將在幾分鐘後收到一封電子郵件'%{email},內含可重新設定密碼連結的電子郵件。"
26
+ user_not_found: "找不到帳號 '%{email}'。"
27
+ password_not_required: "這不是一個需要密碼的帳號. 請使用 '%{provider}' 進行登入"
28
+ missing_passwords: "必需填寫'密碼'與'確認密碼'。"
29
+ successfully_updated: "您的密碼已被修改。"
30
+ errors:
31
+ messages:
32
+ validate_sign_up_params: "請在request body中填入有效的註冊內容"
33
+ validate_account_update_params: "請在request body中填入有效的更新帳號資料"
34
+ not_email: "這不是一個合適的電郵。"
35
+ devise:
36
+ mailer:
37
+ confirmation_instructions:
38
+ confirm_link_msg: "可以使用下面連結確定你的電郵"
39
+ confirm_account_link: "確定你的帳號"
40
+ reset_password_instructions:
41
+ request_reset_link_msg: "已申請修改您的密碼,你可以用下面連結進入"
42
+ password_change_link: "修改我的密碼"
43
+ ignore_mail_msg: "如你沒有申請,請忽略"
44
+ no_changes_msg: "在你點擊上面連結前,你的密碼都沒有改變"
45
+ unlock_instructions:
46
+ account_lock_msg: "由於多失敗登入,我們已鎖定你的帳號"
47
+ unlock_link_msg: "可以使用下面連結解鎖你的帳號"
48
+ unlock_link: "解鎖帳號"
49
+ hello: "你好"
50
+ welcome: "歡迎"
@@ -0,0 +1,50 @@
1
+ # Additional translations at https://github.com/plataformatec/devise/wiki/I18n
2
+
3
+ zh-TW:
4
+ devise_token_auth:
5
+ sessions:
6
+ not_confirmed: "您將在幾分鐘後收到一封電子郵件'%{email}',內有驗證帳號的步驟說明。"
7
+ bad_credentials: "不正確的登入資料。請重試。"
8
+ not_supported: "請使用 POST /sign_in 進行登入. GET 是不支援的."
9
+ user_not_found: "未能找到帳號或未能成功登入。"
10
+ token_validations:
11
+ invalid: "不正確的登入資料。"
12
+ registrations:
13
+ missing_confirm_success_url: "欠缺數值 'confirm_success_url'"
14
+ redirect_url_not_allowed: "不支援轉向到'%{redirect_url}'"
15
+ email_already_exists: "電郵'%{email}'已被使用"
16
+ account_with_uid_destroyed: "帳號 '%{uid}' 已被移除。"
17
+ account_to_destroy_not_found: "無法找到目標帳號。"
18
+ user_not_found: "找不到帳號。"
19
+ omniauth:
20
+ not_allowed_redirect_url: "不支援轉向到 '%{redirect_url}'"
21
+ passwords:
22
+ missing_email: "必需提供電郵。"
23
+ missing_redirect_url: "欠缺 redirect URL."
24
+ not_allowed_redirect_url: "不支援轉向到 '%{redirect_url}'"
25
+ sended: "您將在幾分鐘後收到一封電子郵件'%{email},內含可重新設定密碼連結的電子郵件。"
26
+ user_not_found: "找不到帳號 '%{email}'。"
27
+ password_not_required: "這不是一個需要密碼的帳號. 請使用 '%{provider}' 進行登入"
28
+ missing_passwords: "必需填寫'密碼'與'確認密碼'。"
29
+ successfully_updated: "您的密碼已被修改。"
30
+ errors:
31
+ messages:
32
+ validate_sign_up_params: "請在request body中填入有效的註冊內容"
33
+ validate_account_update_params: "請在request body中填入有效的更新帳號資料"
34
+ not_email: "這不是一個合適的電郵。"
35
+ devise:
36
+ mailer:
37
+ confirmation_instructions:
38
+ confirm_link_msg: "可以使用下面連結確定你的電郵"
39
+ confirm_account_link: "確定你的帳號"
40
+ reset_password_instructions:
41
+ request_reset_link_msg: "已申請修改您的密碼,你可以用下面連結進入"
42
+ password_change_link: "修改我的密碼"
43
+ ignore_mail_msg: "如你沒有申請,請忽略"
44
+ no_changes_msg: "在你點擊上面連結前,你的密碼都沒有改變"
45
+ unlock_instructions:
46
+ account_lock_msg: "由於多失敗登入,我們已鎖定你的帳號"
47
+ unlock_link_msg: "可以使用下面連結解鎖你的帳號"
48
+ unlock_link: "解鎖帳號"
49
+ hello: "你好"
50
+ welcome: "歡迎"
@@ -0,0 +1,6 @@
1
+ # don't serialize tokens
2
+ if defined? Devise::Models::Authenticatable::UNSAFE_ATTRIBUTES_FOR_SERIALIZATION
3
+ Devise::Models::Authenticatable::UNSAFE_ATTRIBUTES_FOR_SERIALIZATION << :tokens
4
+ else
5
+ Devise::Models::Authenticatable::BLACKLIST_FOR_SERIALIZATION << :tokens
6
+ end
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeviseTokenAuth
4
+ module Controllers
5
+ module Helpers
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ # Define authentication filters and accessor helpers for a group of mappings.
10
+ # These methods are useful when you are working with multiple mappings that
11
+ # share some functionality. They are pretty much the same as the ones
12
+ # defined for normal mappings.
13
+ #
14
+ # Example:
15
+ #
16
+ # inside BlogsController (or any other controller, it doesn't matter which):
17
+ # devise_group :blogger, contains: [:user, :admin]
18
+ #
19
+ # Generated methods:
20
+ # authenticate_blogger! # Redirects unless user or admin are signed in
21
+ # blogger_signed_in? # Checks whether there is either a user or an admin signed in
22
+ # current_blogger # Currently signed in user or admin
23
+ # current_bloggers # Currently signed in user and admin
24
+ # render_authenticate_error # Render error unless user or admin are signed in
25
+ #
26
+ # Use:
27
+ # before_action :authenticate_blogger! # Redirects unless either a user or an admin are authenticated
28
+ # before_action ->{ authenticate_blogger! :admin } # Redirects to the admin login page
29
+ # current_blogger :user # Preferably returns a User if one is signed in
30
+ #
31
+ def devise_token_auth_group(group_name, opts = {})
32
+ mappings = "[#{opts[:contains].map { |m| ":#{m}" }.join(',')}]"
33
+
34
+ class_eval <<-METHODS, __FILE__, __LINE__ + 1
35
+ def authenticate_#{group_name}!(favourite=nil, opts={})
36
+ unless #{group_name}_signed_in?
37
+ unless current_#{group_name}
38
+ render_authenticate_error
39
+ end
40
+ end
41
+ end
42
+
43
+ def #{group_name}_signed_in?
44
+ !!current_#{group_name}
45
+ end
46
+
47
+ def current_#{group_name}(favourite=nil)
48
+ @current_#{group_name} ||= set_group_user_by_token(favourite)
49
+ end
50
+
51
+ def set_group_user_by_token(favourite)
52
+ mappings = #{mappings}
53
+ mappings.unshift mappings.delete(favourite.to_sym) if favourite
54
+ mappings.each do |mapping|
55
+ current = set_user_by_token(mapping)
56
+ return current if current
57
+ end
58
+ nil
59
+ end
60
+
61
+ def current_#{group_name.to_s.pluralize}
62
+ #{mappings}.map do |mapping|
63
+ set_user_by_token(mapping)
64
+ end.compact
65
+ end
66
+
67
+ def render_authenticate_error
68
+ return render json: {
69
+ errors: [I18n.t('devise.failure.unauthenticated')]
70
+ }, status: 401
71
+ end
72
+
73
+ if respond_to?(:helper_method)
74
+ helper_method(
75
+ "current_#{group_name}",
76
+ "current_#{group_name.to_s.pluralize}",
77
+ "#{group_name}_signed_in?",
78
+ "render_authenticate_error"
79
+ )
80
+ end
81
+ METHODS
82
+ end
83
+
84
+ def log_process_action(payload)
85
+ payload[:status] ||= 401 unless payload[:exception]
86
+ super
87
+ end
88
+ end
89
+
90
+ # Define authentication filters and accessor helpers based on mappings.
91
+ # These filters should be used inside the controllers as before_actions,
92
+ # so you can control the scope of the user who should be signed in to
93
+ # access that specific controller/action.
94
+ # Example:
95
+ #
96
+ # Roles:
97
+ # User
98
+ # Admin
99
+ #
100
+ # Generated methods:
101
+ # authenticate_user! # Signs user in or 401
102
+ # authenticate_admin! # Signs admin in or 401
103
+ # user_signed_in? # Checks whether there is a user signed in or not
104
+ # admin_signed_in? # Checks whether there is an admin signed in or not
105
+ # current_user # Current signed in user
106
+ # current_admin # Current signed in admin
107
+ # user_session # Session data available only to the user scope
108
+ # admin_session # Session data available only to the admin scope
109
+ # render_authenticate_error # Render error unless user or admin is signed in
110
+ #
111
+ # Use:
112
+ # before_action :authenticate_user! # Tell devise to use :user map
113
+ # before_action :authenticate_admin! # Tell devise to use :admin map
114
+ #
115
+ def self.define_helpers(mapping) #:nodoc:
116
+ mapping = mapping.name
117
+
118
+ class_eval <<-METHODS, __FILE__, __LINE__ + 1
119
+ def authenticate_#{mapping}!(opts={})
120
+ unless current_#{mapping}
121
+ render_authenticate_error
122
+ end
123
+ end
124
+
125
+ def #{mapping}_signed_in?
126
+ !!current_#{mapping}
127
+ end
128
+
129
+ def current_#{mapping}
130
+ @current_#{mapping} ||= set_user_by_token(:#{mapping})
131
+ end
132
+
133
+ def #{mapping}_session
134
+ current_#{mapping} && warden.session(:#{mapping})
135
+ end
136
+
137
+ def render_authenticate_error
138
+ return render json: {
139
+ errors: [I18n.t('devise.failure.unauthenticated')]
140
+ }, status: 401
141
+ end
142
+ METHODS
143
+
144
+ ActiveSupport.on_load(:action_controller) do
145
+ if respond_to?(:helper_method)
146
+ helper_method(
147
+ "current_#{mapping}",
148
+ "#{mapping}_signed_in?",
149
+ "#{mapping}_session",
150
+ 'render_authenticate_error'
151
+ )
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeviseTokenAuth
4
+ module Controllers
5
+ module UrlHelpers
6
+ def self.define_helpers(mapping)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'devise_token_auth/rails/routes'
4
+
5
+ module DeviseTokenAuth
6
+ class Engine < ::Rails::Engine
7
+ isolate_namespace DeviseTokenAuth
8
+
9
+ initializer 'devise_token_auth.url_helpers' do
10
+ Devise.helpers << DeviseTokenAuth::Controllers::Helpers
11
+ end
12
+ end
13
+
14
+ mattr_accessor :change_headers_on_each_request,
15
+ :max_number_of_devices,
16
+ :token_lifespan,
17
+ :token_cost,
18
+ :batch_request_buffer_throttle,
19
+ :omniauth_prefix,
20
+ :default_confirm_success_url,
21
+ :default_password_reset_url,
22
+ :redirect_whitelist,
23
+ :check_current_password_before_update,
24
+ :enable_standard_devise_support,
25
+ :remove_tokens_after_password_reset,
26
+ :default_callbacks,
27
+ :headers_names,
28
+ :cookie_enabled,
29
+ :cookie_name,
30
+ :cookie_attributes,
31
+ :bypass_sign_in,
32
+ :send_confirmation_email,
33
+ :require_client_password_reset_token,
34
+ :other_uid
35
+
36
+ self.change_headers_on_each_request = true
37
+ self.max_number_of_devices = 10
38
+ self.token_lifespan = 2.weeks
39
+ self.token_cost = 10
40
+ self.batch_request_buffer_throttle = 5.seconds
41
+ self.omniauth_prefix = '/omniauth'
42
+ self.default_confirm_success_url = nil
43
+ self.default_password_reset_url = nil
44
+ self.redirect_whitelist = nil
45
+ self.check_current_password_before_update = false
46
+ self.enable_standard_devise_support = false
47
+ self.remove_tokens_after_password_reset = false
48
+ self.default_callbacks = true
49
+ self.headers_names = { 'authorization': 'Authorization',
50
+ 'access-token': 'access-token',
51
+ 'client': 'client',
52
+ 'expiry': 'expiry',
53
+ 'uid': 'uid',
54
+ 'token-type': 'token-type' }
55
+ self.cookie_enabled = false
56
+ self.cookie_name = 'auth_cookie'
57
+ self.cookie_attributes = {}
58
+ self.bypass_sign_in = true
59
+ self.send_confirmation_email = false
60
+ self.require_client_password_reset_token = false
61
+ self.other_uid = nil
62
+
63
+ def self.setup(&block)
64
+ yield self
65
+
66
+ Rails.application.config.after_initialize do
67
+ if defined?(::OmniAuth)
68
+ ::OmniAuth::config.path_prefix = Devise.omniauth_path_prefix = omniauth_prefix
69
+
70
+ # Omniauth currently does not pass along omniauth.params upon failure redirect
71
+ # see also: https://github.com/intridea/omniauth/issues/626
72
+ OmniAuth::FailureEndpoint.class_eval do
73
+ def redirect_to_failure
74
+ message_key = env['omniauth.error.type']
75
+ origin_query_param = env['omniauth.origin'] ? "&origin=#{CGI.escape(env['omniauth.origin'])}" : ''
76
+ strategy_name_query_param = env['omniauth.error.strategy'] ? "&strategy=#{env['omniauth.error.strategy'].name}" : ''
77
+ extra_params = env['omniauth.params'] ? "&#{env['omniauth.params'].to_query}" : ''
78
+ new_path = "#{env['SCRIPT_NAME']}#{OmniAuth.config.path_prefix}/failure?message=#{message_key}#{origin_query_param}#{strategy_name_query_param}#{extra_params}"
79
+ Rack::Response.new(['302 Moved'], 302, 'Location' => new_path).finish
80
+ end
81
+ end
82
+
83
+ # Omniauth currently removes omniauth.params during mocked requests
84
+ # see also: https://github.com/intridea/omniauth/pull/812
85
+ OmniAuth::Strategy.class_eval do
86
+ def mock_callback_call
87
+ setup_phase
88
+ @env['omniauth.origin'] = session.delete('omniauth.origin')
89
+ @env['omniauth.origin'] = nil if env['omniauth.origin'] == ''
90
+ @env['omniauth.params'] = session.delete('omniauth.params') || {}
91
+ mocked_auth = OmniAuth.mock_auth_for(name.to_s)
92
+ if mocked_auth.is_a?(Symbol)
93
+ fail!(mocked_auth)
94
+ else
95
+ @env['omniauth.auth'] = mocked_auth
96
+ OmniAuth.config.before_callback_phase.call(@env) if OmniAuth.config.before_callback_phase
97
+ call_app!
98
+ end
99
+ end
100
+ end
101
+
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeviseTokenAuth
4
+ module Errors
5
+ class NoResourceDefinedError < StandardError; end
6
+ class InvalidModel < StandardError; end
7
+ end
8
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch::Routing
4
+ class Mapper
5
+ def mount_devise_token_auth_for(resource, opts)
6
+ # ensure objects exist to simplify attr checks
7
+ opts[:controllers] ||= {}
8
+ opts[:skip] ||= []
9
+
10
+ # check for ctrl overrides, fall back to defaults
11
+ sessions_ctrl = opts[:controllers].delete(:sessions) || 'devise_token_auth/sessions'
12
+ registrations_ctrl = opts[:controllers].delete(:registrations) || 'devise_token_auth/registrations'
13
+ passwords_ctrl = opts[:controllers].delete(:passwords) || 'devise_token_auth/passwords'
14
+ confirmations_ctrl = opts[:controllers].delete(:confirmations) || 'devise_token_auth/confirmations'
15
+ token_validations_ctrl = opts[:controllers].delete(:token_validations) || 'devise_token_auth/token_validations'
16
+ omniauth_ctrl = opts[:controllers].delete(:omniauth_callbacks) || 'devise_token_auth/omniauth_callbacks'
17
+ unlocks_ctrl = opts[:controllers].delete(:unlocks) || 'devise_token_auth/unlocks'
18
+
19
+ # check for resource override
20
+ route = opts[:as] || resource.pluralize.underscore.gsub('/', '_')
21
+
22
+ # define devise controller mappings
23
+ controllers = opts[:controllers].merge(
24
+ sessions: sessions_ctrl,
25
+ registrations: registrations_ctrl,
26
+ passwords: passwords_ctrl,
27
+ confirmations: confirmations_ctrl
28
+ )
29
+
30
+ controllers[:unlocks] = unlocks_ctrl if unlocks_ctrl
31
+
32
+ # remove any unwanted devise modules
33
+ opts[:skip].each{ |item| controllers.delete(item) }
34
+
35
+ devise_for route.to_sym,
36
+ class_name: resource,
37
+ module: :devise,
38
+ path: opts[:at].to_s,
39
+ controllers: controllers,
40
+ skip: opts[:skip] + [:omniauth_callbacks]
41
+
42
+ unnest_namespace do
43
+ # get full url path as if it were namespaced
44
+ full_path = "#{@scope[:path]}/#{opts[:at]}"
45
+
46
+ # get namespace name
47
+ namespace_name = @scope[:as]
48
+
49
+ # clear scope so controller routes aren't namespaced
50
+ @scope = ActionDispatch::Routing::Mapper::Scope.new(
51
+ path: '',
52
+ shallow_path: '',
53
+ constraints: {},
54
+ defaults: {},
55
+ options: {},
56
+ parent: nil
57
+ )
58
+
59
+ mapping_name = resource.underscore.gsub('/', '_')
60
+ mapping_name = "#{namespace_name}_#{mapping_name}" if namespace_name
61
+
62
+ devise_scope mapping_name.to_sym do
63
+ # path to verify token validity
64
+ get "#{full_path}/validate_token", controller: token_validations_ctrl.to_s, action: 'validate_token' if !opts[:skip].include?(:token_validations)
65
+
66
+ # omniauth routes. only define if omniauth is installed and not skipped.
67
+ if defined?(::OmniAuth) && !opts[:skip].include?(:omniauth_callbacks)
68
+ match "#{full_path}/failure", controller: omniauth_ctrl, action: 'omniauth_failure', via: [:get, :post]
69
+ match "#{full_path}/:provider/callback", controller: omniauth_ctrl, action: 'omniauth_success', via: [:get, :post]
70
+
71
+ match "#{DeviseTokenAuth.omniauth_prefix}/:provider/callback", controller: omniauth_ctrl, action: 'redirect_callbacks', via: [:get, :post]
72
+ match "#{DeviseTokenAuth.omniauth_prefix}/failure", controller: omniauth_ctrl, action: 'omniauth_failure', via: [:get, :post]
73
+
74
+ # preserve the resource class thru oauth authentication by setting name of
75
+ # resource as "resource_class" param
76
+ match "#{full_path}/:provider", to: redirect(status: 307) { |params, request|
77
+ # get the current querystring
78
+ # TODO: deprecate in favor of using params
79
+ qs = CGI::parse(request.env['QUERY_STRING'].empty? ? request.body.read : request.env['QUERY_STRING'] )
80
+
81
+ # append name of current resource
82
+ qs['resource_class'] = [resource]
83
+ qs['namespace_name'] = [namespace_name] if namespace_name
84
+
85
+ set_omniauth_path_prefix!(DeviseTokenAuth.omniauth_prefix)
86
+
87
+ redirect_params = {}.tap { |hash| qs.each{ |k, v| hash[k] = v.first } }
88
+
89
+ if DeviseTokenAuth.redirect_whitelist
90
+ redirect_url = request.params['auth_origin_url']
91
+ unless DeviseTokenAuth::Url.whitelisted?(redirect_url)
92
+ message = I18n.t(
93
+ 'devise_token_auth.registrations.redirect_url_not_allowed',
94
+ redirect_url: redirect_url
95
+ )
96
+ redirect_params['message'] = message
97
+ next "#{::OmniAuth.config.path_prefix}/failure?#{redirect_params.to_param}"
98
+ end
99
+ end
100
+
101
+ # re-construct the path for omniauth
102
+ "#{::OmniAuth.config.path_prefix}/#{params[:provider]}?#{redirect_params.to_param}"
103
+ }, via: [:get, :post]
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ # this allows us to use namespaced paths without namespacing the routes
110
+ def unnest_namespace
111
+ current_scope = @scope.dup
112
+ yield
113
+ ensure
114
+ @scope = current_scope
115
+ end
116
+
117
+ # ignore error about omniauth/multiple model support
118
+ def set_omniauth_path_prefix!(path_prefix)
119
+ ::OmniAuth.config.path_prefix = path_prefix
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,126 @@
1
+ require 'bcrypt'
2
+
3
+ module DeviseTokenAuth
4
+ # A token management factory which allow generate token objects and check them.
5
+ module TokenFactory
6
+ # For BCrypt::Password class see:
7
+ # https://github.com/codahale/bcrypt-ruby/blob/master/lib/bcrypt/password.rb
8
+
9
+ # Creates a token instance. Takes an optional client, lifespan and cost options.
10
+ # Example:
11
+ # DeviseTokenAuth::TokenFactory.create
12
+ # => #<struct DeviseTokenAuth::TokenFactory::Token client="tElcgkdZ7f9XEa0unZhrYQ", token="rAMcWOs0-mGHFMnIgJD2cA", token_hash="$2a$10$wrsdlHVRGlYW11wfImxU..jr0Ux3bHo/qbXcSfgp8zmvVUNHosita", expiry=1518982690>
13
+ #
14
+ # DeviseTokenAuth::TokenFactory.create(lifespan: 10, cost: 4)
15
+ # => #<struct DeviseTokenAuth::TokenFactory::Token client="5qleT7_t9JPVcX9xmxkVYA", token="RBXX43u4xXNSO-fr2N_4pA", token_hash="$2a$04$9gpCaoFbu2dUKxU3qiTgluHX7jj9UzS.jq1QW0EkQmoaxARo1WxTy", expiry=1517773268>
16
+ def self.create(client: nil, lifespan: nil, cost: nil)
17
+ # obj_client = client.nil? ? client() : client
18
+ obj_client = client || client()
19
+ obj_token = token
20
+ obj_token_hash = token_hash(obj_token, cost)
21
+ obj_expiry = expiry(lifespan)
22
+
23
+ Token.new(obj_client, obj_token, obj_token_hash, obj_expiry)
24
+ end
25
+
26
+ # Generates a random URL-safe client.
27
+ # Example:
28
+ # DeviseTokenAuth::TokenFactory.client
29
+ # => "zNf0pNP5iGfuBItZJGCseQ"
30
+ def self.client
31
+ secure_string
32
+ end
33
+
34
+ # Generates a random URL-safe token.
35
+ # Example:
36
+ # DeviseTokenAuth::TokenFactory.token
37
+ # => "6Bqs4K9x8ChLmZogvruF3A"
38
+ def self.token
39
+ secure_string
40
+ end
41
+
42
+ # Returns token hash for a token with given cost. If no cost value is specified,
43
+ # the default value is used. The possible cost value is within range from 4 to 31.
44
+ # It is recommended to not use a value more than 10.
45
+ # Example:
46
+ # DeviseTokenAuth::TokenFactory.token_hash("_qxAxmc-biQLiYRHsmwd5Q")
47
+ # => "$2a$10$6/cTAtQ3CBLfpkeHW7dlt.PD2aVCbFRN5vDDJUUhGsZ6pzYFlh4Me"
48
+ #
49
+ # DeviseTokenAuth::TokenFactory.token_hash("_qxAxmc-biQLiYRHsmwd5Q", 4)
50
+ # => "$2a$04$RkIrosbdRtuet2eUk3si8eS4ufeNpiPc/rSSsfpniRK8ogM5YFOWS"
51
+ def self.token_hash(token, cost = nil)
52
+ cost ||= DeviseTokenAuth.token_cost
53
+ BCrypt::Password.create(token, cost: cost)
54
+ end
55
+
56
+ # Returns the value of time as an integer number of seconds. Takes one argument.
57
+ # Example:
58
+ # DeviseTokenAuth::TokenFactory.expiry
59
+ # => 1518983359
60
+ # DeviseTokenAuth::TokenFactory.expiry(10)
61
+ # => 1517773781
62
+ def self.expiry(lifespan = nil)
63
+ lifespan ||= DeviseTokenAuth.token_lifespan
64
+ (Time.zone.now + lifespan).to_i
65
+ end
66
+
67
+ # Generates a random URL-safe string.
68
+ # Example:
69
+ # DeviseTokenAuth::TokenFactory.secure_string
70
+ # => "ADBoIaqXsEDnxIpOuumrTA"
71
+ def self.secure_string
72
+ # https://ruby-doc.org/stdlib-2.5.0/libdoc/securerandom/rdoc/Random/Formatter.html#method-i-urlsafe_base64
73
+ SecureRandom.urlsafe_base64
74
+ end
75
+
76
+ # Returns true if token hash is a valid token hash.
77
+ # Example:
78
+ # token_hash = "$2a$10$ArjX0tskRIa5Z/Tmapy59OCiAXLStfhrCiaDz.8fCb6hnX1gJ0p/2"
79
+ # DeviseTokenAuth::TokenFactory.valid_token_hash?(token_hash)
80
+ # => true
81
+ def self.valid_token_hash?(token_hash)
82
+ !!BCrypt::Password.valid_hash?(token_hash)
83
+ end
84
+
85
+ # Compares a potential token against the token hash. Returns true if the token is the original token, false otherwise.
86
+ # Example:
87
+ # token = "4wZ9gcc900rMQD1McpcSNA"
88
+ # token_hash = "$2a$10$ArjX0tskRIa5Z/Tmapy59OCiAXLStfhrCiaDz.8fCb6hnX1gJ0p/2"
89
+ # DeviseTokenAuth::TokenFactory.token_hash_is_token?(token_hash, token)
90
+ # => true
91
+ def self.token_hash_is_token?(token_hash, token)
92
+ BCrypt::Password.new(token_hash).is_password?(token)
93
+ rescue StandardError
94
+ false
95
+ end
96
+
97
+ # Creates a token instance with instance variables equal nil.
98
+ # Example:
99
+ # DeviseTokenAuth::TokenFactory.new
100
+ # => #<struct DeviseTokenAuth::TokenFactory::Token client=nil, token=nil, token_hash=nil, expiry=nil>
101
+ def self.new
102
+ Token.new
103
+ end
104
+
105
+ Token = Struct.new(:client, :token, :token_hash, :expiry) do
106
+ # Sets all instance variables of the token to nil. It is faster than creating new empty token.
107
+ # Example:
108
+ # token.clear!
109
+ # => true
110
+ # token
111
+ # => #<struct DeviseTokenAuth::TokenFactory::Token client=nil, token=nil, token_hash=nil, expiry=nil>
112
+ def clear!
113
+ size.times { |i| self[i] = nil }
114
+ true
115
+ end
116
+
117
+ # Checks token attribute presence
118
+ # Example:
119
+ # token.present?
120
+ # => true
121
+ def present?
122
+ token.present?
123
+ end
124
+ end
125
+ end
126
+ end