/
auth_server.go
147 lines (120 loc) · 4.67 KB
/
auth_server.go
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package server
import (
"context"
"unicode/utf8"
"github.com/ArtyomArtamonov/msg/internal/model"
"github.com/ArtyomArtamonov/msg/internal/repository"
pb "github.com/ArtyomArtamonov/msg/internal/server/msg-proto"
"github.com/ArtyomArtamonov/msg/internal/service"
"github.com/ArtyomArtamonov/msg/internal/utils"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type AuthServer struct {
pb.UnimplementedAuthServiceServer
userStore repository.UserStore
refreshTokenStore repository.RefreshTokenStore
jwtManager service.JWTManagerProtol
}
func NewAuthServer(userStore repository.UserStore, refreshTokenStore repository.RefreshTokenStore, jwtManager service.JWTManagerProtol) *AuthServer {
return &AuthServer{
userStore: userStore,
jwtManager: jwtManager,
refreshTokenStore: refreshTokenStore,
}
}
func (s *AuthServer) Register(ctx context.Context, req *pb.RegisterRequest) (*pb.TokenResponse, error) {
if user, _ := s.userStore.FindByUsername(ctx, req.Username); user != nil {
return nil, status.Errorf(codes.AlreadyExists, "user already exists")
}
if utf8.RuneCountInString(req.Username) > 15 {
return nil, status.Error(codes.InvalidArgument, "username could not be more than 15 characters")
}
// TODO: add more password validation
if utf8.RuneCountInString(req.Password) < 6 {
return nil, status.Error(codes.InvalidArgument, "password could not be less than 6 characters")
}
user, err := model.NewUser(req.Username, req.Password, model.USER_ROLE)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
tokenPair, err := s.jwtManager.Generate(user)
if err != nil {
return nil, status.Error(codes.Internal, "could not generate token pair")
}
if err := s.userStore.Save(ctx, user); err != nil {
return nil, status.Errorf(codes.Internal, "could not save user: %v", err)
}
if err := s.refreshTokenStore.Add(ctx, tokenPair.RefreshToken); err != nil {
return nil, status.Errorf(codes.Internal, "could not save refresh token to database: %v", err)
}
response := pb.TokenResponse{
Token: &pb.Token{
AccessToken: tokenPair.JwtToken,
RefreshToken: tokenPair.RefreshToken.Token.String(),
},
}
return &response, nil
}
func (s *AuthServer) Login(ctx context.Context, req *pb.LoginRequest) (*pb.TokenResponse, error) {
user, err := s.userStore.FindByUsername(ctx, req.Username)
if err != nil {
return nil, status.Errorf(codes.NotFound, "incorrect username or password")
}
if user == nil || !user.IsCorrectPassword(req.Password) {
return nil, status.Error(codes.NotFound, "incorrect username or password")
}
tokenPair, err := s.jwtManager.Generate(user)
if err != nil {
return nil, status.Error(codes.Internal, "could not generate token pair")
}
if err := s.refreshTokenStore.Add(ctx, tokenPair.RefreshToken); err != nil {
return nil, status.Errorf(codes.Internal, "could not save refresh token to database: %v", err)
}
res := pb.TokenResponse{
Token: &pb.Token{
AccessToken: tokenPair.JwtToken,
RefreshToken: tokenPair.RefreshToken.Token.String(),
},
}
return &res, nil
}
func (s *AuthServer) Refresh(ctx context.Context, req *pb.RefreshRequest) (*pb.TokenResponse, error) {
refreshUUID, err := uuid.Parse(req.RefreshToken)
if err != nil {
return nil, status.Error(codes.InvalidArgument, "could not parse refresh token")
}
token, err := s.refreshTokenStore.Get(ctx, refreshUUID)
if err != nil {
return nil, status.Error(codes.Unauthenticated, "refresh token does not exists")
}
if token.ExpiresAt.Unix() < utils.Now().Unix() {
if err := s.refreshTokenStore.Delete(ctx, refreshUUID); err != nil {
logrus.Errorf("could not delete old refresh token: %v", err)
}
return nil, status.Error(codes.Unauthenticated, "refresh token is expired")
}
user, err := s.userStore.Find(ctx, token.UserId)
if err != nil {
logrus.Errorf("refresh token checks above should have failed, needs to be investigated: %v", err)
return nil, status.Error(codes.Internal, "hmm... this is strange. That could not possibly happen")
}
tokenPair, err := s.jwtManager.Generate(user)
if err != nil {
return nil, status.Error(codes.Internal, "could not generate token pair")
}
if err := s.refreshTokenStore.Delete(ctx, refreshUUID); err != nil {
return nil, status.Errorf(codes.Internal, "could not delete old refresh token: %v", err)
}
if err := s.refreshTokenStore.Add(ctx, tokenPair.RefreshToken); err != nil {
return nil, status.Errorf(codes.Internal, "could not save new refresh token: %v", err)
}
return &pb.TokenResponse{
Token: &pb.Token{
AccessToken: tokenPair.JwtToken,
RefreshToken: tokenPair.RefreshToken.Token.String(),
},
}, nil
}