summaryrefslogtreecommitdiff
path: root/shrine/services/auth.go
blob: e1e3bc44e52ecd4b708b368751eaf460c44663aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package services

import (
	"shrine/enums"
	"shrine/messages"
	"shrine/models"
	"shrine/repositories"
	"shrine/types/account"
	"shrine/types/common"
	"shrine/types/hypertext"
	"shrine/utils/crypto"
)

func Register(request account.RegisterRequest, ip string) (*common.MessageResponse, *hypertext.ServiceError) {
	if repositories.IsIPBanned(ip) {
		return nil, fail(enums.Forbidden, messages.IPBanned)
	}

	citizen := models.User{
		Username:    request.Username,
		Email:       request.Email,
		DisplayName: request.DisplayName,
		IP:          ip,
	}

	if err := citizen.SetPassword(request.Password); err != nil {
		return nil, fail(enums.BadRequest, err.Error())
	}

	if err := repositories.CreateUser(&citizen); err != nil {
		return nil, mapRegistrationError(err)
	}

	if serviceErr := SendVerification(&citizen, enums.Activation); serviceErr != nil {
		return nil, serviceErr
	}

	return &common.MessageResponse{Message: messages.AccountCreated}, nil
}

func Authenticate(request account.LoginRequest, ip string) (*models.User, *hypertext.ServiceError) {
	citizen, err := repositories.FindUserByUsername(request.Username)
	if err != nil {
		return nil, fail(enums.Unauthorized, messages.InvalidUsernameOrPassword)
	}

	if !citizen.IsStaff() && repositories.IsIPBanned(ip) {
		return nil, fail(enums.Forbidden, messages.IPBanned)
	}

	if citizen.ClearExpiredDisable() {
		repositories.UpdateUser(citizen)
	}

	if !citizen.CanAuthenticate() {
		return nil, fail(enums.Forbidden, messages.AccountBannedOrDisabled)
	}

	if !citizen.CheckPassword(request.Password) {
		return nil, fail(enums.Unauthorized, messages.InvalidUsernameOrPassword)
	}

	if !citizen.IsVerified() {
		return nil, fail(enums.Forbidden, messages.EmailNotVerified)
	}

	citizen.IP = ip
	repositories.UpdateUser(citizen)

	return citizen, nil
}

func VerifyAccount(request account.VerifyRequest) (*common.MessageResponse, *hypertext.ServiceError) {
	if request.Token == "" {
		return nil, fail(enums.BadRequest, messages.VerificationTokenRequired)
	}

	verificationType := enums.VerificationType(request.Type)
	citizen, err := repositories.FindUserByVerification(crypto.HashToken(request.Token), verificationType)
	if err != nil {
		return nil, fail(enums.BadRequest, messages.VerificationLinkInvalid)
	}

	switch verificationType {
	case enums.Activation:
		citizen.VerifyEmail()
	default:
		return nil, fail(enums.BadRequest, messages.InvalidVerificationType)
	}

	if err := repositories.UpdateUser(citizen); err != nil {
		return nil, fail(enums.Internal, messages.FailedVerifyAccount)
	}

	return &common.MessageResponse{Message: messages.EmailVerified}, nil
}

func ResendActivation(request account.ResendActivationRequest) (*common.MessageResponse, *hypertext.ServiceError) {
	citizen, err := repositories.FindUserByEmail(request.Email)
	if err != nil {
		return nil, fail(enums.BadRequest, messages.NoAccountWithEmail)
	}

	if citizen.IsVerified() {
		return nil, fail(enums.BadRequest, messages.AccountAlreadyVerified)
	}

	if serviceErr := SendVerification(citizen, enums.Activation); serviceErr != nil {
		return nil, serviceErr
	}

	return &common.MessageResponse{Message: messages.VerificationEmailSent}, nil
}

func RevokeToken(tokenHash string) (*common.MessageResponse, *hypertext.ServiceError) {
	if err := repositories.DeleteToken(tokenHash); err != nil {
		return nil, fail(enums.Internal, messages.FailedEndSession)
	}
	return &common.MessageResponse{Message: messages.LoggedOut}, nil
}