feat: add signed SABR compatibility profiles#89
Open
Priveetee wants to merge 4 commits into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This is my idea of how we can deal with future SABR changes without having to release a new Extractor and app version every time YouTube moves a field or changes a small part of the protocol.
I first looked at extending the JavaScript policy work, but I think it gives the downloaded policy the wrong shape: either the runtime is privileged enough to duplicate a large part of the native SABR engine, or it is restricted enough that every useful change still needs a new bridge API and a release.
This PR replaces that path with signed declarative compatibility profiles. A profile describes the volatile WEB and MWEB parts of SABR while the Extractor keeps transport, tokens, UMP framing, media assembly, state transitions and limits in native code.
This is the Extractor half of the first complete implementation. The Android delivery and persistence lifecycle is handled separately in PipePipe Client.
Architecture
SabrCompatibilityProfileParseraccepts a strict UTF-8 document with a 1 MiB size limit, bounded nesting and no unknown properties.SabrCompatibilityProfileValidatorchecks every client, request field, response mapping, recovery rule and capability before a profile can become active.SabrCompatibilityProfileManagerverifies Ed25519 signatures against an identified embedded public key. The signature coversSabrCompatibilityProfile.serialize(), a deterministic binary representation that uses stable string identifiers instead of Java enum ordinals. It also checks the validity interval, document format, minimum Extractor revision, supported capabilities and a monotonic positive revision.The active profile is immutable.
CompatibilitySabrSessionPolicyselects WEB or MWEB once when the session receives its first request. A document can cover only one client: the omitted client continues usingBuiltinSabrSessionPolicywithout invalidating the document.What a profile can change
Request templates are separate for the initial and following SABR requests. Each entry selects a protobuf field number, wire type, required flag and one native value source:
The profile receives only the already encoded value selected by the native host. It cannot access the underlying cookie, token or mutable playback state directly. Generated requests remain under the native 256 KiB limit.
Response mappings associate a UMP part type and a bounded protobuf field path with a normalized native target. This covers:
Media payload bytes are never exposed to the profile. They continue through the existing streaming collector and cache path.
Recovery remains declarative as well. A rule combines known predicates with known actions and must end in one terminal action. There are no loops or arbitrary callbacks, and omission, elapsed-time, forward-seek and retry values stay inside native bounds.
Native ownership
The profile is data, not a second SABR implementation.
YoutubeSabrSessionstill owns:SabrSessionPolicyHostvalidates decisions again before committing state. A profile cannot perform network requests, execute code, inspect process state, allocate unbounded data or introduce a new action that the Extractor does not already understand.Failure handling
FallbackSabrSessionPolicyis a session-local circuit breaker around the profiled policy. If request construction, response interpretation or demand routing fails, the session disables that profile and falls back to the bundled policy.Media framing is selected once for a response. If a profiled media-header decode fails, the profile is disabled and the failure remains recoverable so the native session can retry without mixing two framing contracts inside the same response.
The bundled behavior therefore remains both the default when no valid profile is supplied and the recovery path when a signed profile is incompatible with a real response.
Changes
SabrSessionPolicyYoutubeSabrSessiontransport and state machineCompatibility boundary
This can handle changes to known request fields, response field paths, protobuf wire types, UMP media part numbers, recovery thresholds and combinations of existing native actions.
It cannot introduce a new transport, cryptographic primitive, token flow, media framing model or host capability. Those are structural changes and still require an Extractor release. The goal is to cover the frequent protocol-layout changes without pretending every possible YouTube change can be represented as configuration.
Client integration
The PipePipe Client change handles profile delivery, persistence, revision floors and activation. This Extractor PR only defines the signed document contract, its native evaluator and the session fallback boundary.
The complete download, cache, stable/beta channel and rollback lifecycle will be documented in the Client PR. Without a valid profile supplied by a caller, the Extractor continues using the bundled builtin policy.
Validation
./gradlew --no-daemon checkgit diff --checkDelivery status
This PR does not publish a profile service, signing key or production document. It only adds the format and native execution boundary. Remote delivery stays disabled unless a caller explicitly provides trusted keys and a valid signed profile.
Related PR