Restructure the projec and start adding projects
Signed-off-by: Nikolai Rodionov <iam@allanger.xyz>
This commit is contained in:
89
internal/api/v1/accounts.go
Normal file
89
internal/api/v1/accounts.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"gitea.badhouseplants.net/softplayer/softplayer-backend/internal/services"
|
||||
accounts "gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/accounts/v1"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
func NewAccountServer(
|
||||
accountsCtrl *services.AccountController,
|
||||
authorizationCtrl *services.AuthController,
|
||||
) *AccountsServer {
|
||||
return &AccountsServer{
|
||||
accountsCtrl: accountsCtrl,
|
||||
authorizationCtrl: authorizationCtrl,
|
||||
}
|
||||
}
|
||||
|
||||
//var _ accounts.AccountsServiceServer = (*AccountsServer)(nil)
|
||||
|
||||
type AccountsServer struct {
|
||||
accounts.UnimplementedAccountsServiceServer
|
||||
accountsCtrl *services.AccountController
|
||||
authorizationCtrl *services.AuthController
|
||||
}
|
||||
|
||||
func (srv *AccountsServer) RefreshToken(ctx context.Context, in *empty.Empty) (*empty.Empty, error) {
|
||||
claims, err := services.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Context is invalid")
|
||||
}
|
||||
|
||||
if claims.TokenType != services.TokenTypeRefresh {
|
||||
return nil, status.Error(codes.Unauthenticated, "Invalid token")
|
||||
}
|
||||
|
||||
session, err := srv.authorizationCtrl.GetSession(ctx, claims.TokenID)
|
||||
if err != nil {
|
||||
if errors.Is(err, services.ErrSessionNotFound) {
|
||||
return nil, status.Error(codes.Unauthenticated, "Session doesn't exists")
|
||||
}
|
||||
return nil, status.Error(codes.Internal, "Somethings is broken on our side")
|
||||
}
|
||||
|
||||
if session.UserID != claims.UserID {
|
||||
return nil, status.Error(codes.Unauthenticated, "Invalid session")
|
||||
}
|
||||
|
||||
accessToken, _, err := srv.authorizationCtrl.GenerateToken(&services.JWTData{
|
||||
UserID: claims.UserID,
|
||||
TokenType: services.TokenTypeAccess,
|
||||
TokenAud: services.TokenAudWeb,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Couldn't generate an access token")
|
||||
}
|
||||
|
||||
refreshToken, tokenID, err := srv.authorizationCtrl.GenerateToken(&services.JWTData{
|
||||
UserID: claims.UserID,
|
||||
TokenType: services.TokenTypeRefresh,
|
||||
TokenAud: services.TokenAudWeb,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Couldn't generate an access token")
|
||||
}
|
||||
newSession := &services.Session{UserID: session.UserID}
|
||||
|
||||
if err := srv.authorizationCtrl.SaveSession(ctx, tokenID, newSession); err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Couldn't store session")
|
||||
}
|
||||
|
||||
header := metadata.New(map[string]string{
|
||||
"X-Access-Token": accessToken,
|
||||
"X-Refresh-Token": refreshToken,
|
||||
})
|
||||
if err := grpc.SetHeader(ctx, header); err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Couldn't set metadata")
|
||||
}
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
38
internal/api/v1/projects.go
Normal file
38
internal/api/v1/projects.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
projects "gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/projects/v1"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func NewProjectsServer() *ProjectsServer {
|
||||
return &ProjectsServer{}
|
||||
}
|
||||
|
||||
// var _ projects.ProjectsServiceServer = (*ProjectsServer)(nil)
|
||||
|
||||
type ProjectsServer struct {
|
||||
projects.UnimplementedProjectsServiceServer
|
||||
}
|
||||
|
||||
// CreateProject implements [v1.ProjectsServiceServer].
|
||||
func (p *ProjectsServer) CreateProject(context.Context, *projects.CreateProjectRequest) (*projects.CreateProjectResponse, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// GetProject implements [v1.ProjectsServiceServer].
|
||||
func (p *ProjectsServer) GetProject(context.Context, *projects.GetProjectRequest) (*projects.GetProjectResponse, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// ListProjects implements [v1.ProjectsServiceServer].
|
||||
func (p *ProjectsServer) ListProjects(*projects.ListProjectsRequest, grpc.ServerStreamingServer[projects.ListProjectsResponse]) error {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// UpdateProject implements [v1.ProjectsServiceServer].
|
||||
func (p *ProjectsServer) UpdateProject(context.Context, *projects.UpdateProjectRequest) (*projects.UpdateProjectResponse, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
107
internal/api/v1/public_accounts.go
Normal file
107
internal/api/v1/public_accounts.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitea.badhouseplants.net/softplayer/softplayer-backend/internal/services"
|
||||
accounts "gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/accounts/v1"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func NewPublicAccountServer(
|
||||
accountsCtrl *services.AccountController,
|
||||
authorizationCtrl *services.AuthController,
|
||||
) *PublicAccountService {
|
||||
return &PublicAccountService{
|
||||
accountsCtrl: accountsCtrl,
|
||||
authorizationCtrl: authorizationCtrl,
|
||||
}
|
||||
}
|
||||
|
||||
type PublicAccountService struct {
|
||||
accounts.UnimplementedPublicAccountsServiceServer
|
||||
accountsCtrl *services.AccountController
|
||||
authorizationCtrl *services.AuthController
|
||||
}
|
||||
|
||||
func (a *PublicAccountService) SignIn(ctx context.Context, in *accounts.SignInRequest) (*accounts.SignInResponse, error) {
|
||||
id, err := a.accountsCtrl.Login(ctx, in.GetEmail(), in.GetPassword())
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Couldn't create a user")
|
||||
}
|
||||
accessToken, _, err := a.authorizationCtrl.GenerateToken(&services.JWTData{
|
||||
UserID: id,
|
||||
TokenType: services.TokenTypeAccess,
|
||||
TokenAud: services.TokenAudWeb,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Couldn't generate an access token")
|
||||
}
|
||||
|
||||
refreshToken, tokenID, err := a.authorizationCtrl.GenerateToken(&services.JWTData{
|
||||
UserID: id,
|
||||
TokenType: services.TokenTypeRefresh,
|
||||
TokenAud: services.TokenAudWeb,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Couldn't generate an access token")
|
||||
}
|
||||
|
||||
session := &services.Session{UserID: id}
|
||||
|
||||
if err := a.authorizationCtrl.SaveSession(ctx, tokenID, session); err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Couldn't store session")
|
||||
}
|
||||
return &accounts.SignInResponse{
|
||||
TokenPair: &accounts.TokenPair{
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Create a new account in Softplayer
|
||||
func (a *PublicAccountService) SignUp(ctx context.Context, in *accounts.SignUpRequest) (*accounts.SignUpResponse, error) {
|
||||
data := &services.AccountData{
|
||||
Password: in.GetPassword(),
|
||||
Email: in.GetEmail(),
|
||||
Name: in.PersonalData.GetName(),
|
||||
Surname: in.PersonalData.GetSurname(),
|
||||
}
|
||||
id, err := a.accountsCtrl.Create(ctx, data)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Couldn't create a user")
|
||||
}
|
||||
|
||||
accessToken, _, err := a.authorizationCtrl.GenerateToken(&services.JWTData{
|
||||
UserID: id,
|
||||
TokenType: services.TokenTypeAccess,
|
||||
TokenAud: services.TokenAudWeb,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Couldn't generate an access token")
|
||||
}
|
||||
|
||||
refreshToken, tokenID, err := a.authorizationCtrl.GenerateToken(&services.JWTData{
|
||||
UserID: id,
|
||||
TokenType: services.TokenTypeRefresh,
|
||||
TokenAud: services.TokenAudWeb,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Couldn't generate an access token")
|
||||
}
|
||||
|
||||
session := &services.Session{UserID: id}
|
||||
|
||||
if err := a.authorizationCtrl.SaveSession(ctx, tokenID, session); err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Couldn't store session")
|
||||
}
|
||||
|
||||
return &accounts.SignUpResponse{
|
||||
TokenPair: &accounts.TokenPair{
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
64
internal/api/v1/public_tokens.go
Normal file
64
internal/api/v1/public_tokens.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"gitea.badhouseplants.net/softplayer/softplayer-backend/internal/services"
|
||||
tokens "gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/tokens/v1"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
// var _ tokens.PublicTokensServiceServer = (*PublicTokensServer)(nil)
|
||||
|
||||
type PublicTokensServer struct {
|
||||
tokens.UnimplementedPublicTokensServiceServer
|
||||
tokenCtrl *services.TokenController
|
||||
authorizationCtrl *services.AuthController
|
||||
}
|
||||
|
||||
func NewPublicTokensServer(
|
||||
tokenCtrl *services.TokenController,
|
||||
authorizationCtrl *services.AuthController,
|
||||
) *PublicTokensServer {
|
||||
return &PublicTokensServer{
|
||||
tokenCtrl: tokenCtrl,
|
||||
authorizationCtrl: authorizationCtrl,
|
||||
}
|
||||
}
|
||||
|
||||
func (srv *PublicTokensServer) AuthenticateWithToken(ctx context.Context, in *tokens.AuthenticateWithTokenRequest) (*emptypb.Empty, error) {
|
||||
tokenAuthRes, err := srv.tokenCtrl.AuthenticateWithToken(ctx, in.TokenValue.Token)
|
||||
if err != nil {
|
||||
if errors.Is(err, services.ErrBadToken) {
|
||||
return nil, status.Error(codes.Unauthenticated, "Token is not valid")
|
||||
}
|
||||
if errors.Is(err, services.ErrServerError) {
|
||||
return nil, status.Error(codes.Internal, "Something is broken on our side")
|
||||
}
|
||||
return nil, status.Error(codes.Aborted, "Couldn't authorize")
|
||||
}
|
||||
|
||||
jwtData := &services.JWTData{
|
||||
UserID: tokenAuthRes.UserID,
|
||||
TokenType: services.TokenTypeAccess,
|
||||
TokenAud: services.TokenAudToken,
|
||||
Scope: tokenAuthRes.Scope,
|
||||
}
|
||||
accessToken, _, err := srv.authorizationCtrl.GenerateToken(jwtData)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Couldn't generate an access token")
|
||||
}
|
||||
|
||||
header := metadata.New(map[string]string{
|
||||
"X-Access-Token": accessToken,
|
||||
})
|
||||
if err := grpc.SetHeader(ctx, header); err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Couldn't set metadata")
|
||||
}
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
78
internal/api/v1/refresh_session.go
Normal file
78
internal/api/v1/refresh_session.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"gitea.badhouseplants.net/softplayer/softplayer-backend/internal/controllers"
|
||||
accounts "gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/accounts/v1"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func NewRefreshSessionServer(
|
||||
authorizationCtrl *controllers.AuthController,
|
||||
) *RefreshSessionService {
|
||||
return &RefreshSessionService{
|
||||
authorizationCtrl: authorizationCtrl,
|
||||
}
|
||||
}
|
||||
|
||||
type RefreshSessionService struct {
|
||||
accounts.UnimplementedRefreshSessionServiceServer
|
||||
authorizationCtrl *controllers.AuthController
|
||||
}
|
||||
|
||||
func (srv *RefreshSessionService) RefreshSession(ctx context.Context, in *accounts.RefreshSessionRequest) (*accounts.RefreshSessionResponse, error) {
|
||||
fmt.Println(in.GetRefreshToken())
|
||||
claims, err := srv.authorizationCtrl.ParseToken(in.GetRefreshToken())
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, status.Error(codes.Aborted, "Invalid token is sent")
|
||||
}
|
||||
|
||||
if claims.TokenType != controllers.TokenTypeRefresh {
|
||||
return nil, status.Error(codes.Unauthenticated, "Invalid token")
|
||||
}
|
||||
|
||||
session, err := srv.authorizationCtrl.GetSession(ctx, claims.TokenID)
|
||||
if err != nil {
|
||||
if errors.Is(err, controllers.ErrSessionNotFound) {
|
||||
return nil, status.Error(codes.Unauthenticated, "Session doesn't exists")
|
||||
}
|
||||
return nil, status.Error(codes.Internal, "Somethings is broken on our side")
|
||||
}
|
||||
|
||||
if session.UserID != claims.UserID {
|
||||
return nil, status.Error(codes.Unauthenticated, "Invalid session")
|
||||
}
|
||||
|
||||
accessToken, _, err := srv.authorizationCtrl.GenerateToken(&controllers.JWTData{
|
||||
UserID: claims.UserID,
|
||||
TokenType: controllers.TokenTypeAccess,
|
||||
TokenAud: controllers.TokenAudWeb,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Couldn't generate an access token")
|
||||
}
|
||||
|
||||
refreshToken, tokenID, err := srv.authorizationCtrl.GenerateToken(&controllers.JWTData{
|
||||
UserID: claims.UserID,
|
||||
TokenType: controllers.TokenTypeRefresh,
|
||||
TokenAud: controllers.TokenAudWeb,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Couldn't generate an access token")
|
||||
}
|
||||
newSession := &controllers.Session{UserID: session.UserID}
|
||||
|
||||
if err := srv.authorizationCtrl.SaveSession(ctx, tokenID, newSession); err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Couldn't store session")
|
||||
}
|
||||
|
||||
return &accounts.RefreshSessionResponse{TokenPair: &accounts.TokenPair{
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
}}, nil
|
||||
}
|
||||
51
internal/api/v1/test.go
Normal file
51
internal/api/v1/test.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
test "gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/test/v1"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
func NewTestServer() *TestServer {
|
||||
return &TestServer{}
|
||||
}
|
||||
|
||||
type TestServer struct {
|
||||
test.UnimplementedTestServiceServer
|
||||
}
|
||||
|
||||
func (t *TestServer) Pong(ctx context.Context, in *test.PongRequest) (*test.PongResponse, error) {
|
||||
return &test.PongResponse{}, nil
|
||||
}
|
||||
|
||||
func (t *TestServer) PongStream(in *emptypb.Empty, stream grpc.ServerStreamingServer[test.PongStreamResponse]) error {
|
||||
for i := 0; i < 10; i++ {
|
||||
if err := stream.Send(&test.PongStreamResponse{Dummy: "test"}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewPublicTestServer() *PublicTestServer {
|
||||
return &PublicTestServer{}
|
||||
}
|
||||
|
||||
type PublicTestServer struct {
|
||||
test.UnimplementedPublicTestServiceServer
|
||||
}
|
||||
|
||||
func (t *PublicTestServer) Ping(ctx context.Context, in *test.PingRequest) (*test.PingResponse, error) {
|
||||
return &test.PingResponse{}, nil
|
||||
}
|
||||
|
||||
func (t *PublicTestServer) PingStream(in *emptypb.Empty, stream grpc.ServerStreamingServer[test.PingStreamResponse]) error {
|
||||
for i := 0; i < 10; i++ {
|
||||
if err := stream.Send(&test.PingStreamResponse{Dummy: "test"}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
267
internal/api/v1/tokens.go
Normal file
267
internal/api/v1/tokens.go
Normal file
@@ -0,0 +1,267 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"gitea.badhouseplants.net/softplayer/softplayer-backend/internal/services"
|
||||
tokens "gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/tokens/v1"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
// var _ tokens.TokensServiceServer = (*TokensServer)(nil)
|
||||
|
||||
// TokensServer implements the Token Service
|
||||
type TokensServer struct {
|
||||
tokens.UnimplementedTokensServiceServer
|
||||
tokenCtrl *services.TokenController
|
||||
authorizationCtrl *services.AuthController
|
||||
}
|
||||
|
||||
func NewTokensServer(
|
||||
tokenCtrl *services.TokenController,
|
||||
authorizationCtrl *services.AuthController,
|
||||
) *TokensServer {
|
||||
return &TokensServer{
|
||||
tokenCtrl: tokenCtrl,
|
||||
authorizationCtrl: authorizationCtrl,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateToken implements [v1.TokensServiceServer].
|
||||
func (srv *TokensServer) CreateToken(ctx context.Context, in *tokens.CreateTokenRequest) (*tokens.CreateTokenResponse, error) {
|
||||
claims, err := services.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Context is invalid")
|
||||
}
|
||||
if claims.UserID == "" {
|
||||
return nil, status.Error(codes.Aborted, "Context is invalid")
|
||||
}
|
||||
|
||||
if in.TokenPermissions == nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "Permissions must be set")
|
||||
}
|
||||
permissions := map[string][]string{}
|
||||
for service, methods := range in.TokenPermissions.Permissions {
|
||||
permissions[service] = methods.GetMethods()
|
||||
}
|
||||
|
||||
tokenData := &services.TokenData{
|
||||
Name: in.TokenMetadata.GetName(),
|
||||
UserID: claims.UserID,
|
||||
ExpiresAt: in.TokenMetadata.ExpiresAt.AsTime(),
|
||||
Scopes: permissions,
|
||||
}
|
||||
|
||||
token, tokenID, err := srv.tokenCtrl.Create(ctx, tokenData)
|
||||
if err != nil {
|
||||
if errors.Is(err, services.ErrServerError) {
|
||||
return nil, status.Error(codes.Internal, "Something is broken on our side")
|
||||
}
|
||||
return nil, status.Error(codes.Aborted, "Couldn't create a token")
|
||||
}
|
||||
|
||||
return &tokens.CreateTokenResponse{
|
||||
TokenUuid: &tokens.TokenUUID{
|
||||
Uuid: tokenID,
|
||||
},
|
||||
TokenValue: &tokens.TokenValue{Token: token},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ForceTokenExpiration implements [v1.TokensServiceServer].
|
||||
func (srv *TokensServer) ForceTokenExpiration(ctx context.Context, in *tokens.ForceTokenExpirationRequest) (*emptypb.Empty, error) {
|
||||
claims, err := services.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Context is invalid")
|
||||
}
|
||||
if claims.UserID == "" {
|
||||
return nil, status.Error(codes.Aborted, "Context is invalid")
|
||||
}
|
||||
|
||||
if err := srv.tokenCtrl.VerifyTokenOwner(ctx, claims.UserID, in.TokenUuid.Uuid); err != nil {
|
||||
if errors.Is(err, services.ErrServerError) {
|
||||
return nil, status.Error(codes.Internal, "Something is broken on our side")
|
||||
}
|
||||
return nil, status.Error(codes.Aborted, "User is now allowed to manipulate this token")
|
||||
}
|
||||
|
||||
if err := srv.tokenCtrl.ForceExpiration(ctx, in.TokenUuid.GetUuid()); err != nil {
|
||||
if errors.Is(err, services.ErrServerError) {
|
||||
return nil, status.Error(codes.Internal, "Something is broken on our side")
|
||||
}
|
||||
return nil, status.Error(codes.Aborted, "Couldn't create a token")
|
||||
}
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
// GetToken implements [v1.TokensServiceServer].
|
||||
func (srv *TokensServer) GetToken(ctx context.Context, in *tokens.GetTokenRequest) (*tokens.GetTokenResponse, error) {
|
||||
claims, err := services.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Context is invalid")
|
||||
}
|
||||
if claims.UserID == "" {
|
||||
return nil, status.Error(codes.Aborted, "Context is invalid")
|
||||
}
|
||||
if err := srv.tokenCtrl.VerifyTokenOwner(ctx, claims.UserID, in.TokenUuid.Uuid); err != nil {
|
||||
if errors.Is(err, services.ErrServerError) {
|
||||
return nil, status.Error(codes.Internal, "Something is broken on our side")
|
||||
}
|
||||
return nil, status.Error(codes.Aborted, "User is now allowed to manipulate this token")
|
||||
}
|
||||
|
||||
token, err := srv.tokenCtrl.Get(ctx, in.TokenUuid.Uuid, claims.UserID)
|
||||
if err != nil {
|
||||
if errors.Is(err, services.ErrServerError) {
|
||||
return nil, status.Error(codes.Internal, "Something is broken on our side")
|
||||
}
|
||||
return nil, status.Error(codes.Aborted, "Couldn't list tokens")
|
||||
}
|
||||
|
||||
return &tokens.GetTokenResponse{
|
||||
TokenUuid: &tokens.TokenUUID{
|
||||
Uuid: token.UUID,
|
||||
},
|
||||
TokenMetadata: &tokens.TokenMetadata{
|
||||
Name: token.Name,
|
||||
ExpiresAt: timestamppb.New(token.ExpiresAt),
|
||||
LastUsedAt: timestamppb.New(token.LastUsedAt),
|
||||
GeneratedAt: timestamppb.New(token.GeneratedAt),
|
||||
CreatedAt: timestamppb.New(token.CreatedAt),
|
||||
RevokedAt: timestamppb.New(token.RevokedAt),
|
||||
},
|
||||
TokenPermissions: &tokens.TokenPermissions{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ListTokens implements [v1.TokensServiceServer].
|
||||
func (srv *TokensServer) ListTokens(in *emptypb.Empty, stream grpc.ServerStreamingServer[tokens.ListTokensResponse]) error {
|
||||
claims, err := services.ClaimsFromContext(stream.Context())
|
||||
if err != nil {
|
||||
return status.Error(codes.Aborted, "Context is invalid")
|
||||
}
|
||||
if claims.UserID == "" {
|
||||
return status.Error(codes.Aborted, "Context is invalid")
|
||||
}
|
||||
|
||||
tokensRes, err := srv.tokenCtrl.List(stream.Context(), claims.UserID)
|
||||
if err != nil {
|
||||
if errors.Is(err, services.ErrServerError) {
|
||||
return status.Error(codes.Internal, "Something is broken on our side")
|
||||
}
|
||||
return status.Error(codes.Aborted, "Couldn't list tokens")
|
||||
}
|
||||
|
||||
for _, tokenRes := range tokensRes {
|
||||
if err := stream.Send(&tokens.ListTokensResponse{
|
||||
TokenUuid: &tokens.TokenUUID{
|
||||
Uuid: tokenRes.UUID,
|
||||
},
|
||||
TokenMetadata: &tokens.TokenMetadata{
|
||||
Name: tokenRes.Name,
|
||||
ExpiresAt: timestamppb.New(tokenRes.ExpiresAt),
|
||||
LastUsedAt: timestamppb.New(tokenRes.LastUsedAt),
|
||||
GeneratedAt: timestamppb.New(tokenRes.GeneratedAt),
|
||||
CreatedAt: timestamppb.New(tokenRes.CreatedAt),
|
||||
RevokedAt: timestamppb.New(tokenRes.RevokedAt),
|
||||
},
|
||||
}); err != nil {
|
||||
return status.Error(codes.Aborted, "Couldn't send data")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegenerateToken implements [v1.TokensServiceServer].
|
||||
func (srv *TokensServer) RegenerateToken(ctx context.Context, in *tokens.RegenerateTokenRequest) (*tokens.RegenerateTokenResponse, error) {
|
||||
claims, err := services.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Context is invalid")
|
||||
}
|
||||
if claims.UserID == "" {
|
||||
return nil, status.Error(codes.Aborted, "Context is invalid")
|
||||
}
|
||||
if err := srv.tokenCtrl.VerifyTokenOwner(ctx, claims.UserID, in.TokenUuid.Uuid); err != nil {
|
||||
if errors.Is(err, services.ErrServerError) {
|
||||
return nil, status.Error(codes.Internal, "Something is broken on our side")
|
||||
}
|
||||
return nil, status.Error(codes.Aborted, "User is now allowed to manipulate this token")
|
||||
}
|
||||
|
||||
tokenVal, err := srv.tokenCtrl.Regenerate(ctx, in.TokenUuid.GetUuid())
|
||||
if err != nil {
|
||||
if errors.Is(err, services.ErrServerError) {
|
||||
return nil, status.Error(codes.Internal, "Something is broken on our side")
|
||||
}
|
||||
return nil, status.Error(codes.Aborted, "Couldn't list tokens")
|
||||
}
|
||||
return &tokens.RegenerateTokenResponse{
|
||||
TokenValue: &tokens.TokenValue{
|
||||
Token: tokenVal,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateToken implements [v1.TokensServiceServer].
|
||||
func (srv *TokensServer) UpdateToken(ctx context.Context, in *tokens.UpdateTokenRequest) (*tokens.UpdateTokenResponse, error) {
|
||||
claims, err := services.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, "Context is invalid")
|
||||
}
|
||||
if claims.UserID == "" {
|
||||
return nil, status.Error(codes.Aborted, "Context is invalid")
|
||||
}
|
||||
|
||||
if err := srv.tokenCtrl.VerifyTokenOwner(ctx, claims.UserID, in.TokenUuid.Uuid); err != nil {
|
||||
if errors.Is(err, services.ErrServerError) {
|
||||
return nil, status.Error(codes.Internal, "Something is broken on our side")
|
||||
}
|
||||
return nil, status.Error(codes.Aborted, "User is now allowed to manipulate this token")
|
||||
}
|
||||
if in.TokenPermissions == nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "Permissions must be set")
|
||||
}
|
||||
|
||||
permissions := map[string][]string{}
|
||||
for service, methods := range in.TokenPermissions.Permissions {
|
||||
permissions[service] = methods.GetMethods()
|
||||
}
|
||||
tokenData := &services.TokenData{
|
||||
Name: in.TokenMetadata.Name,
|
||||
Scopes: permissions,
|
||||
}
|
||||
if err := srv.tokenCtrl.Update(ctx, tokenData); err != nil {
|
||||
if errors.Is(err, services.ErrServerError) {
|
||||
return nil, status.Error(codes.Internal, "Something is broken on our side")
|
||||
}
|
||||
return nil, status.Error(codes.Aborted, "Couldn't list tokens")
|
||||
}
|
||||
return &tokens.UpdateTokenResponse{
|
||||
TokenUuid: &tokens.TokenUUID{},
|
||||
TokenMetadata: &tokens.TokenMetadata{},
|
||||
TokenPermissions: &tokens.TokenPermissions{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ListPermissions implements [v1.TokensServiceServer].
|
||||
func (srv *TokensServer) ListPermissions(in *emptypb.Empty, stream grpc.ServerStreamingServer[tokens.ListPermissionsResponse]) error {
|
||||
data := srv.tokenCtrl.ListPermissions(stream.Context())
|
||||
for key, data := range data {
|
||||
result := &tokens.ListPermissionsResponse{
|
||||
Permissions: &tokens.TokenPermissions{
|
||||
Permissions: map[string]*tokens.MethodList{
|
||||
key: {Methods: data},
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := stream.Send(result); err != nil {
|
||||
return status.Error(codes.Aborted, "Couldn't send data to the client")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user