diff options
Diffstat (limited to 'src/actions/mixins')
-rw-r--r-- | src/actions/mixins/.keep | 0 | ||||
-rw-r--r-- | src/actions/mixins/api/auth/helpers.cr | 28 | ||||
-rw-r--r-- | src/actions/mixins/api/auth/require_auth_token.cr | 34 | ||||
-rw-r--r-- | src/actions/mixins/api/auth/skip_require_auth_token.cr | 10 | ||||
-rw-r--r-- | src/actions/mixins/auth/allow_guests.cr | 10 | ||||
-rw-r--r-- | src/actions/mixins/auth/password_resets/base.cr | 7 | ||||
-rw-r--r-- | src/actions/mixins/auth/password_resets/find_user.cr | 5 | ||||
-rw-r--r-- | src/actions/mixins/auth/password_resets/require_token.cr | 17 | ||||
-rw-r--r-- | src/actions/mixins/auth/password_resets/token_from_session.cr | 5 | ||||
-rw-r--r-- | src/actions/mixins/auth/redirect_signed_in_users.cr | 19 | ||||
-rw-r--r-- | src/actions/mixins/auth/require_sign_in.cr | 21 | ||||
-rw-r--r-- | src/actions/mixins/auth/test_backdoor.cr | 13 |
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 |