GooDrive/backend/drive/google_shortcuts.py
Louis Mazin f0fbefa642 nickel
2026-10-14 19:24:07 +02:00

63 lines
3.2 KiB
Python

"""Safe previews for Google Drive Desktop shortcut files (.gdoc/.gsheet/.gslides).
Google-native documents are not stored inside these shortcuts. The preview
opens the linked document on Google with its normal Google permissions.
"""
from html import escape
import json
from pathlib import Path
import re
from urllib.parse import parse_qs, urlsplit
SHORTCUT_TYPES = {
'.gdoc': ('document', 'Google Docs'),
'.gsheet': ('spreadsheets', 'Google Sheets'),
'.gslides': ('presentation', 'Google Slides'),
}
MAX_SHORTCUT_SIZE = 64 * 1024
GOOGLE_ID = re.compile(r'^[A-Za-z0-9_-]{10,}$')
def google_shortcut_url(path):
"""Read a tiny Google shortcut and reject untrusted/off-domain redirects."""
path = Path(path)
subtype, _ = SHORTCUT_TYPES.get(path.suffix.lower(), (None, None))
if subtype is None or path.stat().st_size > MAX_SHORTCUT_SIZE:
raise ValueError('Fichier Google incompatible.')
try:
data = json.loads(path.read_text(encoding='utf-8-sig'))
url = data['url']
except (OSError, ValueError, KeyError, TypeError, UnicodeError) as exc:
raise ValueError('Raccourci Google illisible.') from exc
if not isinstance(url, str) or len(url) > 4096:
raise ValueError('URL Google invalide.')
parsed = urlsplit(url)
if parsed.scheme != 'https' or parsed.username or parsed.password or parsed.port or parsed.fragment:
raise ValueError('Lien Google non autorisé.')
if parsed.hostname == 'docs.google.com':
prefix = f'/{subtype}/d/'
if not parsed.path.startswith(prefix):
raise ValueError('Lien Google incompatible avec le document.')
doc_id = parsed.path[len(prefix):].split('/')[0]
if not GOOGLE_ID.fullmatch(doc_id):
raise ValueError('ID Google incorrect.')
elif parsed.hostname == 'drive.google.com' and parsed.path == '/open':
doc_id = parse_qs(parsed.query).get('id', [''])[0]
if not GOOGLE_ID.fullmatch(doc_id):
raise ValueError('ID Google incorrect.')
else:
raise ValueError('Lien Google non autorisé.')
return url
def render_google_shortcut(path):
url = google_shortcut_url(path)
label = SHORTCUT_TYPES[Path(path).suffix.lower()][1]
return ('''<!doctype html><html lang="fr"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style>
*{box-sizing:border-box}body{margin:0;min-height:100vh;display:grid;place-items:center;background:#f4f6fa;color:#262d3d;font:15px/1.5 system-ui,sans-serif;padding:24px}
main{width:min(100%,520px);text-align:center;background:#fff;border:1px solid #e1e5f0;border-radius:18px;padding:36px 24px;box-shadow:0 8px 25px #1321420d}
h1{font-size:22px}p{color:#657082}a{display:inline-block;margin-top:14px;background:#465a9a;color:#fff;padding:12px 20px;border-radius:10px;text-decoration:none;font-weight:600}</style></head><body><main>
<h1>''' + escape(label) + '''</h1><p>Ce fichier est un raccourci Google. Son contenu reste hébergé sur Google Drive.</p>
<a href="''' + escape(url, quote=True) + '''" target="_blank" rel="noopener noreferrer">Ouvrir sur Google</a>
<p>L'accès dépend des autorisations du document Google.</p></main></body></html>''')