fix: normalize legacy wechat auth identity keys
This commit is contained in:
@@ -606,39 +606,42 @@ func ensurePendingWeChatOAuthIdentityForUser(ctx context.Context, tx *dbent.Tx,
|
||||
providerType := strings.TrimSpace(session.ProviderType)
|
||||
providerKey := strings.TrimSpace(session.ProviderKey)
|
||||
providerSubject := strings.TrimSpace(session.ProviderSubject)
|
||||
providerKeys := wechatCompatibleProviderKeys(providerKey)
|
||||
channel := strings.TrimSpace(pendingSessionStringValue(session.UpstreamIdentityClaims, "channel"))
|
||||
channelAppID := strings.TrimSpace(pendingSessionStringValue(session.UpstreamIdentityClaims, "channel_app_id"))
|
||||
channelSubject := strings.TrimSpace(pendingSessionStringValue(session.UpstreamIdentityClaims, "channel_subject"))
|
||||
metadata := cloneOAuthMetadata(session.UpstreamIdentityClaims)
|
||||
|
||||
identity, err := client.AuthIdentity.Query().
|
||||
identityRecords, err := client.AuthIdentity.Query().
|
||||
Where(
|
||||
authidentity.ProviderTypeEQ(providerType),
|
||||
authidentity.ProviderKeyEQ(providerKey),
|
||||
authidentity.ProviderKeyIn(providerKeys...),
|
||||
authidentity.ProviderSubjectEQ(providerSubject),
|
||||
).
|
||||
Only(ctx)
|
||||
if err != nil && !dbent.IsNotFound(err) {
|
||||
All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if identity != nil && identity.UserID != userID {
|
||||
return nil, infraerrors.Conflict("AUTH_IDENTITY_OWNERSHIP_CONFLICT", "auth identity already belongs to another user")
|
||||
identity, hasCanonicalKey, err := chooseWeChatIdentityForUser(identityRecords, userID, providerKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var legacyOpenIDIdentity *dbent.AuthIdentity
|
||||
if channelSubject != "" && channelSubject != providerSubject {
|
||||
legacyOpenIDIdentity, err = client.AuthIdentity.Query().
|
||||
legacyOpenIDRecords, err := client.AuthIdentity.Query().
|
||||
Where(
|
||||
authidentity.ProviderTypeEQ(providerType),
|
||||
authidentity.ProviderKeyEQ(providerKey),
|
||||
authidentity.ProviderKeyIn(providerKeys...),
|
||||
authidentity.ProviderSubjectEQ(channelSubject),
|
||||
).
|
||||
Only(ctx)
|
||||
if err != nil && !dbent.IsNotFound(err) {
|
||||
All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if legacyOpenIDIdentity != nil && legacyOpenIDIdentity.UserID != userID {
|
||||
return nil, infraerrors.Conflict("AUTH_IDENTITY_OWNERSHIP_CONFLICT", "auth identity already belongs to another user")
|
||||
legacyOpenIDIdentity, _, err = chooseWeChatIdentityForUser(legacyOpenIDRecords, userID, providerKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,6 +649,9 @@ func ensurePendingWeChatOAuthIdentityForUser(ctx context.Context, tx *dbent.Tx,
|
||||
case identity != nil:
|
||||
update := client.AuthIdentity.UpdateOneID(identity.ID).
|
||||
SetMetadata(mergeOAuthMetadata(identity.Metadata, metadata))
|
||||
if !strings.EqualFold(strings.TrimSpace(identity.ProviderKey), providerKey) && !hasCanonicalKey {
|
||||
update = update.SetProviderKey(providerKey)
|
||||
}
|
||||
if issuer := oauthIdentityIssuer(session); issuer != nil {
|
||||
update = update.SetIssuer(strings.TrimSpace(*issuer))
|
||||
}
|
||||
@@ -655,6 +661,7 @@ func ensurePendingWeChatOAuthIdentityForUser(ctx context.Context, tx *dbent.Tx,
|
||||
}
|
||||
case legacyOpenIDIdentity != nil:
|
||||
update := client.AuthIdentity.UpdateOneID(legacyOpenIDIdentity.ID).
|
||||
SetProviderKey(providerKey).
|
||||
SetProviderSubject(providerSubject).
|
||||
SetMetadata(mergeOAuthMetadata(legacyOpenIDIdentity.Metadata, metadata))
|
||||
if issuer := oauthIdentityIssuer(session); issuer != nil {
|
||||
@@ -684,21 +691,22 @@ func ensurePendingWeChatOAuthIdentityForUser(ctx context.Context, tx *dbent.Tx,
|
||||
return identity, nil
|
||||
}
|
||||
|
||||
channelRecord, err := client.AuthIdentityChannel.Query().
|
||||
channelRecords, err := client.AuthIdentityChannel.Query().
|
||||
Where(
|
||||
authidentitychannel.ProviderTypeEQ(providerType),
|
||||
authidentitychannel.ProviderKeyEQ(providerKey),
|
||||
authidentitychannel.ProviderKeyIn(providerKeys...),
|
||||
authidentitychannel.ChannelEQ(channel),
|
||||
authidentitychannel.ChannelAppIDEQ(channelAppID),
|
||||
authidentitychannel.ChannelSubjectEQ(channelSubject),
|
||||
).
|
||||
WithIdentity().
|
||||
Only(ctx)
|
||||
if err != nil && !dbent.IsNotFound(err) {
|
||||
All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if channelRecord != nil && channelRecord.Edges.Identity != nil && channelRecord.Edges.Identity.UserID != userID {
|
||||
return nil, infraerrors.Conflict("AUTH_IDENTITY_CHANNEL_OWNERSHIP_CONFLICT", "auth identity channel already belongs to another user")
|
||||
channelRecord, hasCanonicalChannelKey, err := chooseWeChatChannelForUser(channelRecords, userID, providerKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
channelMetadata := mergeOAuthMetadata(channelRecordMetadata(channelRecord), metadata)
|
||||
@@ -717,16 +725,75 @@ func ensurePendingWeChatOAuthIdentityForUser(ctx context.Context, tx *dbent.Tx,
|
||||
return identity, nil
|
||||
}
|
||||
|
||||
_, err = client.AuthIdentityChannel.UpdateOneID(channelRecord.ID).
|
||||
updateChannel := client.AuthIdentityChannel.UpdateOneID(channelRecord.ID).
|
||||
SetIdentityID(identity.ID).
|
||||
SetMetadata(channelMetadata).
|
||||
Save(ctx)
|
||||
SetMetadata(channelMetadata)
|
||||
if !strings.EqualFold(strings.TrimSpace(channelRecord.ProviderKey), providerKey) && !hasCanonicalChannelKey {
|
||||
updateChannel = updateChannel.SetProviderKey(providerKey)
|
||||
}
|
||||
_, err = updateChannel.Save(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return identity, nil
|
||||
}
|
||||
|
||||
func chooseWeChatIdentityForUser(records []*dbent.AuthIdentity, userID int64, preferredProviderKey string) (*dbent.AuthIdentity, bool, error) {
|
||||
var preferred *dbent.AuthIdentity
|
||||
var fallback *dbent.AuthIdentity
|
||||
hasCanonicalKey := false
|
||||
for _, record := range records {
|
||||
if record == nil {
|
||||
continue
|
||||
}
|
||||
if record.UserID != userID {
|
||||
return nil, false, infraerrors.Conflict("AUTH_IDENTITY_OWNERSHIP_CONFLICT", "auth identity already belongs to another user")
|
||||
}
|
||||
if strings.EqualFold(strings.TrimSpace(record.ProviderKey), preferredProviderKey) {
|
||||
hasCanonicalKey = true
|
||||
if preferred == nil {
|
||||
preferred = record
|
||||
}
|
||||
continue
|
||||
}
|
||||
if fallback == nil {
|
||||
fallback = record
|
||||
}
|
||||
}
|
||||
if preferred != nil {
|
||||
return preferred, hasCanonicalKey, nil
|
||||
}
|
||||
return fallback, hasCanonicalKey, nil
|
||||
}
|
||||
|
||||
func chooseWeChatChannelForUser(records []*dbent.AuthIdentityChannel, userID int64, preferredProviderKey string) (*dbent.AuthIdentityChannel, bool, error) {
|
||||
var preferred *dbent.AuthIdentityChannel
|
||||
var fallback *dbent.AuthIdentityChannel
|
||||
hasCanonicalKey := false
|
||||
for _, record := range records {
|
||||
if record == nil {
|
||||
continue
|
||||
}
|
||||
if record.Edges.Identity != nil && record.Edges.Identity.UserID != userID {
|
||||
return nil, false, infraerrors.Conflict("AUTH_IDENTITY_CHANNEL_OWNERSHIP_CONFLICT", "auth identity channel already belongs to another user")
|
||||
}
|
||||
if strings.EqualFold(strings.TrimSpace(record.ProviderKey), preferredProviderKey) {
|
||||
hasCanonicalKey = true
|
||||
if preferred == nil {
|
||||
preferred = record
|
||||
}
|
||||
continue
|
||||
}
|
||||
if fallback == nil {
|
||||
fallback = record
|
||||
}
|
||||
}
|
||||
if preferred != nil {
|
||||
return preferred, hasCanonicalKey, nil
|
||||
}
|
||||
return fallback, hasCanonicalKey, nil
|
||||
}
|
||||
|
||||
func channelRecordMetadata(channel *dbent.AuthIdentityChannel) map[string]any {
|
||||
if channel == nil {
|
||||
return map[string]any{}
|
||||
|
||||
Reference in New Issue
Block a user