mirror of
https://github.com/superdesigndev/treg.git
synced 2026-10-02 03:24:35 +08:00
57 lines
2.4 KiB
Python
57 lines
2.4 KiB
Python
"""Intercom Messenger wiring — OFF by default, secret never leaves the server.
|
|
|
|
Like analytics.py, the contract is mostly negative space: with no TREG_INTERCOM_APP_ID the widget
|
|
must not exist anywhere (/meta serves "", the pages' loaders stay inert), and the identity-
|
|
verification secret must never appear in any response — only the derived user_hash does. The markup
|
|
pins keep the web pages honest: the loader must key off /meta, never a hardcoded workspace id, or
|
|
every self-hosted deployment would boot chat into OUR workspace.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import hmac
|
|
import re
|
|
from pathlib import Path
|
|
|
|
from treg.config import get_settings
|
|
|
|
WEB = Path(__file__).resolve().parents[1] / "src" / "treg" / "web"
|
|
|
|
|
|
async def test_meta_off_by_default(clients):
|
|
body = (await clients.get("/meta")).json()
|
|
assert body["intercom_app_id"] == ""
|
|
|
|
|
|
async def test_meta_exposes_app_id_when_configured_and_never_the_secret(clients, monkeypatch):
|
|
monkeypatch.setattr(get_settings(), "intercom_app_id", "ic_test_id", raising=False)
|
|
monkeypatch.setattr(get_settings(), "intercom_secret", "super-secret", raising=False)
|
|
r = await clients.get("/meta")
|
|
assert r.json()["intercom_app_id"] == "ic_test_id"
|
|
assert "super-secret" not in r.text
|
|
|
|
|
|
async def test_auth_me_has_no_hash_when_unconfigured(clients):
|
|
body = (await clients.get("/auth/me")).json()
|
|
assert "intercom_user_hash" not in body
|
|
|
|
|
|
async def test_auth_me_user_hash_is_hmac_of_the_email(clients, monkeypatch):
|
|
monkeypatch.setattr(get_settings(), "intercom_secret", "s3cret", raising=False)
|
|
r = await clients.get("/auth/me")
|
|
body = r.json()
|
|
# independently recomputed: HMAC-SHA256 of the identifier the Messenger boots with (the email)
|
|
want = hmac.new(b"s3cret", body["email"].encode(), hashlib.sha256).hexdigest()
|
|
assert body["intercom_user_hash"] == want
|
|
assert "s3cret" not in r.text # the secret itself never leaves the server
|
|
|
|
|
|
def test_no_hardcoded_workspace_id_anywhere():
|
|
# the only allowed form of the widget URL is the config-driven concatenation
|
|
pat = re.compile(r"widget\.intercom\.io/widget/(?!'\+app)")
|
|
sources = [*WEB.rglob("*"), *(WEB.parents[2] / "frontend" / "src").rglob("*")]
|
|
for f in sources:
|
|
if "dashboard" not in f.parts and f.is_file() and f.suffix in {".html", ".js", ".md", ".txt"}:
|
|
assert not pat.search(f.read_text()), f"hardcoded Intercom workspace id in {f.name}"
|