Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 74 additions & 72 deletions packages/dashboard-api/internal/api/api.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,12 @@ func (s *APIStore) PostAdminUsersBootstrap(c *gin.Context) {
}

team, err := s.bootstrapOIDCUser(ctx, oidcUserBootstrapInput{
OIDCIssuer: oidcIssuer,
OIDCUserID: oidcUserID,
OIDCUserEmail: oidcUserEmail,
OIDCUserName: body.OidcUserName,
OIDCIssuer: oidcIssuer,
OIDCUserID: oidcUserID,
OIDCUserEmail: oidcUserEmail,
OIDCUserName: body.OidcUserName,
SignupIP: strings.TrimSpace(valueOrEmpty(body.SignupIp)),
SignupUserAgent: strings.TrimSpace(valueOrEmpty(body.SignupUserAgent)),
})
if err != nil {
s.handleProvisioningError(ctx, c, "bootstrap auth provider user", err)
Expand All @@ -74,3 +76,11 @@ func (s *APIStore) PostAdminUsersBootstrap(c *gin.Context) {
Slug: team.Slug,
})
}

func valueOrEmpty(value *string) string {
if value == nil {
return ""
}

return *value
}
22 changes: 18 additions & 4 deletions packages/dashboard-api/internal/handlers/team_handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -572,10 +572,12 @@ func TestBootstrapAuthProviderUser_CreatesIdentityAndDefaultTeam(t *testing.T) {
}

input := oidcUserBootstrapInput{
OIDCIssuer: "https://ory.example.test",
OIDCUserID: uuid.NewString(),
OIDCUserEmail: "ada@example.test",
OIDCUserName: nil,
OIDCIssuer: "https://ory.example.test",
OIDCUserID: uuid.NewString(),
OIDCUserEmail: "ada@example.test",
OIDCUserName: nil,
SignupIP: "198.51.100.20",
SignupUserAgent: "Mozilla/5.0",
}

team, err := store.bootstrapOIDCUser(ctx, input)
Expand Down Expand Up @@ -611,6 +613,18 @@ func TestBootstrapAuthProviderUser_CreatesIdentityAndDefaultTeam(t *testing.T) {
if sink.requests[0].CreatorUserID != userIdentity.UserID {
t.Fatalf("expected sink creator %s, got %s", userIdentity.UserID, sink.requests[0].CreatorUserID)
}
if sink.requests[0].CreatorContext == nil {
t.Fatal("expected sink creator context")
}
if sink.requests[0].CreatorContext.IPAddress != "198.51.100.20" {
t.Fatalf("expected sink creator ip %q, got %q", "198.51.100.20", sink.requests[0].CreatorContext.IPAddress)
}
if sink.requests[0].CreatorContext.UserAgent != "Mozilla/5.0" {
t.Fatalf("expected sink creator user agent %q, got %q", "Mozilla/5.0", sink.requests[0].CreatorContext.UserAgent)
}
if sink.requests[0].CreatorContext.AuthMethod != teamprovision.AuthMethodSocial {
t.Fatalf("expected sink creator auth method %q, got %q", teamprovision.AuthMethodSocial, sink.requests[0].CreatorContext.AuthMethod)
}
}

func TestBootstrapOIDCUser_ConcurrentRequestsSingleIdentityAndTeam(t *testing.T) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type bootstrapUserProfile struct {
UserID uuid.UUID
Email string
DefaultTeamName string
CreatorContext *teamprovision.CreatorContextV1
}

