256 lines
6.1 KiB
Go
256 lines
6.1 KiB
Go
package grpc
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"git.sch9.ru/new_gate/ms-auth/internal/models"
|
|
"git.sch9.ru/new_gate/ms-auth/internal/users"
|
|
"git.sch9.ru/new_gate/ms-auth/pkg"
|
|
userv1 "git.sch9.ru/new_gate/ms-auth/proto/user/v1"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/metadata"
|
|
"google.golang.org/protobuf/types/known/emptypb"
|
|
"google.golang.org/protobuf/types/known/timestamppb"
|
|
"strings"
|
|
)
|
|
|
|
type UserHandlers struct {
|
|
userv1.UnimplementedUserServiceServer
|
|
userUC users.UseCase
|
|
}
|
|
|
|
func NewUserHandlers(gserver *grpc.Server, userUC users.UseCase) {
|
|
handlers := &UserHandlers{
|
|
userUC: userUC,
|
|
}
|
|
|
|
userv1.RegisterUserServiceServer(gserver, handlers)
|
|
}
|
|
|
|
const (
|
|
SessionHeaderName = "x-session-id"
|
|
AuthUserHeaderName = "x-auth-user-id"
|
|
)
|
|
|
|
func (h *UserHandlers) Login(ctx context.Context, req *userv1.LoginRequest) (*emptypb.Empty, error) {
|
|
const op = "UserHandlers.Login"
|
|
|
|
var (
|
|
err error
|
|
user *models.User
|
|
)
|
|
|
|
username := req.GetUsername()
|
|
password := req.GetPassword()
|
|
|
|
user, err = h.userUC.ReadUserByUsername(ctx, username)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(err)
|
|
}
|
|
|
|
err = user.ComparePassword(password)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(pkg.Wrap(pkg.ErrNotFound, err, op, "bad username or password"))
|
|
}
|
|
|
|
sessionId, err := h.userUC.CreateSession(ctx, user.Id, user.Role)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(err)
|
|
}
|
|
|
|
header := metadata.New(map[string]string{
|
|
SessionHeaderName: sessionId,
|
|
})
|
|
err = grpc.SendHeader(ctx, header)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &emptypb.Empty{}, nil
|
|
}
|
|
|
|
func AuthSessionIdFromContext(ctx context.Context) (string, error) {
|
|
md, ok := metadata.FromIncomingContext(ctx)
|
|
|
|
if !ok {
|
|
return "", errors.New("failed to get metadata")
|
|
}
|
|
tokens := md.Get(SessionHeaderName)
|
|
sessionId := strings.Join(tokens, "")
|
|
if len(sessionId) == 0 {
|
|
return "", errors.New("no session id in context")
|
|
}
|
|
return sessionId, nil
|
|
}
|
|
|
|
func (h *UserHandlers) Refresh(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) {
|
|
const op = "UserHandlers.Refresh"
|
|
|
|
sessionId, err := AuthSessionIdFromContext(ctx)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(pkg.Wrap(err, pkg.ErrUnauthenticated, op, "no session id in context"))
|
|
}
|
|
err = h.userUC.UpdateSession(ctx, sessionId)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(err)
|
|
}
|
|
return &emptypb.Empty{}, nil
|
|
}
|
|
|
|
func (h *UserHandlers) Logout(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) {
|
|
const op = "UserHandlers.Logout"
|
|
|
|
sessionId, err := AuthSessionIdFromContext(ctx)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(pkg.Wrap(err, pkg.ErrUnauthenticated, op, "no session id in context"))
|
|
}
|
|
err = h.userUC.DeleteSession(ctx, sessionId)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(err)
|
|
}
|
|
return &emptypb.Empty{}, nil
|
|
}
|
|
|
|
func (h *UserHandlers) CompleteLogout(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) {
|
|
const op = "UserHandlers.CompleteLogout"
|
|
|
|
sessionId, err := AuthSessionIdFromContext(ctx)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(pkg.Wrap(err, pkg.ErrUnauthenticated, op, "no session id in context"))
|
|
}
|
|
|
|
session, err := h.userUC.ReadSession(ctx, sessionId)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(err)
|
|
}
|
|
|
|
err = h.userUC.DeleteAllSessions(ctx, session.UserId)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(err)
|
|
}
|
|
return &emptypb.Empty{}, nil
|
|
}
|
|
|
|
func (h *UserHandlers) Verify(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) {
|
|
const op = "UserHandlers.Verify"
|
|
|
|
sessionId, err := AuthSessionIdFromContext(ctx)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(pkg.Wrap(err, pkg.ErrUnauthenticated, op, "no session id in context"))
|
|
}
|
|
token, err := h.userUC.Verify(ctx, sessionId)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(err)
|
|
}
|
|
|
|
header := metadata.New(map[string]string{
|
|
AuthUserHeaderName: token,
|
|
})
|
|
err = grpc.SendHeader(ctx, header)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &emptypb.Empty{}, nil
|
|
}
|
|
|
|
func (h *UserHandlers) CreateUser(ctx context.Context, req *userv1.CreateUserRequest) (*userv1.CreateUserResponse, error) {
|
|
const op = "UserHandlers.CreateUser"
|
|
|
|
sessionId, err := AuthSessionIdFromContext(ctx)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(pkg.Wrap(err, pkg.ErrUnauthenticated, op, "no session id in context"))
|
|
}
|
|
|
|
ctx = context.WithValue(ctx, "userId", sessionId)
|
|
|
|
id, err := h.userUC.CreateUser(
|
|
ctx,
|
|
req.GetUsername(),
|
|
req.GetPassword(),
|
|
models.RoleParticipant,
|
|
)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(err)
|
|
}
|
|
|
|
return &userv1.CreateUserResponse{
|
|
Id: id,
|
|
}, nil
|
|
}
|
|
|
|
func (h *UserHandlers) GetUser(ctx context.Context, req *userv1.GetUserRequest) (*userv1.GetUserResponse, error) {
|
|
user, err := h.userUC.ReadUserById(
|
|
ctx,
|
|
req.GetId(),
|
|
)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(err)
|
|
}
|
|
|
|
return &userv1.GetUserResponse{
|
|
User: &userv1.User{
|
|
Id: user.Id,
|
|
Username: user.Username,
|
|
CreatedAt: timestamppb.New(user.CreatedAt),
|
|
ModifiedAt: timestamppb.New(user.ModifiedAt),
|
|
Role: userv1.Role(user.Role),
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (h *UserHandlers) UpdateUser(ctx context.Context, req *userv1.UpdateUserRequest) (*emptypb.Empty, error) {
|
|
const op = "UserHandlers.UpdateUser"
|
|
|
|
sessionId, err := AuthSessionIdFromContext(ctx)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(pkg.Wrap(err, pkg.ErrUnauthenticated, op, "no session id in context"))
|
|
}
|
|
|
|
ctx = context.WithValue(ctx, "userId", sessionId)
|
|
|
|
err = h.userUC.UpdateUser(
|
|
ctx,
|
|
req.GetId(),
|
|
AsStringP(req.Username),
|
|
AsMRoleP(req.Role),
|
|
)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(err)
|
|
}
|
|
return &emptypb.Empty{}, nil
|
|
}
|
|
|
|
func (h *UserHandlers) DeleteUser(ctx context.Context, req *userv1.DeleteUserRequest) (*emptypb.Empty, error) {
|
|
const op = "UserHandlers.DeleteUser"
|
|
|
|
sessionId, err := AuthSessionIdFromContext(ctx)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(pkg.Wrap(err, pkg.ErrUnauthenticated, op, "no session id in context"))
|
|
}
|
|
|
|
ctx = context.WithValue(ctx, "userId", sessionId)
|
|
|
|
err = h.userUC.DeleteUser(
|
|
ctx,
|
|
req.GetId(),
|
|
)
|
|
if err != nil {
|
|
return nil, pkg.ToGRPC(err)
|
|
}
|
|
return &emptypb.Empty{}, nil
|
|
}
|
|
|
|
func AsMRoleP(v userv1.Role) *models.Role {
|
|
vv := models.Role(v.Number())
|
|
return &vv
|
|
}
|
|
|
|
func AsRoleP(v models.Role) *models.Role {
|
|
return &v
|
|
}
|
|
|
|
func AsStringP(str string) *string {
|
|
return &str
|
|
}
|