63 lines
3.2 KiB
Python
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>''')
|