type bootstrapUserIdentity struct {
Expand All @@ -54,10 +55,12 @@ type bootstrapUserIdentity struct {
}

type oidcUserBootstrapInput struct {
OIDCIssuer string
OIDCUserID string
OIDCUserEmail string
OIDCUserName *string
OIDCIssuer string
OIDCUserID string
OIDCUserEmail string
OIDCUserName *string
SignupIP string
SignupUserAgent string
}

func (s *APIStore) bootstrapSupabaseUser(ctx context.Context, userID uuid.UUID) (provisionedTeam, error) {
Expand Down Expand Up @@ -111,6 +114,7 @@ func (s *APIStore) bootstrapOIDCUser(ctx context.Context, input oidcUserBootstra
UserID: uuid.New(),
Email: input.OIDCUserEmail,
DefaultTeamName: defaultTeamNameFromOIDCUserName(input.OIDCUserName),
CreatorContext: creatorContextFromSignupMetadata(input.SignupIP, input.SignupUserAgent, teamprovision.AuthMethodSocial),
}

return s.bootstrapUserWithIdentity(ctx, profile, &bootstrapUserIdentity{
Expand Down Expand Up @@ -219,7 +223,7 @@ func (s *APIStore) bootstrapUserWithIdentity(ctx context.Context, profile bootst
TeamName: existingTeam.Name,
TeamEmail: existingTeam.Email,
CreatorUserID: profile.UserID,
CreatorContext: s.resolveTeamCreatorContext(ctx, profile.UserID),
CreatorContext: s.teamCreatorContextForProvisioning(ctx, profile),
Reason: teamprovision.ReasonDefaultSignupTeam,
}
_ = s.teamProvisionSink.ProvisionTeam(ctx, req)
Expand Down Expand Up @@ -267,7 +271,7 @@ func (s *APIStore) bootstrapUserWithIdentity(ctx context.Context, profile bootst
TeamName: team.Name,
TeamEmail: team.Email,
CreatorUserID: profile.UserID,
CreatorContext: s.resolveTeamCreatorContext(ctx, profile.UserID),
CreatorContext: s.teamCreatorContextForProvisioning(ctx, profile),
Reason: teamprovision.ReasonDefaultSignupTeam,
}
_ = s.teamProvisionSink.ProvisionTeam(ctx, req)
Expand Down Expand Up @@ -462,7 +466,40 @@ func (s *APIStore) resolveTeamCreatorContext(ctx context.Context, userID uuid.UU
return nil
}

return creatorContext
return normalizeCreatorContext(creatorContext)
}

func (s *APIStore) teamCreatorContextForProvisioning(ctx context.Context, profile bootstrapUserProfile) *teamprovision.CreatorContextV1 {
if profile.CreatorContext != nil {
return normalizeCreatorContext(profile.CreatorContext)
}

return s.resolveTeamCreatorContext(ctx, profile.UserID)
}

func creatorContextFromSignupMetadata(signupIP, signupUserAgent, authMethod string) *teamprovision.CreatorContextV1 {
return normalizeCreatorContext(&teamprovision.CreatorContextV1{
IPAddress: signupIP,
UserAgent: signupUserAgent,
AuthMethod: authMethod,
})
}

func normalizeCreatorContext(creatorContext *teamprovision.CreatorContextV1) *teamprovision.CreatorContextV1 {
if creatorContext == nil {
return nil
}

ipAddress := strings.TrimSpace(creatorContext.IPAddress)
if ipAddress == "" {
return nil
}

return &teamprovision.CreatorContextV1{
IPAddress: ipAddress,
UserAgent: strings.TrimSpace(creatorContext.UserAgent),
AuthMethod: strings.TrimSpace(creatorContext.AuthMethod),
}
}

func defaultTeamNameFromProfile(profile userprofile.Profile) string {
Expand Down
15 changes: 2 additions & 13 deletions packages/dashboard-api/internal/userprofile/creator_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,19 @@ import (
"strings"

sharedteamprovision "github.com/e2b-dev/infra/packages/shared/pkg/teamprovision"
"github.com/e2b-dev/infra/packages/shared/pkg/utils"
)

const (
signupIPMetadataKey = "signup_ip"
signupUserAgentMetadataKey = "signup_user_agent"
ipMetadataKey = "ip"
ipAddressMetadataKey = "ip_address"
userAgentMetadataKey = "user_agent"
providersMetadataKey = "providers"
providerMetadataKey = "provider"
)

func creatorContextFromMetadata(metadata map[string]any, providerNames []string) *sharedteamprovision.CreatorContextV1 {
return &sharedteamprovision.CreatorContextV1{
IPAddress: utils.FirstNonEmpty(
metadataString(metadata, signupIPMetadataKey),
metadataString(metadata, ipAddressMetadataKey),
metadataString(metadata, ipMetadataKey),
),
UserAgent: utils.FirstNonEmpty(
metadataString(metadata, signupUserAgentMetadataKey),
metadataString(metadata, userAgentMetadataKey),
),
IPAddress: metadataString(metadata, signupIPMetadataKey),
UserAgent: metadataString(metadata, signupUserAgentMetadataKey),
AuthMethod: authMethodFromProviderNames(providerNames),
}
}
Expand Down
Loading
Loading