package api import ( "context" "errors" "log" codequestpb "github.com/hhhapz/codequest/api/v1" "github.com/hhhapz/codequest/models" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/emptypb" ) type AuthService struct { codequestpb.UnimplementedAuthServiceServer oauthStore OAuthStore userStore UserStore } const ( forwardedHostKey = "x-forwarded-host" uiHost = "codequest.teamortix.com" ) func (as *AuthService) AuthFuncOverride(ctx context.Context, method string) (context.Context, error) { switch method { case "DeleteToken": return BearerAuth(ctx, as.userStore) } return ctx, nil } func (as *AuthService) OAuthCode(ctx context.Context, req *codequestpb.OAuthCodeRequest) (*codequestpb.OAuthCodeResponse, error) { md := RequestMetadata(ctx) host := md.Get(forwardedHostKey) if host != uiHost && inProd { return nil, status.Errorf(codes.InvalidArgument, "invalid host: %v", host) } page := as.oauthStore.Create(host) return &codequestpb.OAuthCodeResponse{ RedirectURI: page, }, nil } func (as *AuthService) Token(ctx context.Context, req *codequestpb.TokenRequest) (*codequestpb.Token, error) { token, _, err := as.oauthStore.Validate(ctx, req.State, req.Code) if err != nil { if errors.As(err, &models.UserError{}) { return nil, status.Errorf(codes.InvalidArgument, err.Error()) } log.Printf("could not perform token exchange: %v", err) return nil, status.Errorf(codes.InvalidArgument, "invalid code %q: %v", req.Code, err) } tk, err := as.userStore.ConsumeToken(ctx, token) if err != nil { if errors.As(err, &models.UserError{}) { return nil, status.Errorf(codes.InvalidArgument, "could not authorize: %v", err) } log.Printf("could not authorize request: %v", err) return nil, status.Errorf(codes.Internal, "could not authorize: internal error") } return &codequestpb.Token{ Token: tk.Token, Expires: nil, }, nil } func (as *AuthService) DeleteToken(ctx context.Context, req *codequestpb.DeleteTokenRequest) (*emptypb.Empty, error) { u := UserCtx(ctx) var err error if req.All { _, err = as.userStore.RevokeUserTokens(ctx, u) } else { err = as.userStore.RevokeToken(ctx, TokenCtx(ctx)) } if err != nil { log.Printf("could not revoke token: %v", err) return nil, status.Errorf(codes.Internal, "could not revoke token") } return &emptypb.Empty{}, nil }