aboutsummaryrefslogtreecommitdiff
path: root/src/actions/mixins
diff options
context:
space:
mode:
Diffstat (limited to 'src/actions/mixins')
-rw-r--r--src/actions/mixins/.keep0
-rw-r--r--src/actions/mixins/api/auth/helpers.cr28
-rw-r--r--src/actions/mixins/api/auth/require_auth_token.cr34
-rw-r--r--src/actions/mixins/api/auth/skip_require_auth_token.cr10
-rw-r--r--src/actions/mixins/auth/allow_guests.cr10
-rw-r--r--src/actions/mixins/auth/password_resets/base.cr7
-rw-r--r--src/actions/mixins/auth/password_resets/find_user.cr5
-rw-r--r--src/actions/mixins/auth/password_resets/require_token.cr17
-rw-r--r--src/actions/mixins/auth/password_resets/token_from_session.cr5
-rw-r--r--src/actions/mixins/auth/redirect_signed_in_users.cr19
-rw-r--r--src/actions/mixins/auth/require_sign_in.cr21
-rw-r--r--src/actions/mixins/auth/test_backdoor.cr13
12 files changed, 169 insertions, 0 deletions
diff --git a/src/actions/mixins/.keep b/src/actions/mixins/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/actions/mixins/.keep
diff --git a/src/actions/mixins/api/auth/helpers.cr b/src/actions/mixins/api/auth/helpers.cr
new file mode 100644
index 0000000..6b51cb5
--- /dev/null
+++ b/src/actions/mixins/api/auth/helpers.cr
@@ -0,0 +1,28 @@
+module Api::Auth::Helpers
+ # The 'memoize' macro makes sure only one query is issued to find the user
+ memoize def current_user? : User?
+ auth_token.try do |value|
+ user_from_auth_token(value)
+ end
+ end
+
+ private def auth_token : String?
+ bearer_token || token_param
+ end
+
+ private def bearer_token : String?
+ context.request.headers["Authorization"]?
+ .try(&.gsub("Bearer", ""))
+ .try(&.strip)
+ end
+
+ private def token_param : String?
+ params.get?(:auth_token)
+ end
+
+ private def user_from_auth_token(token : String) : User?
+ UserToken.decode_user_id(token).try do |user_id|
+ UserQuery.new.id(user_id).first?
+ end
+ end
+end
diff --git a/src/actions/mixins/api/auth/require_auth_token.cr b/src/actions/mixins/api/auth/require_auth_token.cr
new file mode 100644
index 0000000..e018638
--- /dev/null
+++ b/src/actions/mixins/api/auth/require_auth_token.cr
@@ -0,0 +1,34 @@
+module Api::Auth::RequireAuthToken
+ macro included
+ before require_auth_token
+ end
+
+ private def require_auth_token
+ if current_user?
+ continue
+ else
+ json auth_error_json, 401
+ end
+ end
+
+ private def auth_error_json
+ ErrorSerializer.new(
+ message: "Not authenticated.",
+ details: auth_error_details
+ )
+ end
+
+ private def auth_error_details : String
+ if auth_token
+ "The provided authentication token was incorrect."
+ else
+ "An authentication token is required. Please include a token in an 'auth_token' param or 'Authorization' header."
+ end
+ end
+
+ # Tells the compiler that the current_user is not nil since we have checked
+ # that the user is signed in
+ private def current_user : User
+ current_user?.as(User)
+ end
+end
diff --git a/src/actions/mixins/api/auth/skip_require_auth_token.cr b/src/actions/mixins/api/auth/skip_require_auth_token.cr
new file mode 100644
index 0000000..68098cf
--- /dev/null
+++ b/src/actions/mixins/api/auth/skip_require_auth_token.cr
@@ -0,0 +1,10 @@
+module Api::Auth::SkipRequireAuthToken
+ macro included
+ skip require_auth_token
+ end
+
+ # Since sign in is not required, current_user might be nil
+ def current_user : User?
+ current_user?
+ end
+end
diff --git a/src/actions/mixins/auth/allow_guests.cr b/src/actions/mixins/auth/allow_guests.cr
new file mode 100644
index 0000000..3961399
--- /dev/null
+++ b/src/actions/mixins/auth/allow_guests.cr
@@ -0,0 +1,10 @@
+module Auth::AllowGuests
+ macro included
+ skip require_sign_in
+ end
+
+ # Since sign in is not required, current_user might be nil
+ def current_user : User?
+ current_user?
+ end
+end
diff --git a/src/actions/mixins/auth/password_resets/base.cr b/src/actions/mixins/auth/password_resets/base.cr
new file mode 100644
index 0000000..77166a9
--- /dev/null
+++ b/src/actions/mixins/auth/password_resets/base.cr
@@ -0,0 +1,7 @@
+module Auth::PasswordResets::Base
+ macro included
+ include Auth::RedirectSignedInUsers
+ include Auth::PasswordResets::FindUser
+ include Auth::PasswordResets::RequireToken
+ end
+end
diff --git a/src/actions/mixins/auth/password_resets/find_user.cr b/src/actions/mixins/auth/password_resets/find_user.cr
new file mode 100644
index 0000000..cab02d5
--- /dev/null
+++ b/src/actions/mixins/auth/password_resets/find_user.cr
@@ -0,0 +1,5 @@
+module Auth::PasswordResets::FindUser
+ private def user : User
+ UserQuery.find(user_id)
+ end
+end
diff --git a/src/actions/mixins/auth/password_resets/require_token.cr b/src/actions/mixins/auth/password_resets/require_token.cr
new file mode 100644
index 0000000..15da423
--- /dev/null
+++ b/src/actions/mixins/auth/password_resets/require_token.cr
@@ -0,0 +1,17 @@
+module Auth::PasswordResets::RequireToken
+ macro included
+ before require_valid_password_reset_token
+ end
+
+ abstract def token : String
+ abstract def user : User
+
+ private def require_valid_password_reset_token
+ if Authentic.valid_password_reset_token?(user, token)
+ continue
+ else
+ flash.failure = "The password reset link is incorrect or expired. Please try again."
+ redirect to: PasswordResetRequests::New
+ end
+ end
+end
diff --git a/src/actions/mixins/auth/password_resets/token_from_session.cr b/src/actions/mixins/auth/password_resets/token_from_session.cr
new file mode 100644
index 0000000..820b91b
--- /dev/null
+++ b/src/actions/mixins/auth/password_resets/token_from_session.cr
@@ -0,0 +1,5 @@
+module Auth::PasswordResets::TokenFromSession
+ private def token : String
+ session.get?(:password_reset_token) || raise "Password reset token not found in session"
+ end
+end
diff --git a/src/actions/mixins/auth/redirect_signed_in_users.cr b/src/actions/mixins/auth/redirect_signed_in_users.cr
new file mode 100644
index 0000000..546bf7b
--- /dev/null
+++ b/src/actions/mixins/auth/redirect_signed_in_users.cr
@@ -0,0 +1,19 @@
+module Auth::RedirectSignedInUsers
+ macro included
+ include Auth::AllowGuests
+ before redirect_signed_in_users
+ end
+
+ private def redirect_signed_in_users
+ if current_user?
+ flash.success = "You are already signed in"
+ redirect to: Home::Index
+ else
+ continue
+ end
+ end
+
+ # current_user returns nil because signed in users are redirected.
+ def current_user
+ end
+end
diff --git a/src/actions/mixins/auth/require_sign_in.cr b/src/actions/mixins/auth/require_sign_in.cr
new file mode 100644
index 0000000..27a6f5e
--- /dev/null
+++ b/src/actions/mixins/auth/require_sign_in.cr
@@ -0,0 +1,21 @@
+module Auth::RequireSignIn
+ macro included
+ before require_sign_in
+ end
+
+ private def require_sign_in
+ if current_user?
+ continue
+ else
+ Authentic.remember_requested_path(self)
+ flash.info = "Please sign in first"
+ redirect to: SignIns::New
+ end
+ end
+
+ # Tells the compiler that the current_user is not nil since we have checked
+ # that the user is signed in
+ private def current_user : User
+ current_user?.as(User)
+ end
+end
diff --git a/src/actions/mixins/auth/test_backdoor.cr b/src/actions/mixins/auth/test_backdoor.cr
new file mode 100644
index 0000000..68c9d91
--- /dev/null
+++ b/src/actions/mixins/auth/test_backdoor.cr
@@ -0,0 +1,13 @@
+module Auth::TestBackdoor
+ macro included
+ before test_backdoor
+ end
+
+ private def test_backdoor
+ if LuckyEnv.test? && (user_id = params.get?(:backdoor_user_id))
+ user = UserQuery.find(user_id)
+ sign_in user
+ end
+ continue
+ end
+end