addressed first review comments and fixed tests

This commit is contained in:
groovecoder 2023-02-23 14:59:18 -06:00
Родитель aa21d76723
Коммит 9f1e5469eb
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: FB5123597126E96C
4 изменённых файлов: 43 добавлений и 33 удалений

Просмотреть файл

@ -38,6 +38,7 @@ TWILIO_SMS_APPLICATION_SID=
TWILIO_MESSAGING_SERVICE_SID=
TWILIO_MAIN_NUMBER=
IQ_ENABLED=False
IQ_FOR_NEW_NUMBERS=False
IQ_OUTBOUND_API_KEY=""
IQ_INBOUND_API_KEY=""
PERIODICAL_PREMIUM_PROD_ID=prod_KGizMiBqUJdYoY

Просмотреть файл

@ -9,6 +9,7 @@ from twilio.rest import Client
from django.conf import settings
from rest_framework.test import RequestsClient
from api.views.phones import compute_iq_mac
from phones.tests.models_tests import make_phone_test_user
from api.tests.phones_views_tests import _make_real_phone, _make_relay_number
@ -77,21 +78,18 @@ def test_iq_endpoint_invalid_hash():
def test_iq_endpoint_valid_hash_no_auth_failed_status():
message_id = "9a09df23-01f3-4e0f-adbc-2a783878a574"
combined = settings.IQ_INBOUND_API_KEY + message_id
token = hashlib.sha256(combined.encode()).hexdigest()
token = compute_iq_mac(message_id)
client = RequestsClient()
client.headers.update({"Verificationtoken": token})
client.headers.update({"MessageId": message_id})
response = client.post(INBOUND_SMS_PATH)
assert response.status_code != 401
assert response.status_code == 400
def _prepare_valid_iq_request_client() -> RequestsClient:
message_id = "9a09df23-01f3-4e0f-adbc-2a783878a574"
combined = settings.IQ_INBOUND_API_KEY + message_id
token = hashlib.sha256(combined.encode()).hexdigest()
token = compute_iq_mac(message_id)
client = RequestsClient()
client.headers.update({"Verificationtoken": token})
client.headers.update({"MessageId": message_id})

Просмотреть файл

@ -68,19 +68,20 @@ urlpatterns = [
),
]
if settings.PHONES_ENABLED:
from .views.phones import (
RealPhoneViewSet,
RelayNumberViewSet,
InboundContactViewSet,
inbound_call,
inbound_sms,
vCard,
sms_status,
voice_status,
resend_welcome_sms,
)
from .views.phones import (
RealPhoneViewSet,
RelayNumberViewSet,
InboundContactViewSet,
inbound_call,
inbound_sms,
inbound_sms_iq,
vCard,
sms_status,
voice_status,
resend_welcome_sms,
)
if settings.PHONES_ENABLED:
api_router.register(r"realphone", RealPhoneViewSet, "real_phone")
api_router.register(r"relaynumber", RelayNumberViewSet, "relay_number")
api_router.register(r"inboundcontact", InboundContactViewSet, "inbound_contact")
@ -131,12 +132,13 @@ if settings.PHONES_ENABLED:
]
if settings.PHONES_ENABLED and settings.IQ_ENABLED:
from .views.phones import inbound_sms_iq
urlpatterns += [
path("v1/inbound_sms_iq/", inbound_sms_iq, name="inbound_sms"),
]
urlpatterns += [
path(
"v1/inbound_sms_iq/",
enable_if_setting("IQ_ENABLED")(inbound_sms_iq),
name="inbound_sms",
),
]
urlpatterns += [

Просмотреть файл

@ -476,6 +476,10 @@ def _try_delete_from_twilio(message):
raise e
def message_body(from_num, body):
return f"[Relay 📲 {from_num}] {body}"
@decorators.api_view(["POST"])
@decorators.permission_classes([permissions.AllowAny])
@decorators.renderer_classes([TemplateTwiMLRenderer])
@ -538,9 +542,10 @@ def inbound_sms(request):
client = twilio_client()
app = twiml_app()
incr_if_enabled("phones_outbound_sms")
body = message_body(inbound_from, inbound_body)
client.messages.create(
from_=relay_number.number,
body=f"[Relay 📲 {inbound_from}] {inbound_body}",
body=body,
status_callback=app.sms_status_callback,
to=real_phone.number,
)
@ -591,7 +596,7 @@ def inbound_sms_iq(request: Request) -> response.Response:
_check_and_update_contact(inbound_contact, "texts", relay_number)
iq_formatted_real_num = real_phone.number.replace("+", "")
text = f"[Relay 📲 {inbound_from}] {inbound_body}"
text = message_body(inbound_from, inbound_body)
json_body = {"from": relay_num, "to": [iq_formatted_real_num], "text": text}
resp = requests.post(
"https://messagebroker.inteliquent.com/msgbroker/rest/publishMessages",
@ -1106,21 +1111,25 @@ def _validate_twilio_request(request):
raise exceptions.ValidationError("Invalid request: invalid signature")
def _validate_iq_request(request):
def compute_iq_mac(message_id: str) -> str:
iq_api_key = settings.IQ_INBOUND_API_KEY
# FIXME: switch to proper hmac when iQ is ready
# mac = hmac.new(iq_api_key.encode(), msg=message_id.encode(), digestmod=hashlib.sha256)
combined = iq_api_key + message_id
return hashlib.sha256(combined.encode()).hexdigest()
def _validate_iq_request(request: Request) -> None:
if "Verificationtoken" not in request._request.headers:
raise exceptions.AuthenticationFailed("missing Verificationtoken header.")
if "MessageId" not in request._request.headers:
raise exceptions.AuthenticationFailed("missing MessageId header.")
iq_api_key = settings.IQ_INBOUND_API_KEY
message_id = request._request.headers["Messageid"]
mac = compute_iq_mac(message_id)
token = request._request.headers["verificationToken"]
# FIXME: switch to proper hmac when iQ is ready
# mac = hmac.new(iq_api_key.encode(), msg=message_id.encode(), digestmod=hashlib.sha256)
combined = iq_api_key + message_id
mac = hashlib.sha256(combined.encode())
if mac.hexdigest() != token:
if mac != token:
raise exceptions.AuthenticationFailed("verficiationToken != computed sha256")