87 lines
2.9 KiB
Go
87 lines
2.9 KiB
Go
package mtprotoedge
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/iamxvbaba/td/bin"
|
|
"github.com/iamxvbaba/td/proto"
|
|
"github.com/iamxvbaba/td/tg"
|
|
)
|
|
|
|
const (
|
|
destroyAuthKeyRequestTypeID = 0xd1435160
|
|
destroyAuthKeyOkTypeID = 0xf660e1d4
|
|
destroyAuthKeyFailTypeID = 0xea109b13
|
|
)
|
|
|
|
var errDestroyAuthKeyMustBeExclusive = errors.New("wrapped destroy_auth_key must be the only logical message")
|
|
|
|
// wrappedDestroyAuthKeyTerminal accepts only evidence emitted by the generated
|
|
// exact wrapper parser after it has legally reached the innermost non-API
|
|
// terminal. It never re-parses wrapper bytes at runtime.
|
|
func wrappedDestroyAuthKeyTerminal(err error) (*tg.LayerRPCUnknownTerminalError, bool) {
|
|
var terminal *tg.LayerRPCUnknownTerminalError
|
|
if !errors.As(err, &terminal) || terminal == nil || terminal.WireID != destroyAuthKeyRequestTypeID {
|
|
return nil, false
|
|
}
|
|
return terminal, true
|
|
}
|
|
|
|
// validWrappedDestroyAuthKeyChain is deliberately narrower than "some generated
|
|
// wrapper decoded". invokeAfter*, takeout and update-suppression wrappers carry
|
|
// execution semantics which the service-message fast path must not silently
|
|
// discard. The official first-connection path is exactly
|
|
// invokeWithLayer(initConnection(destroy_auth_key)); an already initialized
|
|
// connection sends the bare service message and is classified before Layer RPC
|
|
// admission.
|
|
func validWrappedDestroyAuthKeyChain(terminal *tg.LayerRPCUnknownTerminalError) bool {
|
|
if terminal == nil || terminal.WrapperCount() != 2 {
|
|
return false
|
|
}
|
|
outer, outerOK := terminal.Wrapper(0)
|
|
inner, innerOK := terminal.Wrapper(1)
|
|
return outerOK && innerOK &&
|
|
outer.Profile() == terminal.Profile &&
|
|
inner.Profile() == terminal.Profile &&
|
|
outer.Semantic() == tg.LayerSemanticMethodInvokeWithLayer &&
|
|
inner.Semantic() == tg.LayerSemanticMethodInitConnection
|
|
}
|
|
|
|
type destroyAuthKeyRequest struct{}
|
|
|
|
func (*destroyAuthKeyRequest) Encode(b *bin.Buffer) error {
|
|
b.PutID(destroyAuthKeyRequestTypeID)
|
|
return nil
|
|
}
|
|
|
|
func (*destroyAuthKeyRequest) Decode(b *bin.Buffer) error {
|
|
if err := b.ConsumeID(destroyAuthKeyRequestTypeID); err != nil {
|
|
return fmt.Errorf("decode destroy_auth_key: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// destroyAuthKeyRPCResult is the only rpc_result envelope admitted as a
|
|
// layer-invariant control value. Its closed result set is part of the type, so
|
|
// it can never smuggle a profile-dependent API payload past the exact Layer
|
|
// binding boundary.
|
|
type destroyAuthKeyRPCResult struct {
|
|
RequestMessageID int64
|
|
ResultTypeID uint32
|
|
}
|
|
|
|
func (r *destroyAuthKeyRPCResult) Encode(b *bin.Buffer) error {
|
|
if r == nil {
|
|
return fmt.Errorf("encode destroy_auth_key rpc_result: nil result")
|
|
}
|
|
switch r.ResultTypeID {
|
|
case destroyAuthKeyOkTypeID, destroyAuthKeyFailTypeID:
|
|
default:
|
|
return fmt.Errorf("encode destroy_auth_key rpc_result: invalid inner constructor %#x", r.ResultTypeID)
|
|
}
|
|
b.PutID(proto.ResultTypeID)
|
|
b.PutLong(r.RequestMessageID)
|
|
b.PutID(r.ResultTypeID)
|
|
return nil
|
|
}
|