From 1f929cdab6835853612d7bc62d89f7d7c9fc92b0 Mon Sep 17 00:00:00 2001 From: Philippe Pittoli Date: Mon, 18 Nov 2024 07:45:37 +0100 Subject: [PATCH] Dedicated messages to change the user email address. --- src/requests/mail.cr | 77 ++++++++++++++++++++++++++++++++++++++++ src/responses/contact.cr | 2 +- src/responses/email.cr | 13 +++++++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/requests/mail.cr create mode 100644 src/responses/email.cr diff --git a/src/requests/mail.cr b/src/requests/mail.cr new file mode 100644 index 0000000..123ba51 --- /dev/null +++ b/src/requests/mail.cr @@ -0,0 +1,77 @@ +class AuthD::Request + # NewEmailAddress: any connected user can ask to change its email address. + IPC::JSON.message NewEmailAddress, 16 do + property email : String + + def initialize(@email) + end + + def handle(authd : AuthD::Service, fd : Int32) + logged_user = authd.get_logged_user_full? fd + return Response::ErrorMustBeAuthenticated.new if logged_user.nil? + + cloned_user = logged_user.clone + + # In case of a new email address: + # 1. the new address is stored as "pending_email" + # 2. the new address has to be validated before being used as primary email address + + # Verify the email address isn't already in the database. + if authd.users_per_email.get? Base64.encode(@email).chomp + return Response::ErrorEmailAddressAlreadyUsed.new + end + cloned_user.contact.pending_email = @email + cloned_user.contact.new_activation_key + + begin + u_login = cloned_user.login + u_email = cloned_user.contact.pending_email.not_nil! + u_activation_token = cloned_user.contact.activation_key.not_nil! + + # Once the user is created and stored, we try to contact him. + send_activation_token authd, u_login, u_email, u_activation_token + rescue e + Baguette::Log.error "mailer: #{e}" + return Response::ErrorCannotContactUser.new + end + + authd.users_per_uid.update cloned_user + + Response::NewEmailTokenSent.new + end + end + AuthD.requests << NewEmailAddress + + # NewEmailAddressToken: validate a pending email address. + IPC::JSON.message NewEmailAddressToken, 17 do + property token : String + + def initialize(@token) + end + + def handle(authd : AuthD::Service, fd : Int32) + logged_user = authd.get_logged_user_full? fd + return Response::ErrorMustBeAuthenticated.new if logged_user.nil? + + if logged_user.contact.activation_key.nil? + return Response::ErrorUserAlreadyValidated.new + end + + # Remove the user contact activation key: the email is validated. + if logged_user.contact.activation_key != @token + return Response::ErrorInvalidActivationKey.new + end + + cloned_user = logged_user.clone + + cloned_user.contact.activation_key = nil + cloned_user.contact.email = cloned_user.contact.pending_email + cloned_user.contact.pending_email = nil + + authd.users_per_uid.update cloned_user + + Response::NewEmailAddressValidated.new + end + end + AuthD.requests << NewEmailAddressToken +end diff --git a/src/responses/contact.cr b/src/responses/contact.cr index c4cc413..5c35c8b 100644 --- a/src/responses/contact.cr +++ b/src/responses/contact.cr @@ -1,5 +1,5 @@ class AuthD::Response - IPC::JSON.message Contacts, 12 do + IPC::JSON.message Contacts, 13 do property user : UInt32 property email : String? = nil def initialize(@user, @email) diff --git a/src/responses/email.cr b/src/responses/email.cr new file mode 100644 index 0000000..151c541 --- /dev/null +++ b/src/responses/email.cr @@ -0,0 +1,13 @@ +class AuthD::Response + IPC::JSON.message NewEmailTokenSent, 14 do + def initialize() + end + end + AuthD.responses << NewEmailTokenSent + + IPC::JSON.message NewEmailAddressValidated, 15 do + def initialize() + end + end + AuthD.responses << NewEmailAddressValidated +end