qconnect: Rust backstop validates per-track origins server-side
v2_qconnect_send_command_with_admission trusted a single frontend origin and never inspected track_ids. Add track_origins[] to the request and validate_track_origins_for_admission: re-evaluate every track via the core gate, block if any is non-Qobuz or the list is empty. The per-track check is only enforced when the caller actually ships per-track origins (bulk queue loads); single-track play-next/play-later carry no track_origins and stay gated by the command-level origin alone, so an empty list never over-blocks them. The existing command-level check and admission_blocked emit are kept. Frontend loadQconnectQueue now computes per-track origins from its tracks arg via resolveQconnectTrackOrigin and ships them to the sender. Defers the optional DB cross-check (LibraryState / has_local_track_by_qobuz_id defense-in-depth) as a follow-up; this commit is the per-track-origins validator + wiring + test only. cc
This commit is contained in:
4 files changed
+67
-5
No files matched your search
@@ -202,12 +202,14 @@ async function resolveQconnectPlayNextInsertAfterFromSnapshots(): Promise<Qconne
|
||||
async function sendQconnectQueueCommandWithAdmission(
|
||||
commandType: QconnectQueueCommandType,
|
||||
origin: QconnectTrackOrigin,
|
||||
payload: Record<string, unknown>
|
||||
payload: Record<string, unknown>,
|
||||
trackOrigins: QconnectTrackOrigin[] = []
|
||||
): Promise<void> {
|
||||
await invoke('v2_qconnect_send_command_with_admission', {
|
||||
request: {
|
||||
command_type: commandType,
|
||||
origin,
|
||||
track_origins: trackOrigins,
|
||||
payload
|
||||
}
|
||||
});
|
||||
@@ -610,8 +612,15 @@ export async function loadQconnectQueue(
|
||||
preview_track_ids: trackIds.slice(0, 8),
|
||||
payload
|
||||
});
|
||||
// Per-track origins for the Rust backstop (fix #3): when backend-shaped
|
||||
// tracks are supplied, ship each track's resolved origin so the server gate
|
||||
// can re-validate every id, not just the command-level origin. Bare id-only
|
||||
// callers send none and stay gated by the command-level origin alone.
|
||||
const trackOrigins = tracks
|
||||
? tracks.map((tr) => resolveQconnectTrackOrigin(tr, tr.is_local ?? false))
|
||||
: [];
|
||||
console.log('[QConnect/LoadQueue] sending queue_load_tracks');
|
||||
await sendQconnectQueueCommandWithAdmission('queue_load_tracks', origin, payload);
|
||||
await sendQconnectQueueCommandWithAdmission('queue_load_tracks', origin, payload, trackOrigins);
|
||||
console.log('[QConnect/LoadQueue] SUCCESS');
|
||||
|
||||
// Sync local autoplay preference to QConnect server after queue load
|
||||
|
||||
Reference in new issue
Block a user