Files
metacrypt/internal/grpcserver/auth.go
Kyle Isom dd698ff6d8 Migrate db, auth to mcdsl; remove mcias client dependency
- db.Open: delegate to mcdsl/db.Open
- db.Migrate: convert to mcdsl/db.Migration format, delegate
- auth: type aliases for TokenInfo/Authenticator/Config from mcdsl,
  re-export error sentinels, Logout helper
- cmd/server: construct auth.Authenticator from Config (not mcias.Client)
- server/routes.go logout: use auth.Logout(authenticator, token)
- grpcserver/auth.go: same logout pattern, fix Login return type
  (time.Time not string)
- webserver: replace mcias.Client with mcdsl/auth for service token
  validation; resolveUser degrades to raw UUID (TODO: restore when
  mcias client library is properly tagged)
- Dockerfiles: bump to golang:1.25-alpine, remove gcc/musl-dev,
  add VERSION build arg
- Deploy: add docker-compose-rift.yml with localhost-only port mapping
- Remove git.wntrmute.dev/kyle/mcias/clients/go dependency entirely
- All tests pass, net -185 lines

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 18:42:43 -07:00

56 lines
1.6 KiB
Go

package grpcserver
import (
"context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
pb "git.wntrmute.dev/kyle/metacrypt/gen/metacrypt/v2"
"git.wntrmute.dev/kyle/metacrypt/internal/auth"
)
type authServer struct {
pb.UnimplementedAuthServiceServer
s *GRPCServer
}
func (as *authServer) Login(_ context.Context, req *pb.LoginRequest) (*pb.LoginResponse, error) {
token, expiresAtTime, err := as.s.auth.Login(req.Username, req.Password, req.TotpCode)
if err != nil {
return nil, status.Error(codes.Unauthenticated, "invalid credentials")
}
var expiresAt *timestamppb.Timestamp
if !expiresAtTime.IsZero() {
expiresAt = timestamppb.New(expiresAtTime)
}
as.s.logger.Info("audit: login", "username", req.Username)
return &pb.LoginResponse{Token: token, ExpiresAt: expiresAt}, nil
}
func (as *authServer) Logout(ctx context.Context, _ *pb.LogoutRequest) (*pb.LogoutResponse, error) {
token := extractToken(ctx)
_ = auth.Logout(as.s.auth, token)
as.s.logger.Info("audit: logout", "username", callerUsername(ctx))
return &pb.LogoutResponse{}, nil
}
func (as *authServer) TokenInfo(ctx context.Context, _ *pb.TokenInfoRequest) (*pb.TokenInfoResponse, error) {
ti := tokenInfoFromContext(ctx)
if ti == nil {
// Shouldn't happen — authInterceptor runs first — but guard anyway.
token := extractToken(ctx)
var err error
ti, err = as.s.auth.ValidateToken(token)
if err != nil {
return nil, status.Error(codes.Unauthenticated, "invalid token")
}
}
return &pb.TokenInfoResponse{
Username: ti.Username,
Roles: ti.Roles,
IsAdmin: ti.IsAdmin,
}, nil
}