Skip to content

feat: add signed SABR compatibility profiles#89

Open
Priveetee wants to merge 4 commits into
InfinityLoop1308:mainfrom
Priveetee:feat/sabr-compatibility-profile
Open

feat: add signed SABR compatibility profiles#89
Priveetee wants to merge 4 commits into
InfinityLoop1308:mainfrom
Priveetee:feat/sabr-compatibility-profile

Conversation

@Priveetee

@Priveetee Priveetee commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

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

signed JSON document
  -> strict parser and structural limits
  -> Ed25519 verification and revision checks
  -> immutable WEB/MWEB profile
  -> CompatibilitySabrSessionPolicy
  -> SabrSessionPolicyHost
  -> YoutubeSabrSession

SabrCompatibilityProfileParser accepts a strict UTF-8 document with a 1 MiB size limit, bounded nesting and no unknown properties. SabrCompatibilityProfileValidator checks every client, request field, response mapping, recovery rule and capability before a profile can become active.

SabrCompatibilityProfileManager verifies Ed25519 signatures against an identified embedded public key. The signature covers SabrCompatibilityProfile.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. CompatibilitySabrSessionPolicy selects WEB or MWEB once when the session receives its first request. A document can cover only one client: the omitted client continues using BuiltinSabrSessionPolicy without 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:

  • player time and buffered ranges
  • playback cookie and PO token
  • selected and preferred formats
  • client context and client ABR state
  • ustreamer configuration

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:

  • next-request timing and backoff
  • playback state, redirect, reload, error and protection signals
  • normalized media-header fields
  • WEB or MWEB media header, payload and end part types

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. YoutubeSabrSession still owns:

  • HTTP requests and URL validation
  • player and video-bound token use
  • playback cookies and selected formats
  • UMP streaming and media collection
  • redirects, retries, reloads and token refresh
  • playhead, buffered ranges and request generations
  • cache growth, demand routing, seeks and cancellation

SabrSessionPolicyHost validates 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

FallbackSabrSessionPolicy is 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

  • add strict compatibility-profile document, parser, validator and immutable domain types
  • add deterministic serialization, Ed25519 verification, key rotation and monotonic revision activation
  • add declarative request templates for initial and following WEB/MWEB requests
  • add bounded response mappings for UMP state and media headers
  • add declarative recovery predicates and actions
  • add profile-backed media protocol selection and a native circuit breaker
  • pass the complete native request context through SabrSessionPolicy
  • preserve the existing YoutubeSabrSession transport and state machine
  • allow WEB as an explicit YouTube player client
  • remove the unfinished JavaScript policy API and its documentation
  • document the profile format, trust boundary and compatibility limits

Compatibility 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 check
  • git diff --check
  • compilation against the PipePipe Client integration
  • signed WEB and MWEB profiles exercised through real Android playback
  • request-field, UMP part-type and media-header field changes replayed through the existing SABR session engine
  • broken required mappings verified to trip the circuit breaker and recover through the bundled policy

Delivery 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant