package rpc import ( "context" "encoding/binary" "fmt" "sort" "time" "go.uber.org/zap" "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/domain" "telesrv/internal/store" ) const ( inheritedAuthKeyLayerSingleflightPrefix = "inherited-layer:" durableInheritedAuthKeyLayerSingleflightPrefix = "durable-inherited-layer:" ) const authLayerCommitStripes = 4096 const ( authLayerPublicationTimeout = 5 * time.Second maxAuthLayerEvidenceEntries = maxAuthInfoEntries ) type inheritedAuthKeyLayerResult struct { layer int found bool } // PublishAdmittedLayerProfileEvidence commits protocol evidence before an // admitted request can be delayed by the business scheduler or replaced by an // initConnection rewrap alias. admissionSeq is allocated by mtprotoedge when // the fresh request obtains flight ownership; it orders process-local/no-store // publication and supplies the active-admission safe floor. In durable mode the // store's ObservationID is the cross-session/cross-process publication order. // Replays reuse the owner's admission sequence and do not publish again. func (r *Router) PublishAdmittedLayerProfileEvidence( ctx context.Context, rawAuthKeyID [8]byte, sessionID int64, msgID int64, admissionSeq uint64, safeFloor uint64, layer int, ) error { if r == nil || rawAuthKeyID == ([8]byte{}) || sessionID == 0 { return fmt.Errorf("invalid admitted layer evidence identity") } if admissionSeq == 0 { return fmt.Errorf("invalid admitted layer evidence sequence") } if safeFloor == 0 || safeFloor > admissionSeq { return fmt.Errorf("invalid admitted layer evidence safe floor %d for sequence %d", safeFloor, admissionSeq) } if !isSupportedLayer(layer) { return fmt.Errorf("unsupported admitted layer evidence %d", layer) } // The edge tracker owns admission lifecycle and supplies an exact global // retirement floor. Advance it even if this particular proof became stale: // the floor itself remains valid capacity-reclamation evidence. r.clientInfoMu.Lock() if safeFloor > r.authLayerSafeEvictionFloor { r.authLayerSafeEvictionFloor = safeFloor } r.clientInfoMu.Unlock() if r.deps.AuthKeySessionLayers == nil { currentLayer, currentMsgID, ok := r.NegotiatedSessionLayerEvidence(rawAuthKeyID, sessionID) if !ok || currentLayer != layer || (msgID > 0 && currentMsgID != msgID) { // A newer correction or bounded registry eviction makes this evidence // stale, not invalid. The admitted request keeps its immutable codec but // no longer owns shared mutable state. return nil } } if ctx == nil { ctx = context.Background() } publicationSequence := admissionSeq publicationDurable := false if r.deps.AuthKeySessionLayers != nil { current, found, err := r.deps.AuthKeySessionLayers.GetSessionLayer(ctx, rawAuthKeyID, sessionID) if err != nil { // The durable transaction has already committed the protocol fact. // A failed cache revalidation must not reject/re-execute the RPC; leave // this process cache untouched and let the next session read primary. if r.log != nil { r.log.Warn("revalidate durable auth-key Layer default for local publication failed", zap.String("raw_auth_key_id", fmt.Sprintf("%x", rawAuthKeyID[:])), zap.Int64("session_id", sessionID), zap.Error(err)) } return nil } if !found || !current.SharedDefault || current.Layer != layer || current.MessageID != msgID { // Another session/process has already committed a newer shared // default. This request keeps its immutable result codec but cannot // overwrite process-local inherited state. return nil } if current.ObservationID <= 0 { return store.ErrAuthKeySessionLayerInvalid } publicationSequence = uint64(current.ObservationID) publicationDurable = true } effectiveAuthKeyID := rawAuthKeyID if r.deps.Auth != nil { resolveCtx, cancel := context.WithTimeout(ctx, authLayerPublicationTimeout) resolved, found, err := r.deps.Auth.ResolveAuthKey(resolveCtx, rawAuthKeyID) cancel() switch { case err != nil: // Persistence identity lookup is availability metadata, not proof of // whether this request's generated wire profile is valid. Publish the // raw-key default now; a later bind/explicit observation can retry the // durable permanent-key normalization. if r.log != nil { r.log.Warn("resolve auth key for admitted layer evidence failed; publishing raw default", zap.String("raw_auth_key_id", fmt.Sprintf("%x", rawAuthKeyID[:])), zap.Uint64("admission_seq", admissionSeq), zap.Error(err)) } case found && resolved == ([8]byte{}): return fmt.Errorf("admitted layer evidence resolved an empty permanent auth key") case found: effectiveAuthKeyID = resolved } } unlockCommit := r.lockAuthLayerCommit(rawAuthKeyID, effectiveAuthKeyID) defer unlockCommit() // Freeze may have admitted a newer same-session correction while identity // resolution was in flight. The old request stays decodable, but can no // longer publish shared state. if r.deps.AuthKeySessionLayers == nil { if currentLayer, currentMsgID, ok := r.NegotiatedSessionLayerEvidence(rawAuthKeyID, sessionID); !ok || currentLayer != layer || (msgID > 0 && currentMsgID != msgID) { return nil } } r.clientInfoMu.Lock() applied, err := r.claimAuthLayerDefaultEvidenceLocked( layer, publicationSequence, publicationDurable, rawAuthKeyID, effectiveAuthKeyID, ) if err == nil && applied { if r.clientInfo == nil { r.clientInfo = make(map[clientInfoSessionKey]clientSessionInfo) } key := clientInfoSessionKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID} info, exists := r.clientInfo[key] if !exists { evictMapEntryIfFullLocked(r.clientInfo, maxClientInfoEntries) } info.layer = layer if publicationDurable { info.layerObservationID = int64(publicationSequence) } else { info.layerAdmissionSeq = admissionSeq } r.clientInfo[key] = info } r.clientInfoMu.Unlock() if err != nil || !applied { return err } if binder, ok := r.deps.Sessions.(AuthKeyLayerBinder); ok { binder.SeedInheritedLayerForRawAuthKey(rawAuthKeyID, layer) } if effectiveAuthKeyID != rawAuthKeyID { if binder, ok := r.deps.Sessions.(BusinessAuthKeyLayerBinder); ok { binder.SeedInheritedLayerForBusinessAuthKey(effectiveAuthKeyID, layer) } else if binder, ok := r.deps.Sessions.(AuthKeyLayerBinder); ok { // Compatibility fallback for test doubles/older embedders where a // permanent key is itself also the raw connection key. binder.SeedInheritedLayerForRawAuthKey(effectiveAuthKeyID, layer) } } // Production durable evidence already updated raw/permanent auth_keys and // the authorization mirror in one transaction. The legacy path remains only // for isolated Router tests that intentionally omit the protocol store. if r.deps.AuthKeySessionLayers == nil { r.persistAdmittedAuthKeyLayer(ctx, effectiveAuthKeyID, layer, admissionSeq) if effectiveAuthKeyID != rawAuthKeyID { r.persistAdmittedAuthKeyLayer(ctx, rawAuthKeyID, layer, admissionSeq) } } return nil } func (r *Router) claimAuthLayerDefaultEvidenceLocked( layer int, sequence uint64, durable bool, authKeyIDs ...[8]byte, ) (bool, error) { if r.authLayerEvidence == nil { r.authLayerEvidence = make(map[[8]byte]authLayerDefaultEvidence) } ids := make([][8]byte, 0, len(authKeyIDs)) for _, authKeyID := range authKeyIDs { if authKeyID == ([8]byte{}) { continue } duplicate := false for _, existing := range ids { if existing == authKeyID { duplicate = true break } } if !duplicate { ids = append(ids, authKeyID) } } for _, authKeyID := range ids { info := r.authInfo[authKeyID] if durable { if info.layerObservationID < 0 { return false, fmt.Errorf("invalid cached auth-key layer observation %d", info.layerObservationID) } if uint64(info.layerObservationID) > sequence { return false, nil } if info.layerObservationID > 0 && uint64(info.layerObservationID) == sequence && info.layer != layer { return false, fmt.Errorf("auth-key layer evidence conflict at durable observation %d: current=%d requested=%d", sequence, info.layer, layer) } } else { if info.layerAdmissionSeq > sequence { return false, nil } if info.layerAdmissionSeq == sequence && info.layerAdmissionSeq > 0 && info.layer != layer { return false, fmt.Errorf("auth-key layer evidence conflict at admission sequence %d: current=%d requested=%d", sequence, info.layer, layer) } } current, exists := r.authLayerEvidence[authKeyID] if !exists { continue } if current.durable && !durable { return false, nil } if durable && !current.durable { continue } if current.sequence > sequence { return false, nil } if current.sequence == sequence && current.layer != layer { kind := "admission sequence" if durable { kind = "durable observation" } return false, fmt.Errorf("auth-key layer evidence conflict at %s %d: current=%d requested=%d", kind, sequence, current.layer, layer) } } missing := 0 for _, authKeyID := range ids { if _, exists := r.authLayerEvidence[authKeyID]; !exists { missing++ } } if len(r.authLayerEvidence)+missing > maxAuthLayerEvidenceEntries { for len(r.authLayerEvidence)+missing > maxAuthLayerEvidenceEntries { var ( candidate [8]byte candidateSeq uint64 haveCandidate bool ) for currentID, current := range r.authLayerEvidence { keep := false for _, id := range ids { if currentID == id { keep = true break } } if keep { continue } if !current.durable && current.sequence >= r.authLayerSafeEvictionFloor { continue } if !haveCandidate || current.sequence < candidateSeq { candidate, candidateSeq, haveCandidate = currentID, current.sequence, true } } if !haveCandidate { if r.log != nil { r.log.Warn("auth-key layer evidence capacity exhausted; skip shared default", zap.Int("entries", len(r.authLayerEvidence)), zap.Uint64("evidence_sequence", sequence), zap.Bool("durable", durable), zap.Int("layer", layer)) } return false, nil } delete(r.authLayerEvidence, candidate) } } for _, authKeyID := range ids { r.authLayerEvidence[authKeyID] = authLayerDefaultEvidence{ layer: layer, sequence: sequence, durable: durable, } if durable { r.rememberAuthClientLayerObservationLocked(authKeyID, layer, int64(sequence)) } else { r.rememberAuthClientLayerAtLocked(authKeyID, layer, sequence) } } return true, nil } func (r *Router) persistAdmittedAuthKeyLayer(ctx context.Context, authKeyID [8]byte, layer int, admissionSeq uint64) { if r.deps.Auth == nil || authKeyID == ([8]byte{}) { return } persistCtx, cancel := context.WithTimeout(ctx, authLayerPublicationTimeout) err := r.deps.Auth.UpdateAuthKeyClientInfo(persistCtx, authKeyID, domain.AuthKeyClientInfo{Layer: layer}) cancel() if err != nil && r.log != nil { r.log.Warn("persist admitted auth-key layer default failed", zap.String("auth_key_id", fmt.Sprintf("%x", authKeyID[:])), zap.Int("layer", layer), zap.Uint64("admission_seq", admissionSeq), zap.Error(err)) } } func (r *Router) lockAuthLayerCommit(authKeyIDs ...[8]byte) func() { indices := make([]int, 0, len(authKeyIDs)) for _, authKeyID := range authKeyIDs { if authKeyID == ([8]byte{}) { continue } index := authLayerCommitIndex(authKeyID) duplicate := false for _, existing := range indices { if existing == index { duplicate = true break } } if !duplicate { indices = append(indices, index) } } sort.Ints(indices) for _, index := range indices { r.authLayerCommit[index].Lock() } return func() { for index := len(indices) - 1; index >= 0; index-- { r.authLayerCommit[indices[index]].Unlock() } } } func authLayerCommitIndex(authKeyID [8]byte) int { return int(binary.LittleEndian.Uint64(authKeyID[:]) % authLayerCommitStripes) } // ResolveInheritedAuthKeyLayer resolves the durable last-known default for a // newly-created connection. The input is always the physical/raw auth key. A // bound temporary key is normalized to its permanent identity before reading // Layer, so an old raw shadow can never outrank the current permanent default. // // found=false means no canonical default exists and permits the edge to inspect // a raw-key fallback. found=true with layer=0 means the canonical record carries // a future Layer not generated into this binary; it is authoritative-but- // unusable and therefore blocks fallback/clamping until fresh supported explicit // invokeWithLayer evidence or a newer binary establishes a usable profile. func (r *Router) ResolveInheritedAuthKeyLayer(ctx context.Context, rawAuthKeyID [8]byte) (int, bool, error) { if r == nil || rawAuthKeyID == ([8]byte{}) { return 0, false, nil } if ctx == nil { ctx = context.Background() } effectiveAuthKeyID := rawAuthKeyID if r.deps.Auth != nil { resolved, found, err := r.deps.Auth.ResolveAuthKey(ctx, rawAuthKeyID) if err != nil { return 0, false, wrapLayerEvidenceStoreAvailability(err) } if found { if resolved == ([8]byte{}) { return 0, false, fmt.Errorf("resolved empty permanent auth key") } effectiveAuthKeyID = resolved } } layer, found, err := r.resolveAuthKeyLayerDefault(ctx, effectiveAuthKeyID) if err != nil { return 0, false, wrapLayerEvidenceStoreAvailability(err) } if !found { return 0, false, nil } var durableProjection clientSessionInfo if r.deps.AuthKeySessionLayers != nil { // resolveDurableAuthKeyLayerDefault may have completed a stale DB read // after a newer same-process explicit observation was published. The // observation-aware cache merge keeps the newer tuple; re-read it before // returning or projecting to a bound raw identity. r.clientInfoMu.RLock() current := r.authInfo[effectiveAuthKeyID] r.clientInfoMu.RUnlock() if current.layerObservationID > 0 { durableProjection = clientSessionInfo{ layer: current.layer, layerObservationID: current.layerObservationID, layerBlocked: current.layerBlocked, layerBlockedByAuthKey: current.layerBlockedByAuthKey, authKeyInfoChecked: current.authKeyInfoChecked, authorizationChecked: current.authorizationChecked, } switch { case isSupportedLayer(current.layer): layer, found = current.layer, true case current.layerBlocked: layer, found = 0, true } } } if layer == 0 { // found=true with no usable profile is an authoritative future/unsupported // canonical default. The edge must stay unknown rather than falling back // to an older raw temporary-key shadow. return 0, true, nil } if effectiveAuthKeyID != rawAuthKeyID { // This updates only the auth-key default/shadow. Existing session entries // remain untouched and therefore keep mixed Layer 225/227 profiles. r.clientInfoMu.Lock() if durableProjection.layerObservationID > 0 { r.rememberAuthClientInfoLocked(rawAuthKeyID, durableProjection) } else { r.rememberAuthClientLayerLocked(rawAuthKeyID, layer) } r.clientInfoMu.Unlock() } return layer, true, nil } func (r *Router) resolveAuthKeyLayerDefault(ctx context.Context, authKeyID [8]byte) (int, bool, error) { if r == nil || authKeyID == ([8]byte{}) { return 0, false, nil } if r.deps.AuthKeySessionLayers != nil { return r.resolveDurableAuthKeyLayerDefault(ctx, authKeyID) } if layer, found, resolved := r.cachedAuthKeyLayerResolution(authKeyID); resolved { return layer, found, nil } if r.deps.Auth == nil { return 0, false, nil } v, err, _ := r.authUserSF.Do(inheritedAuthKeyLayerSingleflightPrefix+string(authKeyID[:]), func() (any, error) { if layer, found, resolved := r.cachedAuthKeyLayerResolution(authKeyID); resolved { return inheritedAuthKeyLayerResult{layer: layer, found: found}, nil } keyInfo, keyFound, err := r.deps.Auth.AuthKeyClientInfo(ctx, authKeyID) if err != nil { return inheritedAuthKeyLayerResult{}, err } if keyFound { r.cacheAuthKeyClientInfo(authKeyID, clientSessionInfoFromAuthKeyClientInfo(keyInfo)) if current, ok := r.cachedAuthKeyLayerDefault(authKeyID); ok { return inheritedAuthKeyLayerResult{layer: current, found: true}, nil } if keyInfo.Layer != 0 { if !isSupportedLayer(keyInfo.Layer) { r.cacheAuthKeyClientInfo(authKeyID, clientSessionInfo{layerBlocked: true, layerBlockedByAuthKey: true}) return inheritedAuthKeyLayerResult{found: true}, nil } return inheritedAuthKeyLayerResult{layer: keyInfo.Layer, found: true}, nil } } else { r.cacheAuthKeyClientInfo(authKeyID, clientSessionInfo{authKeyInfoChecked: true}) } // auth_keys.layer is the only protocol authority. A zero value means no // default exists yet; authorization.layer is a materialized device-list // projection and must never be promoted back into wire evidence. return inheritedAuthKeyLayerResult{}, nil }) if err != nil { return 0, false, err } if current, ok := r.cachedAuthKeyLayerDefault(authKeyID); ok { return current, true, nil } result := v.(inheritedAuthKeyLayerResult) return result.layer, result.found, nil } // resolveDurableAuthKeyLayerDefault deliberately re-reads auth_keys for each // new logical session. A process-local cache has no way to observe a newer // observation committed by another server process; using it as authority would // make new sessions inherit an old supported Layer forever (and could hide a // future authoritative Layer). singleflight only coalesces the concurrent // startup burst; it does not turn the result into an unbounded authority. func (r *Router) resolveDurableAuthKeyLayerDefault(ctx context.Context, authKeyID [8]byte) (int, bool, error) { if r.deps.Auth == nil { return 0, false, nil } v, err, _ := r.authUserSF.Do(durableInheritedAuthKeyLayerSingleflightPrefix+string(authKeyID[:]), func() (any, error) { keyInfo, keyFound, err := r.deps.Auth.AuthKeyClientInfo(ctx, authKeyID) if err != nil { return inheritedAuthKeyLayerResult{}, err } if keyFound { parsed := clientSessionInfoFromAuthKeyClientInfo(keyInfo) r.cacheAuthKeyClientInfo(authKeyID, parsed) if keyInfo.Layer != 0 { if !isSupportedLayer(keyInfo.Layer) { return inheritedAuthKeyLayerResult{found: true}, nil } return inheritedAuthKeyLayerResult{layer: keyInfo.Layer, found: true}, nil } } // Do not normalize old authorization mirrors on read. Missing primary // evidence stays unknown until a selector advances auth_keys explicitly; // any legacy repair belongs in an audited migration. return inheritedAuthKeyLayerResult{}, nil }) if err != nil { return 0, false, err } result := v.(inheritedAuthKeyLayerResult) return result.layer, result.found, nil } func (r *Router) cachedAuthKeyLayerDefault(authKeyID [8]byte) (int, bool) { r.clientInfoMu.RLock() layer := r.authInfo[authKeyID].layer r.clientInfoMu.RUnlock() return layer, isSupportedLayer(layer) } func (r *Router) cachedAuthKeyLayerResolution(authKeyID [8]byte) (layer int, found, resolved bool) { r.clientInfoMu.RLock() info, ok := r.authInfo[authKeyID] r.clientInfoMu.RUnlock() if !ok { return 0, false, false } if isSupportedLayer(info.layer) { return info.layer, true, true } if info.layerBlocked { return 0, true, true } if info.authKeyInfoChecked { return 0, false, true } return 0, false, false } func (r *Router) cacheAuthKeyClientInfo(authKeyID [8]byte, info clientSessionInfo) { r.clientInfoMu.Lock() r.rememberAuthClientInfoLocked(authKeyID, info) r.clientInfoMu.Unlock() } func (r *Router) setAuthKeyLayerDefaults(layer int, authKeyIDs ...[8]byte) { if !isSupportedLayer(layer) { return } r.clientInfoMu.Lock() for _, authKeyID := range authKeyIDs { r.rememberAuthClientLayerLocked(authKeyID, layer) } r.clientInfoMu.Unlock() } func (r *Router) persistAuthKeyLayerDefaults(ctx context.Context, layer int, authKeyIDs ...[8]byte) { if r == nil || r.deps.Auth == nil || !isSupportedLayer(layer) { return } seen := make(map[[8]byte]struct{}, len(authKeyIDs)) for _, authKeyID := range authKeyIDs { if authKeyID == ([8]byte{}) { continue } if _, ok := seen[authKeyID]; ok { continue } seen[authKeyID] = struct{}{} if err := r.deps.Auth.UpdateAuthKeyClientInfo(ctx, authKeyID, domain.AuthKeyClientInfo{Layer: layer}); err != nil && r.log != nil { r.log.Warn("persist inherited auth key layer default failed", zap.String("auth_key_id", fmt.Sprintf("%x", authKeyID[:])), zap.Int("layer", layer), zap.Error(err)) } } } func isSupportedLayer(layer int) bool { if layer <= 0 { return false } profile, ok := tlprofile.ResolveProfile(layer) return ok && int(profile) == layer }