feat(downloads): per-user, per-host yt-dlp cookie/auth support (S6)
Each user stores their own login cookies (Netscape cookies.txt) for an auth-walled download host (Facebook, Instagram, X, TikTok, Reddit) in Settings; a download of an auth-walled link on that host is retried with the acting user's cookie. Two load-bearing security controls, both in downloads.credentials as the single source of truth so enqueue and the worker can't drift: - cache privacy: a cookie-authed download salts its MediaAsset format_sig with the user id, so the authed asset is private and never cache-served to another user. The worker attaches a cookie ONLY when the asset it is downloading into IS that private, salted identity. - host scope (SEC-12): a cookie is resolved only for a URL whose netloc the credential owns (netloc-scoped _host_is); a look-alike/unrelated host gets none. cookies_enc is Fernet-encrypted at rest, only decrypted in-worker into a 0600 file under staging/.auth/ (survives the retry wipe + _produced_file scan) and unlinked in finally. The blob is never returned by a route, logged, audited, or written to a job's error/snapshot. cookiefile is set after the adapter's extra merge so an adapter can't clobber it. Settings UI is write-only (host + set/updated only, never echoed). New download_credentials table + migration 0074; per-user routes; HU+EN i18n. Tests: host-scope, cache-privacy (no cross-user serve), encrypt-at-rest, write-only API, worker attach-gate; FE dom test for the write-only field.
This commit is contained in:
@@ -17,5 +17,7 @@
|
||||
"sync_pause": "Sync paused",
|
||||
"sync_resume": "Sync resumed",
|
||||
"job_run": "Scheduler job run",
|
||||
"audit_clear": "Audit log cleared"
|
||||
"audit_clear": "Audit log cleared",
|
||||
"download_credential_set": "Download cookies set",
|
||||
"download_credential_delete": "Download cookies removed"
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@
|
||||
},
|
||||
"login_required": {
|
||||
"short": "Sign-in required",
|
||||
"body": "This video needs a signed-in, age-verified, or members-only account to view, so it can't be downloaded here."
|
||||
"body": "This video needs a signed-in account (age-restricted, members-only, or a private group) to view. Add your cookies for this site under Settings → Account → Download authentication to download it."
|
||||
},
|
||||
"unsupported_host": {
|
||||
"short": "Site not supported",
|
||||
@@ -253,6 +253,11 @@
|
||||
"body": "Something went wrong while downloading this item. The technical details below may help."
|
||||
}
|
||||
}
|
||||
},
|
||||
"cookies": {
|
||||
"empty": "Paste your cookies first.",
|
||||
"format": "That doesn't look like a cookies.txt file (Netscape format).",
|
||||
"generic": "Those cookies couldn't be saved."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +104,26 @@
|
||||
"failed": "Couldn't sign out other sessions. Please try again."
|
||||
}
|
||||
},
|
||||
"downloadAuth": {
|
||||
"title": "Download authentication",
|
||||
"intro": "Some sites (e.g. a private Facebook group you belong to) only let logged-in members view a video. Paste your browser cookies for a site here and your downloads from it will use your login. Cookies are encrypted, kept private to your account, and only ever sent to the matching site.",
|
||||
"configured": "Set · updated {{when}}",
|
||||
"notSet": "Not set",
|
||||
"set": "Set cookies",
|
||||
"update": "Update",
|
||||
"remove": "Remove",
|
||||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
"saving": "Saving…",
|
||||
"placeholder": "Paste the contents of your cookies.txt (Netscape format) here",
|
||||
"help": "Export a cookies.txt for this site with a browser extension, then paste it here. It's write-only — we never show it back.",
|
||||
"saved": "Cookies saved.",
|
||||
"removed": "Cookies removed.",
|
||||
"failed": "Couldn't save those cookies.",
|
||||
"removeConfirmTitle": "Remove cookies?",
|
||||
"removeConfirmBody": "Downloads from this site will stop using your login.",
|
||||
"removeConfirmAction": "Remove"
|
||||
},
|
||||
"demo": {
|
||||
"title": "Demo access",
|
||||
"intro": "Emails here can enter the shared demo account straight from the login page — no Google sign-in. They just type the address into the field and are let in after a moment.",
|
||||
|
||||
@@ -17,5 +17,7 @@
|
||||
"sync_pause": "Szinkron szüneteltetve",
|
||||
"sync_resume": "Szinkron folytatva",
|
||||
"job_run": "Ütemező job lefutott",
|
||||
"audit_clear": "Napló ürítve"
|
||||
"audit_clear": "Napló ürítve",
|
||||
"download_credential_set": "Letöltési cookie-k beállítva",
|
||||
"download_credential_delete": "Letöltési cookie-k eltávolítva"
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@
|
||||
},
|
||||
"login_required": {
|
||||
"short": "Bejelentkezés szükséges",
|
||||
"body": "Ehhez a videóhoz bejelentkezett, kor-ellenőrzött vagy tagsági fiók kell, ezért itt nem tölthető le."
|
||||
"body": "Ehhez a videóhoz bejelentkezett fiók kell (korhatáros, csak tagoknak szóló vagy zárt csoport). Töltsd fel a cookie-kat ehhez az oldalhoz a Beállítások → Fiók → Letöltés-hitelesítés alatt a letöltéshez."
|
||||
},
|
||||
"unsupported_host": {
|
||||
"short": "Nem támogatott oldal",
|
||||
@@ -253,6 +253,11 @@
|
||||
"body": "Valami hiba történt az elem letöltése közben. Az alábbi technikai részletek segíthetnek."
|
||||
}
|
||||
}
|
||||
},
|
||||
"cookies": {
|
||||
"empty": "Előbb illeszd be a cookie-kat.",
|
||||
"format": "Ez nem tűnik cookies.txt fájlnak (Netscape formátum).",
|
||||
"generic": "A cookie-kat nem sikerült menteni."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +104,26 @@
|
||||
"failed": "Nem sikerült kijelentkeztetni a többi munkamenetet. Próbáld újra."
|
||||
}
|
||||
},
|
||||
"downloadAuth": {
|
||||
"title": "Letöltés-hitelesítés",
|
||||
"intro": "Egyes oldalak (pl. egy zárt Facebook-csoport, aminek tagja vagy) csak bejelentkezett tagoknak mutatják a videót. Illeszd be ide a böngésződ cookie-jait egy oldalhoz, és az onnan induló letöltések a te bejelentkezésedet használják. A cookie-k titkosítva, csak a te fiókodhoz kötve tárolódnak, és kizárólag az adott oldalnak küldjük el őket.",
|
||||
"configured": "Beállítva · frissítve: {{when}}",
|
||||
"notSet": "Nincs beállítva",
|
||||
"set": "Cookie-k beállítása",
|
||||
"update": "Frissítés",
|
||||
"remove": "Eltávolítás",
|
||||
"save": "Mentés",
|
||||
"cancel": "Mégse",
|
||||
"saving": "Mentés…",
|
||||
"placeholder": "Illeszd be ide a cookies.txt tartalmát (Netscape formátum)",
|
||||
"help": "Exportálj cookies.txt-t ehhez az oldalhoz egy böngészőbővítménnyel, majd illeszd be ide. Csak írható — sosem mutatjuk vissza.",
|
||||
"saved": "Cookie-k mentve.",
|
||||
"removed": "Cookie-k eltávolítva.",
|
||||
"failed": "A cookie-kat nem sikerült menteni.",
|
||||
"removeConfirmTitle": "Cookie-k eltávolítása?",
|
||||
"removeConfirmBody": "Az erről az oldalról induló letöltések nem használják tovább a bejelentkezésedet.",
|
||||
"removeConfirmAction": "Eltávolítás"
|
||||
},
|
||||
"demo": {
|
||||
"title": "Demo hozzáférés",
|
||||
"intro": "Az itt szereplő e-mailek a bejelentkező oldalról közvetlenül beléphetnek a közös demo fiókba — Google-bejelentkezés nélkül. Csak beírják a címet a mezőbe, és pár pillanat múlva bekerülnek.",
|
||||
|
||||
Reference in New Issue
Block a user