List possible services and filter unavailable
All checks were successful
ci/woodpecker/push/build Pipeline was successful
All checks were successful
ci/woodpecker/push/build Pipeline was successful
Signed-off-by: Nikolai Rodionov <allanger@badhouseplants.net>
This commit is contained in:
@@ -4,6 +4,8 @@ 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 {
|
||||
@@ -18,6 +20,15 @@ func (t *TestServer) Pong(ctx context.Context, in *test.PongRequest) (*test.Pong
|
||||
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{}
|
||||
}
|
||||
@@ -29,3 +40,12 @@ type PublicTestServer struct {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -1,9 +1,100 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitea.badhouseplants.net/softplayer/softplayer-backend/internal/controllers"
|
||||
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"
|
||||
)
|
||||
|
||||
// var _ tokens.TokensServiceServer = (*TokensServer)(nil)
|
||||
type TokensServer struct {
|
||||
tokens.UnimplementedTokensServiceServer
|
||||
tokenCtrl *controllers.TokenController
|
||||
authorizationCtrl *controllers.AuthController
|
||||
}
|
||||
|
||||
func NewTokensServer(
|
||||
tokenCtrl *controllers.TokenController,
|
||||
authorizationCtrl *controllers.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 := srv.authorizationCtrl.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")
|
||||
}
|
||||
tokenData := &controllers.TokenData{
|
||||
Name: in.TokenMetadata.GetName(),
|
||||
UserID: claims.UserID,
|
||||
Scopes: &controllers.Scopes{},
|
||||
}
|
||||
|
||||
token, err := srv.tokenCtrl.Create(ctx, tokenData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &tokens.CreateTokenResponse{
|
||||
TokenUuid: &tokens.TokenUUID{},
|
||||
TokenMetadata: &tokens.TokenMetadata{},
|
||||
TokenPermissions: &tokens.TokenPermissions{},
|
||||
TokenValue: &tokens.TokenValue{Token: token},
|
||||
}, status.Error(codes.Unimplemented, "Method is not implemented")
|
||||
}
|
||||
|
||||
// ForceTokenExpiration implements [v1.TokensServiceServer].
|
||||
func (t *TokensServer) ForceTokenExpiration(context.Context, *tokens.ForceTokenExpirationRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "Method is not implemented")
|
||||
}
|
||||
|
||||
// GetToken implements [v1.TokensServiceServer].
|
||||
func (t *TokensServer) GetToken(context.Context, *tokens.GetTokenRequest) (*tokens.GetTokenResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "Method is not implemented")
|
||||
}
|
||||
|
||||
// ListTokens implements [v1.TokensServiceServer].
|
||||
func (t *TokensServer) ListTokens(*emptypb.Empty, grpc.ServerStreamingServer[tokens.ListTokensResponse]) error {
|
||||
return status.Error(codes.Unimplemented, "Method is not implemented")
|
||||
}
|
||||
|
||||
// RegenerateToken implements [v1.TokensServiceServer].
|
||||
func (t *TokensServer) RegenerateToken(context.Context, *tokens.RegenerateTokenRequest) (*tokens.RegenerateTokenResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "Method is not implemented")
|
||||
}
|
||||
|
||||
// UpdateToken implements [v1.TokensServiceServer].
|
||||
func (t *TokensServer) UpdateToken(context.Context, *tokens.UpdateTokenRequest) (*tokens.UpdateTokenResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "Method is not implemented")
|
||||
}
|
||||
|
||||
// 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.Permissions{
|
||||
AvailabiePermissions: 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
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"gitea.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/logger"
|
||||
accounts "gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/accounts/v1"
|
||||
test "gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/test/v1"
|
||||
tokens "gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/tokens/v1"
|
||||
grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors"
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
|
||||
@@ -82,13 +83,24 @@ func (cmd *Server) Run(ctx context.Context) error {
|
||||
selector.MatchFunc(selectorRequireAuth),
|
||||
),
|
||||
),
|
||||
grpc.StreamInterceptor(grpc_zap.StreamServerInterceptor(logger.SetupLogger("info"))),
|
||||
grpc.ChainStreamInterceptor(
|
||||
grpc_zap.StreamServerInterceptor(logger.SetupLogger("info")),
|
||||
selector.StreamServerInterceptor(
|
||||
auth.StreamServerInterceptor(authInterceptor.AuthInterceptorFN),
|
||||
selector.MatchFunc(selectorRequireAuth),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
if cmd.Reflection {
|
||||
reflection.Register(grpcServer)
|
||||
}
|
||||
|
||||
tokenCtrl := &controllers.TokenController{
|
||||
DB: db,
|
||||
HashCost: cmd.HashCost,
|
||||
}
|
||||
|
||||
accountCtrl := &controllers.AccountController{
|
||||
HashCost: cmd.HashCost,
|
||||
DB: db,
|
||||
@@ -99,10 +111,17 @@ func (cmd *Server) Run(ctx context.Context) error {
|
||||
Redis: rdb,
|
||||
}
|
||||
|
||||
accounts.RegisterPublicAccountsServiceServer(grpcServer, v1.NewPublicAccountServer(accountCtrl, authInterceptor))
|
||||
// Services that should be accessible for tokens should go here
|
||||
accounts.RegisterAccountsServiceServer(grpcServer, v1.NewAccountServer(accountCtrl, authInterceptor))
|
||||
test.RegisterTestServiceServer(grpcServer, v1.NewTestServer())
|
||||
test.RegisterPublicTestServiceServer(grpcServer, v1.NewPublicTestServer())
|
||||
tokens.RegisterTokensServiceServer(grpcServer, v1.NewTokensServer(tokenCtrl, authInterceptor))
|
||||
accounts.RegisterPublicAccountsServiceServer(grpcServer, v1.NewPublicAccountServer(accountCtrl, authInterceptor))
|
||||
|
||||
info := grpcServer.GetServiceInfo()
|
||||
tokenCtrl.SetGRPCInfo(info)
|
||||
tokenCtrl.SetRules()
|
||||
|
||||
if err := grpcServer.Serve(lis); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -116,8 +135,15 @@ func selectorRequireAuth(ctx context.Context, callMeta interceptors.CallMeta) bo
|
||||
if len(serviceParts) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
serviceName := serviceParts[len(serviceParts)-1]
|
||||
fmt.Println(serviceName)
|
||||
return !strings.HasPrefix(serviceName, "Public")
|
||||
|
||||
if strings.HasPrefix(serviceName, "Public") {
|
||||
return false
|
||||
}
|
||||
|
||||
if strings.Contains(serviceName, "ServerReflection") {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
2
go.mod
2
go.mod
@@ -42,7 +42,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
gitea.badhouseplants.net/softplayer/softplayer-go-proto v0.0.0-20260511094640-0f4959475dc9
|
||||
gitea.badhouseplants.net/softplayer/softplayer-go-proto v0.0.0-20260514095622-3ce39b865e5a
|
||||
github.com/golang/protobuf v1.5.4
|
||||
golang.org/x/net v0.49.0 // indirect
|
||||
golang.org/x/sys v0.40.0 // indirect
|
||||
|
||||
4
go.sum
4
go.sum
@@ -2,8 +2,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
|
||||
cloud.google.com/go v0.121.6 h1:waZiuajrI28iAf40cWgycWNgaXPO06dupuS+sgibK6c=
|
||||
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
|
||||
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
|
||||
gitea.badhouseplants.net/softplayer/softplayer-go-proto v0.0.0-20260511094640-0f4959475dc9 h1:gVB4z3qZXriL8xfJnY8hEqiBTGHGeeWO5E3GY/7aNRM=
|
||||
gitea.badhouseplants.net/softplayer/softplayer-go-proto v0.0.0-20260511094640-0f4959475dc9/go.mod h1:AgOh1lkPHyRgBf3/s1btKcAqke/33LbKYarTD13qeAg=
|
||||
gitea.badhouseplants.net/softplayer/softplayer-go-proto v0.0.0-20260514095622-3ce39b865e5a h1:F21MJw0xsiZf3cj4D+n8JPqkX38XlY+xFju2gQkC9eA=
|
||||
gitea.badhouseplants.net/softplayer/softplayer-go-proto v0.0.0-20260514095622-3ce39b865e5a/go.mod h1:AgOh1lkPHyRgBf3/s1btKcAqke/33LbKYarTD13qeAg=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
|
||||
@@ -4,19 +4,26 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"gitea.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/hash"
|
||||
"gitea.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/logger"
|
||||
"gitea.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/token"
|
||||
"github.com/google/uuid"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type TokenController struct {
|
||||
DB *sql.DB
|
||||
HashCost int16
|
||||
DB *sql.DB
|
||||
HashCost int16
|
||||
ServiceInfo map[string]grpc.ServiceInfo
|
||||
rules []rule
|
||||
}
|
||||
|
||||
// Services that are not available for tokens
|
||||
var DisabledServicesRegex = []string{".*Accounts.*", ".*Tokens.*"}
|
||||
|
||||
// Errors
|
||||
var (
|
||||
ErrServerError = errors.New("internal server error")
|
||||
@@ -35,6 +42,20 @@ type TokenData struct {
|
||||
|
||||
type Scopes struct{}
|
||||
|
||||
// Set the grpc info, must happen after all the service are initialized
|
||||
func (ctrl *TokenController) SetGRPCInfo(info map[string]grpc.ServiceInfo) {
|
||||
ctrl.ServiceInfo = info
|
||||
}
|
||||
|
||||
func (ctrl *TokenController) SetRules() {
|
||||
rules := []rule{
|
||||
{re: regexp.MustCompile(`.*Tokens.*`)},
|
||||
{re: regexp.MustCompile(`.*Accounts.*`)},
|
||||
{re: regexp.MustCompile(`.*Reflection.*`)},
|
||||
}
|
||||
ctrl.rules = rules
|
||||
}
|
||||
|
||||
// Create a new token, store its hash in the database and return the token value
|
||||
func (ctrl *TokenController) Create(ctx context.Context, data *TokenData) (string, error) {
|
||||
id := uuid.NewString()
|
||||
@@ -86,3 +107,32 @@ func (ctrl *TokenController) Get(ctx context.Context, uuid string) error {
|
||||
func (ctrl *TokenController) List(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Lis all available permissions
|
||||
func (ctrl *TokenController) ListPermissions(ctx context.Context) (result map[string][]string) {
|
||||
result = map[string][]string{}
|
||||
for key, val := range ctrl.ServiceInfo {
|
||||
if shouldSkip(key, ctrl.rules) {
|
||||
continue
|
||||
}
|
||||
var services []string
|
||||
for _, svc := range val.Methods {
|
||||
services = append(services, svc.Name)
|
||||
}
|
||||
result[key] = services
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type rule struct {
|
||||
re *regexp.Regexp
|
||||
}
|
||||
|
||||
func shouldSkip(s string, rules []rule) bool {
|
||||
for _, r := range rules {
|
||||
if r.re.MatchString(s) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user