Merge remote-tracking branch 'upstream/main' into dev
This commit is contained in:
commit
6b29556ef8
836 changed files with 1598388 additions and 64684 deletions
|
|
@ -10,9 +10,10 @@ import (
|
|||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/gotd/td/proto"
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/proto"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"github.com/iamxvbaba/td/tlprofile"
|
||||
"telesrv/internal/app/auth"
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
@ -21,39 +22,97 @@ import (
|
|||
const devCodeLength = 5
|
||||
|
||||
// registerAuth 注册 auth.* RPC handler。
|
||||
func (r *Router) registerAuth(d *tg.ServerDispatcher) {
|
||||
d.OnAuthBindTempAuthKey(r.onAuthBindTempAuthKey)
|
||||
d.OnAuthExportLoginToken(r.onAuthExportLoginToken)
|
||||
d.OnAuthImportLoginToken(r.onAuthImportLoginToken)
|
||||
d.OnAuthAcceptLoginToken(r.onAuthAcceptLoginToken)
|
||||
d.OnAuthExportAuthorization(func(ctx context.Context, dcid int) (*tg.AuthExportedAuthorization, error) {
|
||||
func (r *Router) registerAuth(d *tlprofile.Dispatcher) {
|
||||
registerRPC[*tg.AuthBindTempAuthKeyRequest](d, tlprofile.SemanticMethodAuthBindTempAuthKey, func(ctx context.Context, layerRequest *tg.AuthBindTempAuthKeyRequest) (any, error) {
|
||||
return r.onAuthBindTempAuthKey(ctx, layerRequest)
|
||||
})
|
||||
registerRPC[*tg.AuthExportLoginTokenRequest](d, tlprofile.SemanticMethodAuthExportLoginToken, func(ctx context.Context, layerRequest *tg.AuthExportLoginTokenRequest) (any, error) {
|
||||
return r.onAuthExportLoginToken(ctx, layerRequest)
|
||||
})
|
||||
registerRPC[*tg.AuthImportLoginTokenRequest](d, tlprofile.SemanticMethodAuthImportLoginToken, func(ctx context.Context, layerRequest *tg.AuthImportLoginTokenRequest) (any, error) {
|
||||
return r.onAuthImportLoginToken(ctx, layerRequest.
|
||||
Token)
|
||||
})
|
||||
registerRPC[*tg.AuthAcceptLoginTokenRequest](d, tlprofile.SemanticMethodAuthAcceptLoginToken, func(ctx context.Context, layerRequest *tg.AuthAcceptLoginTokenRequest) (any, error) {
|
||||
return r.onAuthAcceptLoginToken(ctx, layerRequest.
|
||||
Token)
|
||||
})
|
||||
registerRPC[*tg.AuthExportAuthorizationRequest](d, tlprofile.SemanticMethodAuthExportAuthorization, func(ctx context.Context, layerRequest *tg.AuthExportAuthorizationRequest) (any, error) {
|
||||
dcid := layerRequest.
|
||||
DCID
|
||||
_ = dcid
|
||||
|
||||
return nil, dcIDInvalidErr()
|
||||
})
|
||||
d.OnAuthImportAuthorization(func(ctx context.Context, req *tg.AuthImportAuthorizationRequest) (tg.AuthAuthorizationClass, error) {
|
||||
registerRPC[*tg.AuthImportAuthorizationRequest](d, tlprofile.SemanticMethodAuthImportAuthorization, func(ctx context.Context, req *tg.AuthImportAuthorizationRequest) (any, error) {
|
||||
return nil, dcIDInvalidErr()
|
||||
})
|
||||
d.OnAuthDropTempAuthKeys(func(ctx context.Context, exceptauthkeys []int64) (bool, error) {
|
||||
registerRPC[*tg.AuthDropTempAuthKeysRequest](d, tlprofile.SemanticMethodAuthDropTempAuthKeys, func(ctx context.Context, layerRequest *tg.AuthDropTempAuthKeysRequest) (any, error) {
|
||||
exceptauthkeys := layerRequest.
|
||||
ExceptAuthKeys
|
||||
_ = exceptauthkeys
|
||||
|
||||
return true, nil
|
||||
})
|
||||
d.OnAuthInitPasskeyLogin(r.onAuthInitPasskeyLogin)
|
||||
d.OnAuthFinishPasskeyLogin(r.onAuthFinishPasskeyLogin)
|
||||
d.OnAuthSendCode(r.onAuthSendCode)
|
||||
d.OnAuthResendCode(r.onAuthResendCode)
|
||||
d.OnAuthCancelCode(r.onAuthCancelCode)
|
||||
d.OnAuthSignIn(r.onAuthSignIn)
|
||||
d.OnAuthSignUp(r.onAuthSignUp)
|
||||
d.OnAuthImportBotAuthorization(r.onAuthImportBotAuthorization)
|
||||
d.OnAuthLogOut(r.onAuthLogOut)
|
||||
d.OnAuthResetAuthorizations(r.onAuthResetAuthorizations)
|
||||
d.OnAuthCheckPassword(r.onAuthCheckPassword)
|
||||
d.OnAuthRequestPasswordRecovery(r.onAuthRequestPasswordRecovery)
|
||||
d.OnAuthRecoverPassword(r.onAuthRecoverPassword)
|
||||
d.OnAuthCheckRecoveryPassword(r.onAuthCheckRecoveryPassword)
|
||||
d.OnAuthResetLoginEmail(r.onAuthResetLoginEmail)
|
||||
registerRPC[*tg.AuthInitPasskeyLoginRequest](d, tlprofile.SemanticMethodAuthInitPasskeyLogin, func(ctx context.Context, layerRequest *tg.AuthInitPasskeyLoginRequest) (any, error) {
|
||||
return r.onAuthInitPasskeyLogin(ctx, layerRequest)
|
||||
})
|
||||
registerRPC[*tg.AuthFinishPasskeyLoginRequest](d, tlprofile.SemanticMethodAuthFinishPasskeyLogin, func(ctx context.Context, layerRequest *tg.AuthFinishPasskeyLoginRequest) (any, error) {
|
||||
return r.onAuthFinishPasskeyLogin(ctx, layerRequest)
|
||||
})
|
||||
registerRPC[*tg.AuthSendCodeRequest](d, tlprofile.SemanticMethodAuthSendCode, func(ctx context.Context, layerRequest *tg.AuthSendCodeRequest) (any, error) {
|
||||
return r.onAuthSendCode(ctx, layerRequest)
|
||||
})
|
||||
registerRPC[*tg.AuthResendCodeRequest](d, tlprofile.SemanticMethodAuthResendCode, func(ctx context.Context, layerRequest *tg.AuthResendCodeRequest) (any, error) {
|
||||
return r.onAuthResendCode(ctx, layerRequest)
|
||||
})
|
||||
registerRPC[*tg.AuthCancelCodeRequest](d, tlprofile.SemanticMethodAuthCancelCode, func(ctx context.Context, layerRequest *tg.AuthCancelCodeRequest) (any, error) {
|
||||
return r.onAuthCancelCode(ctx, layerRequest)
|
||||
})
|
||||
registerRPC[*tg.AuthSignInRequest](d, tlprofile.SemanticMethodAuthSignIn, func(ctx context.Context, layerRequest *tg.AuthSignInRequest) (any, error) {
|
||||
return r.onAuthSignIn(ctx, layerRequest)
|
||||
})
|
||||
registerRPC[*tg.AuthSignUpRequest](d, tlprofile.SemanticMethodAuthSignUp, func(ctx context.Context, layerRequest *tg.AuthSignUpRequest) (any, error) {
|
||||
return r.onAuthSignUp(ctx, layerRequest)
|
||||
})
|
||||
registerRPC[*tg.AuthImportBotAuthorizationRequest](d, tlprofile.SemanticMethodAuthImportBotAuthorization, func(ctx context.Context, layerRequest *tg.AuthImportBotAuthorizationRequest) (any, error) {
|
||||
return r.onAuthImportBotAuthorization(ctx, layerRequest)
|
||||
})
|
||||
registerRPC[*tg.AuthLogOutRequest](d, tlprofile.SemanticMethodAuthLogOut, func(ctx context.Context, layerRequest *tg.AuthLogOutRequest) (any, error) {
|
||||
return r.onAuthLogOut(ctx)
|
||||
})
|
||||
registerRPC[*tg.AuthResetAuthorizationsRequest](d, tlprofile.SemanticMethodAuthResetAuthorizations, func(ctx context.Context, layerRequest *tg.AuthResetAuthorizationsRequest) (any, error) {
|
||||
return r.onAuthResetAuthorizations(ctx)
|
||||
})
|
||||
registerRPC[*tg.AuthCheckPasswordRequest](d, tlprofile.SemanticMethodAuthCheckPassword, func(ctx context.Context, layerRequest *tg.AuthCheckPasswordRequest) (any, error) {
|
||||
return r.onAuthCheckPassword(ctx, layerRequest.
|
||||
Password)
|
||||
})
|
||||
registerRPC[*tg.AuthRequestPasswordRecoveryRequest](d, tlprofile.SemanticMethodAuthRequestPasswordRecovery, func(ctx context.Context, layerRequest *tg.AuthRequestPasswordRecoveryRequest) (any, error) {
|
||||
return r.onAuthRequestPasswordRecovery(ctx)
|
||||
})
|
||||
registerRPC[*tg.AuthRecoverPasswordRequest](d, tlprofile.SemanticMethodAuthRecoverPassword, func(ctx context.Context, layerRequest *tg.AuthRecoverPasswordRequest) (any, error) {
|
||||
return r.onAuthRecoverPassword(ctx, layerRequest)
|
||||
})
|
||||
registerRPC[*tg.AuthCheckRecoveryPasswordRequest](d, tlprofile.SemanticMethodAuthCheckRecoveryPassword, func(ctx context.Context, layerRequest *tg.AuthCheckRecoveryPasswordRequest) (
|
||||
|
||||
// onAuthBindTempAuthKey 记录 TDesktop 的 PFS temp→perm auth key 绑定。
|
||||
any, error) {
|
||||
return r.onAuthCheckRecoveryPassword(ctx, layerRequest.
|
||||
Code)
|
||||
})
|
||||
registerRPC[*tg.AuthResetLoginEmailRequest](d, tlprofile.SemanticMethodAuthResetLoginEmail, func(ctx context.Context, layerRequest *tg.AuthResetLoginEmailRequest) (any, error) {
|
||||
return r.onAuthResetLoginEmail(ctx, layerRequest)
|
||||
})
|
||||
}
|
||||
|
||||
// onAuthBindTempAuthKey 记录 TDesktop 的 PFS temp→perm auth key 绑定。
|
||||
func (r *Router) onAuthBindTempAuthKey(ctx context.Context, req *tg.AuthBindTempAuthKeyRequest) (bool, error) {
|
||||
if !layerRPCProfileEvidenceFresh(ctx) {
|
||||
// The inner request is outside MTProto's mutable msg_id window. It may be
|
||||
// decoded request-locally, but acknowledging it would mutate the durable
|
||||
// temp→perm identity and every live session from stale replay evidence.
|
||||
return false, bindTempAuthKeyErr(auth.ErrTempAuthKeyEmpty)
|
||||
}
|
||||
if r.deps.Auth == nil {
|
||||
return true, nil
|
||||
}
|
||||
|
|
@ -71,18 +130,95 @@ func (r *Router) onAuthBindTempAuthKey(ctx context.Context, req *tg.AuthBindTemp
|
|||
}); err != nil {
|
||||
return false, bindTempAuthKeyErr(err)
|
||||
}
|
||||
permID := authKeyIDFromInt64(req.PermAuthKeyID)
|
||||
// temp key (re)bind 后立即作废其 temp→perm 解析缓存,确保下一帧按新绑定重新解析,
|
||||
// 不被 TTL 内的旧 perm 缓存命中(防跨账号串号)。
|
||||
if id != ([8]byte{}) {
|
||||
r.tempKeyResolveCache.Delete(id)
|
||||
}
|
||||
if r.deps.Sessions != nil {
|
||||
r.deps.Sessions.BindAuthKeyForSession(id, sessionID, authKeyIDFromInt64(req.PermAuthKeyID))
|
||||
}
|
||||
// Save atomically merged raw/permanent Layer observations. Both identities
|
||||
// must now re-read that durable permanent primary; pre-bind process caches
|
||||
// are not ordering evidence and cannot overwrite the transaction's winner.
|
||||
r.invalidateAuthUserCache(id)
|
||||
r.invalidateAuthUserCache(permID)
|
||||
unlockLayerCommit := r.lockAuthLayerCommit(id, permID)
|
||||
defer unlockLayerCommit()
|
||||
r.invalidateBoundAuthKeyLayerResolution(id, permID)
|
||||
if r.deps.Sessions != nil {
|
||||
if all, ok := r.deps.Sessions.(RawAuthKeySessionBinder); ok {
|
||||
all.BindAuthKeyForRawAuthKey(id, permID)
|
||||
} else {
|
||||
r.deps.Sessions.BindAuthKeyForSession(id, sessionID, permID)
|
||||
}
|
||||
}
|
||||
layer, _, err := r.resolveAuthKeyLayerDefault(ctx, permID)
|
||||
if err != nil {
|
||||
if clearer, ok := r.deps.Sessions.(AuthKeyInheritedLayerClearer); ok {
|
||||
clearer.ClearInheritedLayerForRawAuthKey(id)
|
||||
}
|
||||
if r.log != nil {
|
||||
r.log.Warn("reload merged permanent layer after temp auth key bind failed",
|
||||
zap.String("raw_auth_key_id", fmt.Sprintf("%x", id[:])),
|
||||
zap.String("perm_auth_key_id", fmt.Sprintf("%x", permID[:])),
|
||||
zap.Error(err))
|
||||
}
|
||||
return false, internalErr()
|
||||
}
|
||||
r.cacheBoundAuthKeyLayerResolution(id, permID)
|
||||
if isSupportedLayer(layer) {
|
||||
if refresher, ok := r.deps.Sessions.(AuthKeyLayerRefresher); ok {
|
||||
refresher.RefreshInheritedLayerForRawAuthKey(id, layer)
|
||||
} else if binder, ok := r.deps.Sessions.(AuthKeyLayerBinder); ok {
|
||||
binder.SeedInheritedLayerForRawAuthKey(id, layer)
|
||||
}
|
||||
} else if clearer, ok := r.deps.Sessions.(AuthKeyInheritedLayerClearer); ok {
|
||||
clearer.ClearInheritedLayerForRawAuthKey(id)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (r *Router) invalidateBoundAuthKeyLayerResolution(authKeyIDs ...[8]byte) {
|
||||
r.clientInfoMu.Lock()
|
||||
defer r.clientInfoMu.Unlock()
|
||||
for _, authKeyID := range authKeyIDs {
|
||||
if info, ok := r.authInfo[authKeyID]; ok {
|
||||
info.layer = 0
|
||||
info.layerObservationID = 0
|
||||
info.layerAdmissionSeq = 0
|
||||
info.authKeyInfoChecked = false
|
||||
info.authorizationChecked = false
|
||||
info.layerBlocked = false
|
||||
info.layerBlockedByAuthKey = false
|
||||
r.authInfo[authKeyID] = info
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Router) cacheBoundAuthKeyLayerResolution(rawAuthKeyID, permAuthKeyID [8]byte) {
|
||||
r.clientInfoMu.Lock()
|
||||
defer r.clientInfoMu.Unlock()
|
||||
if r.authInfo == nil {
|
||||
r.authInfo = make(map[[8]byte]clientSessionInfo)
|
||||
}
|
||||
if _, exists := r.authInfo[rawAuthKeyID]; !exists {
|
||||
evictMapEntryIfFullLocked(r.authInfo, maxAuthInfoEntries)
|
||||
}
|
||||
canonical := r.authInfo[permAuthKeyID]
|
||||
info := r.authInfo[rawAuthKeyID]
|
||||
// The bind transaction made the permanent row authoritative for both
|
||||
// identities. Copy its complete resolution tuple: a Layer without the same
|
||||
// observation token (or a stale blocked bit) would let later cache merging
|
||||
// manufacture an ordering state that never existed durably.
|
||||
info.layer = canonical.layer
|
||||
info.layerObservationID = canonical.layerObservationID
|
||||
info.layerAdmissionSeq = canonical.layerAdmissionSeq
|
||||
info.layerBlocked = canonical.layerBlocked
|
||||
info.layerBlockedByAuthKey = canonical.layerBlockedByAuthKey
|
||||
info.authKeyInfoChecked = canonical.authKeyInfoChecked
|
||||
info.authorizationChecked = canonical.authorizationChecked
|
||||
r.authInfo[rawAuthKeyID] = info
|
||||
}
|
||||
|
||||
// onAuthExportLoginToken 给 QR 登录请求方返回短期 token;扫码端接受后,同一目标
|
||||
// session 后续 export 会升级为 auth.loginTokenSuccess。
|
||||
func (r *Router) onAuthExportLoginToken(ctx context.Context, req *tg.AuthExportLoginTokenRequest) (tg.AuthLoginTokenClass, error) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue