mirror of
https://github.com/CyberMind-FR/secubox-deb.git
synced 2026-07-30 07:05:20 +00:00
Merge pull request #408 from CyberMind-FR/feature/407-privilege-separated-cookie-install-root
Privilege-separated cookie install: root path-unit (no sudo, CSPN) (#407)
This commit is contained in:
commit
b43a67b098
|
|
@ -489,39 +489,22 @@ def _save_cred_state(state: Dict[str, Any]):
|
|||
|
||||
|
||||
def _apply_youtube(poke: CredPoke) -> Dict[str, str]:
|
||||
"""Install YouTube creds into PeerTube. Cookies use the existing, working
|
||||
sudo `peertubectl set-youtube-cookies` path (#388). PO-token application is
|
||||
experimental (needs the peertubectl set-youtube-potoken verb + browser
|
||||
capture, #401 P4) — stored + reported, applied when that lands."""
|
||||
"""Apply YouTube creds to PeerTube. The avatar daemon stays UNPRIVILEGED
|
||||
(CSPN): it writes the cookies to the spool and the root
|
||||
peertube-cookie-install.path/.service installs them into the LXC (#407) —
|
||||
no sudo, NoNewPrivileges intact. PO-token application is experimental and
|
||||
pending the browser capture + a peertubectl verb (#401 P4)."""
|
||||
results: Dict[str, str] = {}
|
||||
if poke.cookies:
|
||||
try:
|
||||
with open(_PT_COOKIE_SPOOL, "w") as f:
|
||||
f.write(poke.cookies)
|
||||
os.chmod(_PT_COOKIE_SPOOL, 0o600)
|
||||
r = subprocess.run(
|
||||
["sudo", "-n", _PEERTUBECTL, "set-youtube-cookies", _PT_COOKIE_SPOOL],
|
||||
capture_output=True, text=True, timeout=90,
|
||||
)
|
||||
results["cookies"] = "ok" if r.returncode == 0 else (r.stderr or r.stdout or "failed").strip()
|
||||
results["cookies"] = "queued" # root path-unit installs + restarts PeerTube
|
||||
except Exception as e:
|
||||
results["cookies"] = f"error: {e}"
|
||||
finally:
|
||||
try:
|
||||
os.remove(_PT_COOKIE_SPOOL)
|
||||
except OSError:
|
||||
pass
|
||||
if poke.po_token:
|
||||
# Experimental: applied once peertubectl gains set-youtube-potoken (P4).
|
||||
if os.path.exists(_PEERTUBECTL):
|
||||
r = subprocess.run(
|
||||
["sudo", "-n", _PEERTUBECTL, "set-youtube-potoken",
|
||||
poke.po_token, poke.visitor_data or ""],
|
||||
capture_output=True, text=True, timeout=30,
|
||||
)
|
||||
results["po_token"] = "ok" if r.returncode == 0 else "pending (peertubectl verb not deployed)"
|
||||
else:
|
||||
results["po_token"] = "pending"
|
||||
results["po_token"] = "pending" # P4: browser PO-token relay not wired yet
|
||||
return results
|
||||
|
||||
|
||||
|
|
@ -568,7 +551,10 @@ async def cred_poke(service: str, poke: CredPoke, user=Depends(require_jwt)):
|
|||
"by": user.get("sub", "?"),
|
||||
}
|
||||
_save_cred_state(state)
|
||||
ok = bool(results) and all(v == "ok" for v in results.values())
|
||||
# Cookies are the primary credential ("queued" = handed to the root installer);
|
||||
# an experimental po_token "pending" must not fail the poke.
|
||||
cstat = results.get("cookies")
|
||||
ok = cstat in ("ok", "queued") or (not poke.cookies and results.get("po_token") == "ok")
|
||||
return {"success": ok, "service": service, "results": results}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -476,21 +476,20 @@ async def import_video(req: VideoImport, user=Depends(require_jwt)):
|
|||
return {"success": False, "error": result.get("error", "import failed")}
|
||||
|
||||
|
||||
# Spool path the dashboard (secubox) can write and that the narrowly-scoped
|
||||
# sudoers rule lets peertubectl read as root (see debian/secubox-peertube.sudoers).
|
||||
# Spool the dashboard (unprivileged secubox) writes; the root-run
|
||||
# peertube-cookie-install.path/.service (#407) applies it — no sudo here (CSPN).
|
||||
COOKIES_SPOOL = "/run/secubox/peertube-yt-cookies.txt"
|
||||
|
||||
|
||||
@router.post("/import/cookies")
|
||||
async def import_cookies(request: Request, user=Depends(require_jwt)):
|
||||
"""Install operator-supplied YouTube cookies (Netscape format) so yt-dlp
|
||||
import can fetch YouTube. Body = the cookies.txt text (the SecuBox
|
||||
WebExtension reads them from the logged-in browser and POSTs here, #401).
|
||||
"""Queue operator-supplied YouTube cookies (Netscape format) for the import
|
||||
pipeline. Body = the cookies.txt text (the SecuBox WebExtension / avatar
|
||||
broker reads them from the logged-in browser and POSTs here, #401/#402).
|
||||
|
||||
The dashboard runs unprivileged (secubox); it spools the body to
|
||||
COOKIES_SPOOL then escalates via a single narrowly-scoped sudoers rule to
|
||||
`peertubectl set-youtube-cookies`, which writes them into the LXC + enables
|
||||
the feature + restarts PeerTube."""
|
||||
The dashboard stays unprivileged: it writes the spool, and the root
|
||||
peertube-cookie-install.path watches it and installs them into the LXC +
|
||||
restarts PeerTube (#407). No sudo, NoNewPrivileges intact."""
|
||||
body = (await request.body()).decode("utf-8", "replace")
|
||||
if "\t" not in body or "youtube" not in body.lower():
|
||||
return {"success": False, "error": "body is not a Netscape youtube cookies file"}
|
||||
|
|
@ -500,25 +499,9 @@ async def import_cookies(request: Request, user=Depends(require_jwt)):
|
|||
os.chmod(COOKIES_SPOOL, 0o600)
|
||||
except Exception as e:
|
||||
return {"success": False, "error": f"spool write failed: {e}"}
|
||||
log.info(f"Installing YouTube cookies ({len(body)} bytes) by {user.get('sub', 'unknown')}")
|
||||
try:
|
||||
r = subprocess.run(
|
||||
["sudo", "-n", PEERTUBECTL, "set-youtube-cookies", COOKIES_SPOOL],
|
||||
capture_output=True, text=True, timeout=90,
|
||||
)
|
||||
ok = r.returncode == 0
|
||||
return {"success": ok,
|
||||
"message": "cookies installed; PeerTube restarting" if ok else None,
|
||||
"error": None if ok else (r.stderr or r.stdout or "install failed").strip()}
|
||||
except subprocess.TimeoutExpired:
|
||||
return {"success": False, "error": "timeout"}
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
finally:
|
||||
try:
|
||||
os.remove(COOKIES_SPOOL)
|
||||
except OSError:
|
||||
pass
|
||||
log.info(f"Queued YouTube cookies ({len(body)} bytes) by {user.get('sub', 'unknown')}")
|
||||
return {"success": True,
|
||||
"message": "cookies queued; installing into the LXC + restarting PeerTube shortly"}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ Standards-Version: 4.6.2
|
|||
Package: secubox-peertube
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}, secubox-core (>= 1.0), python3-uvicorn | python3-pip,
|
||||
lxc, lxc-templates, nftables, openssl, sudo
|
||||
lxc, lxc-templates, nftables, openssl
|
||||
Description: SecuBox PeerTube — federated video platform (native LXC)
|
||||
Dashboard + FastAPI backend for a PeerTube video-hosting instance
|
||||
installed NATIVELY inside a dedicated Debian LXC (its own
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
[Unit]
|
||||
Description=Watch for spooled YouTube cookies to install into the PeerTube LXC
|
||||
Documentation=https://github.com/CyberMind-FR/secubox-deb/issues/407
|
||||
|
||||
[Path]
|
||||
# An unprivileged dashboard (secubox-peertube / secubox-avatar) drops the
|
||||
# Netscape cookies here; this root-run service installs them — no sudo, so the
|
||||
# dashboards keep NoNewPrivileges (CSPN privilege separation).
|
||||
PathChanged=/run/secubox/peertube-yt-cookies.txt
|
||||
Unit=peertube-cookie-install.service
|
||||
|
||||
[Install]
|
||||
WantedBy=paths.target
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
[Unit]
|
||||
Description=Install spooled YouTube cookies into the PeerTube LXC (root, #407)
|
||||
Documentation=https://github.com/CyberMind-FR/secubox-deb/issues/407
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
# Runs as root (no User=) so peertubectl can lxc-attach into the container.
|
||||
# Installs the spooled cookies, then removes the spool (sensitive + avoids
|
||||
# re-triggering the watching .path unit).
|
||||
ExecStart=/usr/sbin/peertubectl set-youtube-cookies /run/secubox/peertube-yt-cookies.txt
|
||||
ExecStartPost=-/bin/rm -f /run/secubox/peertube-yt-cookies.txt
|
||||
|
|
@ -58,6 +58,8 @@ if [ "$1" = "configure" ]; then
|
|||
systemctl enable secubox-peertube.service || true
|
||||
systemctl start secubox-peertube.service || true
|
||||
fi
|
||||
# Root path-unit (#407) that installs spooled YouTube cookies without sudo.
|
||||
systemctl enable --now peertube-cookie-install.path 2>/dev/null || true
|
||||
|
||||
# Reload nginx to pick up the /api/v1/peertube/ + /peertube/ locations
|
||||
# and the public vhost. NOTE: PeerTube itself is NOT installed by this
|
||||
|
|
|
|||
|
|
@ -32,9 +32,9 @@ override_dh_auto_install:
|
|||
# Config example
|
||||
install -d debian/secubox-peertube/etc/secubox
|
||||
[ -f conf/peertube.toml.example ] && cp conf/peertube.toml.example debian/secubox-peertube/etc/secubox/peertube.toml.example || true
|
||||
# Systemd service (host dashboard daemon)
|
||||
# Systemd units: the unprivileged dashboard daemon + the root cookie-install
|
||||
# path-unit (#407) that applies spooled cookies without sudo (CSPN).
|
||||
install -d debian/secubox-peertube/usr/lib/systemd/system
|
||||
install -m 644 debian/secubox-peertube.service debian/secubox-peertube/usr/lib/systemd/system/
|
||||
# sudoers: narrowly-scoped escalation for the cookie-relay (#401)
|
||||
install -d debian/secubox-peertube/etc/sudoers.d
|
||||
install -m 0440 debian/secubox-peertube.sudoers debian/secubox-peertube/etc/sudoers.d/secubox-peertube
|
||||
install -m 644 debian/peertube-cookie-install.path debian/secubox-peertube/usr/lib/systemd/system/
|
||||
install -m 644 debian/peertube-cookie-install.service debian/secubox-peertube/usr/lib/systemd/system/
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ Restart=on-failure
|
|||
RestartSec=5
|
||||
UMask=0000
|
||||
|
||||
# NoNewPrivileges intentionally NOT set: the dashboard escalates via a single
|
||||
# narrowly-scoped sudoers rule (peertubectl set-youtube-cookies) to install
|
||||
# operator-supplied YouTube cookies into the LXC. NoNewPrivileges=true would
|
||||
# block sudo. See debian/secubox-peertube.sudoers.
|
||||
# CSPN: the dashboard stays unprivileged. Cookie installs are spooled to
|
||||
# /run/secubox/peertube-yt-cookies.txt and applied by the root-run
|
||||
# peertube-cookie-install.path/.service (#407) — no sudo needed here.
|
||||
NoNewPrivileges=true
|
||||
RuntimeDirectory=secubox
|
||||
RuntimeDirectoryPreserve=yes
|
||||
RuntimeDirectoryMode=0775
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
# Installed at /etc/sudoers.d/secubox-peertube (mode 0440).
|
||||
#
|
||||
# Lets the unprivileged dashboard user (secubox) install operator-supplied
|
||||
# YouTube cookies into the PeerTube LXC, for the WebExtension/dashboard cookie
|
||||
# relay (#401). Tightly scoped: one command + one fixed spool path — the
|
||||
# dashboard writes the Netscape cookies body to /run/secubox/peertube-yt-cookies.txt
|
||||
# then runs exactly this command, which copies them into the LXC, enables the
|
||||
# import cookies feature, and restarts PeerTube.
|
||||
secubox ALL=(root) NOPASSWD: /usr/sbin/peertubectl set-youtube-cookies /run/secubox/peertube-yt-cookies.txt
|
||||
Loading…
Reference in New Issue
Block a user