""" Overleaf 自助注册服务 提供简单的注册页面,用户输入邮箱和密码即可注册 内部通过管理员账号调用 Overleaf API 创建用户 """ from fastapi import FastAPI, Request, Form from fastapi.responses import HTMLResponse import requests import os app = FastAPI() OL_URL = os.getenv("OL_INSTANCE", "http://overleaf") OL_ADMIN_EMAIL = os.getenv("OL_ADMIN_EMAIL", "") OL_ADMIN_PASSWORD = os.getenv("OL_ADMIN_PASSWORD", "") REGISTER_HTML = """ 注册 - LaTeX 论文编辑器

注册账号

LaTeX 论文编辑器

已有账号?去登录

MSG_PLACEHOLDER
""".replace("OLURL", OL_URL) class OverleafAdmin: def __init__(self): self.session = requests.Session() self.logged_in = False def _get_csrf(self, path="/login"): resp = self.session.get(f"{OL_URL}{path}") # 从页面中提取 CSRF token import re match = re.search(r'name="_csrf"[^>]*value="([^"]+)"', resp.text) if not match: match = re.search(r'ol-csrfToken["\s]*content="([^"]+)"', resp.text) if not match: match = re.search(r'csrfToken["\s]*:\s*"([^"]+)"', resp.text) return match.group(1) if match else "" def login(self): csrf = self._get_csrf("/login") resp = self.session.post(f"{OL_URL}/login", data={ "_csrf": csrf, "email": OL_ADMIN_EMAIL, "password": OL_ADMIN_PASSWORD, }, allow_redirects=False) self.logged_in = resp.status_code in (200, 302) return self.logged_in def register_user(self, email): if not self.logged_in: self.login() csrf = self._get_csrf("/admin/register") resp = self.session.post(f"{OL_URL}/admin/register", data={ "_csrf": csrf, "email": email, }) # 从响应中提取设置密码的链接 import re set_password_url = "" match = re.search(r'(https?://[^\s"<>]*user/password/set\?[^\s"<>]+)', resp.text) if match: set_password_url = match.group(1) return resp.status_code == 200, set_password_url admin = OverleafAdmin() @app.get("/", response_class=HTMLResponse) async def index(): return REGISTER_HTML.replace("MSG_PLACEHOLDER", "") @app.post("/register", response_class=HTMLResponse) async def register(email: str = Form(...)): try: ok, set_url = admin.register_user(email) if ok and set_url: # 把链接中的 localhost 替换为实际访问地址 import re set_url = re.sub(r'https?://[^/]+', OL_URL, set_url) msg = f'

注册成功!请点击下方链接设置密码:

设置密码

' elif ok: msg = f'

注册成功!该邮箱可能已注册。请前往 登录页面 登录。

' else: msg = f'

注册失败,请稍后重试。

' except Exception as e: msg = f'

注册失败:{str(e)[:100]}

' return REGISTER_HTML.replace("MSG_PLACEHOLDER", msg) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=18091)