mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-07 07:55:16 +02:00
chore: mandate telnyx signature verification
This commit is contained in:
parent
5b1e3980b1
commit
ce3ac98bd8
5 changed files with 9 additions and 56 deletions
|
|
@ -142,12 +142,3 @@ FORCE_TURN_RELAY = os.getenv("FORCE_TURN_RELAY", "false").lower() == "true"
|
|||
# OSS Email/Password Auth
|
||||
OSS_JWT_SECRET = os.getenv("OSS_JWT_SECRET", "change-me-in-production")
|
||||
OSS_JWT_EXPIRY_HOURS = int(os.getenv("OSS_JWT_EXPIRY_HOURS", "720")) # 30 days
|
||||
|
||||
# REMOVE-AFTER 2026-05-15: transitional flag. When True, Telnyx webhook
|
||||
# signature verification is skipped for configs that have no
|
||||
# webhook_public_key set (existing configs predating the field). Set in prod
|
||||
# through 2026-05-15 to give users time to add their key; once removed,
|
||||
# configs without a key will fail signature verification.
|
||||
TELNYX_WEBHOOK_VERIFICATION_OPTIONAL = (
|
||||
os.getenv("TELNYX_WEBHOOK_VERIFICATION_OPTIONAL", "false").lower() == "true"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ TELNYX_TIMESTAMP_TOLERANCE_SECONDS = 300
|
|||
TELNYX_PUBLIC_KEY_BYTES = 32
|
||||
TELNYX_SIGNATURE_BYTES = 64
|
||||
|
||||
from api.constants import TELNYX_WEBHOOK_VERIFICATION_OPTIONAL
|
||||
from api.enums import WorkflowRunMode
|
||||
from api.services.telephony.base import (
|
||||
CallInitiationResult,
|
||||
|
|
@ -211,12 +210,6 @@ class TelnyxProvider(TelephonyProvider):
|
|||
return False
|
||||
|
||||
if not self.webhook_public_key:
|
||||
# REMOVE-AFTER 2026-05-15: transition window. Allow webhooks
|
||||
# through for configs that haven't added the key yet. Remove this
|
||||
# branch along with TELNYX_WEBHOOK_VERIFICATION_OPTIONAL after
|
||||
# the cutoff.
|
||||
if TELNYX_WEBHOOK_VERIFICATION_OPTIONAL:
|
||||
return True
|
||||
logger.error("Missing Telnyx webhook_public_key configuration")
|
||||
return False
|
||||
|
||||
|
|
|
|||
|
|
@ -153,45 +153,16 @@ async def test_verify_inbound_signature_rejects_missing_config_public_key():
|
|||
_, headers = _signed_headers(body)
|
||||
provider = _provider()
|
||||
|
||||
# REMOVE-AFTER 2026-05-15: drop the patch wrapper once
|
||||
# TELNYX_WEBHOOK_VERIFICATION_OPTIONAL is removed; the bare call below
|
||||
# will then assert the only path.
|
||||
with patch(
|
||||
"api.services.telephony.providers.telnyx.provider.TELNYX_WEBHOOK_VERIFICATION_OPTIONAL",
|
||||
False,
|
||||
):
|
||||
result = await provider.verify_inbound_signature(
|
||||
"https://example.test/api/v1/telephony/inbound/run",
|
||||
json.loads(body),
|
||||
headers,
|
||||
body,
|
||||
)
|
||||
result = await provider.verify_inbound_signature(
|
||||
"https://example.test/api/v1/telephony/inbound/run",
|
||||
json.loads(body),
|
||||
headers,
|
||||
body,
|
||||
)
|
||||
|
||||
assert result is False
|
||||
|
||||
|
||||
# REMOVE-AFTER 2026-05-15: delete this whole test along with the
|
||||
# TELNYX_WEBHOOK_VERIFICATION_OPTIONAL flag.
|
||||
@pytest.mark.asyncio
|
||||
async def test_verify_inbound_signature_allows_missing_key_when_optional_flag_set():
|
||||
body = _body()
|
||||
_, headers = _signed_headers(body)
|
||||
provider = _provider()
|
||||
|
||||
with patch(
|
||||
"api.services.telephony.providers.telnyx.provider.TELNYX_WEBHOOK_VERIFICATION_OPTIONAL",
|
||||
True,
|
||||
):
|
||||
result = await provider.verify_inbound_signature(
|
||||
"https://example.test/api/v1/telephony/inbound/run",
|
||||
json.loads(body),
|
||||
headers,
|
||||
body,
|
||||
)
|
||||
|
||||
assert result is True
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_verify_inbound_signature_reads_headers_case_insensitively():
|
||||
body = _body()
|
||||
|
|
|
|||
|
|
@ -181,8 +181,7 @@ export default function TelephonyConfigurationsPage() {
|
|||
? "1 Telnyx configuration is"
|
||||
: `${telnyxMissingWebhookPublicKeyCount} Telnyx configurations are`}{" "}
|
||||
missing a webhook public key. Without it, Telnyx call status
|
||||
updates and inbound calls will be rejected starting{" "}
|
||||
<span className="font-medium">15 May 2026</span>. Copy your
|
||||
updates and inbound calls are being rejected. Copy your
|
||||
public key from{" "}
|
||||
<span className="whitespace-nowrap">
|
||||
Mission Control Portal → Keys & Credentials → Public Key
|
||||
|
|
|
|||
|
|
@ -70,8 +70,7 @@ type SidebarNavSection = {
|
|||
items: SidebarNavItem[];
|
||||
};
|
||||
|
||||
const TELEPHONY_WARNING_DEADLINE = "15 May 2026";
|
||||
const TELEPHONY_WARNING_COPY = `Action required before ${TELEPHONY_WARNING_DEADLINE}`;
|
||||
const TELEPHONY_WARNING_COPY = "Action required";
|
||||
|
||||
const NAV_SECTIONS: SidebarNavSection[] = [
|
||||
{
|
||||
|
|
@ -206,7 +205,7 @@ export function AppSidebar() {
|
|||
};
|
||||
const warningIndicator = (
|
||||
<AlertTriangle
|
||||
aria-label={`Action required on a telephony configuration before ${TELEPHONY_WARNING_DEADLINE}`}
|
||||
aria-label="Action required on a telephony configuration"
|
||||
className={cn(
|
||||
"text-amber-500",
|
||||
isCollapsed ? "absolute -right-0.5 -top-0.5 h-3 w-3" : "ml-auto h-3.5 w-3.5"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue