mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-12 20:15:10 +00:00
feat(service): add wait_for_approval and return the cache for a login with no prompt
A pair code shown in a log line never answers a prompt, so the server read that login as anonymous and kept the session cache.
This commit is contained in:
@@ -256,6 +256,24 @@ REST download job shows it as `input_prompt`. Locally it routes through the
|
||||
shared Rich console (`prompt_user`) so the prompt renders correctly alongside
|
||||
progress and log output.
|
||||
|
||||
For a login that the user approves on another device (a pair code, a QR code),
|
||||
use `self.wait_for_approval(message, check, timeout)`, never a hand-written
|
||||
loop. It shows the message, then calls `check` at each interval until `check`
|
||||
returns a value. `check` returns `None` while the approval is pending.
|
||||
|
||||
```python
|
||||
token = self.wait_for_approval(
|
||||
f"Open {self.config['endpoints']['pair']} and enter code {code}",
|
||||
check=lambda: self.poll_pair_token(code),
|
||||
timeout=expires_in,
|
||||
)
|
||||
```
|
||||
|
||||
It raises `TimeoutError` after `timeout` seconds. Under `serve` mode it also stops
|
||||
when the client deletes the remote session, so the loop does not continue on the
|
||||
server with no client. The message goes out as a log line, so a remote
|
||||
session shows it, but a REST download job does not relay it as `input_prompt`.
|
||||
|
||||
!!! warning "Make each token cache entry unique"
|
||||
The cache above uses `tokens_{device}_{profile}` on purpose. A token cache
|
||||
must include every dimension that changes the token (device, profile, or
|
||||
|
||||
@@ -957,7 +957,7 @@ The `proxy` value must be a full proxy URI, unless the operator gives your API k
|
||||
}
|
||||
```
|
||||
|
||||
`server_account` is `true` when the server authenticated with one of its own accounts (`serve.server_accounts`). Otherwise the server uses only what the client sent, and never falls back to its own credentials. Only a client that sent its own cookies, credentials, or cache files gets cookies, auth headers, and the remote session cache back. A client that answered a login prompt (a device code or an OTP) gets them too. This applies only when the login then succeeds and the remote session does not use a server account. For any other remote session (a server account, or an anonymous login through the server's proxy) the tracks and segments responses carry no cookies and no auth headers. The server also drops secret-looking keys from track data, and the cache stays on the server. A server-account service also refuses a client proxy URI, because the server's login would pass through it.
|
||||
`server_account` is `true` when the server authenticated with one of its own accounts (`serve.server_accounts`). Otherwise the server uses only what the client sent, and never falls back to its own credentials. When the login succeeds and the remote session does not use a server account, the login belongs to the client, and the client gets cookies, auth headers, and the remote session cache back. A remote session on the server's device is the exception: the client gets its cookies back, but no auth headers and no cache. For a server-account remote session the tracks and segments responses carry no cookies and no auth headers. The server also drops secret-looking keys from track data, and the cache stays on the server. A server-account service also refuses a client proxy URI, because the server's login would pass through it.
|
||||
|
||||
| Status | Error code | Meaning |
|
||||
| --- | --- | --- |
|
||||
|
||||
@@ -213,9 +213,9 @@ hood the client walks a remote session through its lifecycle.
|
||||
deletes the remote session. If the login belongs to the client, the `DELETE`
|
||||
request returns the updated cache files (for example a refreshed token) and the
|
||||
client saves them locally, so the **next** remote session can skip interactive
|
||||
authentication. The login belongs to the client when the client sent
|
||||
cookies, credentials, or cache files, or answered a login prompt (a device code
|
||||
or an OTP) that led to a successful login. A server-account login never does,
|
||||
authentication. The login belongs to the client when it succeeds and the
|
||||
remote session does not use a server account. This includes a pair code that
|
||||
the user approves on another device. A server-account login never does,
|
||||
and neither does a remote session on the server's device (see below).
|
||||
The client saves only the returned files that pass the same profile check it
|
||||
applies before it sends them, so a file for another profile cannot overwrite
|
||||
|
||||
@@ -89,6 +89,9 @@ These are abstract. A service will not load unless it defines all three:
|
||||
`get_clearkey_license` (returns `None` by default). See [DRM hooks](#drm-hooks) below.
|
||||
- **`request_input(prompt)`**: prompts the user. It goes through the remote-dl input
|
||||
bridge, the REST download job relay, or the rich console.
|
||||
- **`wait_for_approval(message, check, timeout, interval=3.0)`**: shows a message, then
|
||||
calls `check` until it returns a value. Use it for a login that the user approves on
|
||||
another device, such as a pair code.
|
||||
- **Event callbacks**: `on_segment_downloaded`, `on_track_downloaded`,
|
||||
`on_track_decrypted`, `on_track_repacked`, `on_track_multiplex` let a service react to
|
||||
pipeline events (for example, MonaLisa decrypts each segment in `on_segment_downloaded`).
|
||||
|
||||
Reference in New Issue
Block a user