168 lines
4.4 KiB
Go
168 lines
4.4 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"strconv"
|
|
|
|
"git.logidex.ru/fakz9/logidex-id/internal/api/auth/domain"
|
|
userDomain "git.logidex.ru/fakz9/logidex-id/internal/api/user/domain"
|
|
"git.logidex.ru/fakz9/logidex-id/internal/phoneutil"
|
|
hydraApi "github.com/ory/hydra-client-go"
|
|
)
|
|
|
|
type AuthService interface {
|
|
OtpRequest(ctx context.Context, phoneNumber string) error
|
|
OtpVerify(ctx context.Context, phoneNumber, code string, loggingChallenge string) (string, error)
|
|
AcceptConsent(ctx context.Context, phoneNumber string, challenge string) (string, error)
|
|
}
|
|
|
|
type authService struct {
|
|
repo domain.AuthRepository
|
|
userRepo userDomain.UserRepository
|
|
hydraClient *hydraApi.APIClient
|
|
}
|
|
|
|
func (a authService) AcceptConsent(ctx context.Context, phoneNumber string, challenge string) (string, error) {
|
|
phoneNumber, err := phoneutil.ParseAndFormatPhoneNumber(phoneNumber)
|
|
if err != nil {
|
|
return "", domain.ErrInvalidPhoneNumber{
|
|
PhoneNumber: phoneNumber,
|
|
Err: err,
|
|
}
|
|
}
|
|
user, err := a.userRepo.GetUserByPhoneNumber(ctx, phoneNumber)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if user == nil {
|
|
return "", domain.ErrUserNotFound{PhoneNumber: phoneNumber}
|
|
}
|
|
request := hydraApi.AcceptConsentRequest{}
|
|
request.SetGrantScope([]string{"openid"})
|
|
request.SetRemember(true)
|
|
request.SetRememberFor(3600)
|
|
|
|
rsp, rawRsp, err := a.hydraClient.AdminApi.
|
|
AcceptConsentRequest(ctx).
|
|
ConsentChallenge(challenge).
|
|
AcceptConsentRequest(request).
|
|
Execute()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if rawRsp.StatusCode != 200 {
|
|
return "", domain.ErrInvalidHydraAccept{
|
|
Message: "Hydra response is nil: " + strconv.Itoa(rawRsp.StatusCode),
|
|
Uuid: "",
|
|
}
|
|
}
|
|
redirectTo, ok := rsp.GetRedirectToOk()
|
|
if !ok || redirectTo == nil {
|
|
return "", domain.ErrInvalidHydraAccept{
|
|
Message: "Hydra redirectTo is nil",
|
|
Uuid: "",
|
|
}
|
|
}
|
|
// TODO: Verify user in the database
|
|
_, err = a.userRepo.VerifyUser(ctx, user.Uuid.String())
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return *redirectTo, nil
|
|
}
|
|
|
|
func (a authService) OtpRequest(ctx context.Context, phoneNumber string) error {
|
|
phoneNumber, err := phoneutil.ParseAndFormatPhoneNumber(phoneNumber)
|
|
if err != nil {
|
|
return domain.ErrInvalidPhoneNumber{
|
|
PhoneNumber: phoneNumber,
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
user, err := a.userRepo.GetUserByPhoneNumber(ctx, phoneNumber)
|
|
//if err != nil {
|
|
// return err
|
|
//}
|
|
|
|
if user == nil {
|
|
// Create a new user if it does not exist
|
|
user, err = a.userRepo.CreateUser(ctx, phoneNumber)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
code := "123456"
|
|
err = a.repo.SaveOtpRequest(ctx, user.Uuid.String(), code)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// TODO implement sending OTP code via SMS
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a authService) OtpVerify(ctx context.Context, phoneNumber string, code string, loggingChallenge string) (string, error) {
|
|
phoneNumber, err := phoneutil.ParseAndFormatPhoneNumber(phoneNumber)
|
|
if err != nil {
|
|
return "", domain.ErrInvalidPhoneNumber{
|
|
PhoneNumber: phoneNumber,
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
user, err := a.userRepo.GetUserByPhoneNumber(ctx, phoneNumber)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if user == nil {
|
|
return "", domain.ErrUserNotFound{PhoneNumber: phoneNumber}
|
|
}
|
|
otp, err := a.repo.GetOtpRequest(ctx, user.Uuid.String())
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if otp == nil {
|
|
return "", domain.ErrOtpNotFound{Uuid: user.Uuid.String()}
|
|
}
|
|
if *otp != code {
|
|
return "", domain.ErrOtpInvalid{Uuid: user.Uuid.String(), Code: code}
|
|
}
|
|
request := hydraApi.AcceptLoginRequest{}
|
|
request.SetSubject(user.Uuid.String())
|
|
request.SetRemember(true)
|
|
request.SetRememberFor(3600) // 1 hour
|
|
|
|
rsp, rawRsp, err := a.hydraClient.AdminApi.
|
|
AcceptLoginRequest(ctx).
|
|
LoginChallenge(loggingChallenge).
|
|
AcceptLoginRequest(request).
|
|
Execute()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if rawRsp.StatusCode != 200 {
|
|
return "", domain.ErrInvalidHydraAccept{
|
|
Message: "Hydra response is nil: " + strconv.Itoa(rawRsp.StatusCode),
|
|
Uuid: user.Uuid.String(),
|
|
}
|
|
}
|
|
|
|
redirectTo, ok := rsp.GetRedirectToOk()
|
|
if !ok || redirectTo == nil {
|
|
return "", domain.ErrInvalidHydraAccept{
|
|
Message: "Hydra redirectTo is nil",
|
|
Uuid: user.Uuid.String(),
|
|
}
|
|
}
|
|
return *redirectTo, nil
|
|
}
|
|
|
|
func NewAuthService(repo domain.AuthRepository, userRepo userDomain.UserRepository, hydraClient *hydraApi.APIClient) AuthService {
|
|
return &authService{
|
|
repo: repo,
|
|
userRepo: userRepo,
|
|
hydraClient: hydraClient,
|
|
}
|
|
}
|