diff --git a/api/ceramic_cache/api/schema.py b/api/ceramic_cache/api/schema.py index d0e7774d4..959d913ba 100644 --- a/api/ceramic_cache/api/schema.py +++ b/api/ceramic_cache/api/schema.py @@ -3,6 +3,7 @@ from typing import Any, Dict, List, Optional from ninja_schema import Schema + from registry.api.v1 import DetailedScoreResponse from ..models import CeramicCache @@ -46,6 +47,7 @@ class CacaoVerifySubmit(Schema): class AccessTokenResponse(Schema): access: str + intercom_user_hash: str class ComposeDBStatusPayload(Schema): diff --git a/api/ceramic_cache/api/v1.py b/api/ceramic_cache/api/v1.py index 9d695a07f..2379533f2 100644 --- a/api/ceramic_cache/api/v1.py +++ b/api/ceramic_cache/api/v1.py @@ -1,5 +1,7 @@ """Ceramic Cache API""" +import hashlib +import hmac import json from datetime import timedelta from typing import Any, Dict, List, Optional, Type @@ -543,6 +545,22 @@ def authenticate(request, payload: CacaoVerifySubmit): return handle_authenticate(payload) +def generate_access_token_response(user_did: str) -> AccessTokenResponse: + token = DbCacheToken() + token["did"] = user_did + + intercom_user_hash = hmac.new( + bytes(settings.INTERCOM_SECRET_KEY, encoding="utf-8"), + bytes(user_did, encoding="utf-8"), + digestmod=hashlib.sha256, + ).hexdigest() + + return AccessTokenResponse( + access=str(token.access_token), + intercom_user_hash=intercom_user_hash, + ) + + def handle_authenticate(payload: CacaoVerifySubmit) -> AccessTokenResponse: # First validate the payload # This will ensure that the payload signature was made for our unique nonce @@ -573,11 +591,7 @@ def handle_authenticate(payload: CacaoVerifySubmit) -> AccessTokenResponse: if res.status_code == 200: data = res.json() if data.get("status") == "ok": - token = DbCacheToken() - token["did"] = payload.issuer - return { - "access": str(token.access_token), - } + return generate_access_token_response(payload.issuer) log.error( "Failed to validate authentication payload (jws)! Response: %s\n%s", diff --git a/api/ceramic_cache/test/test_authenticate_v1.py b/api/ceramic_cache/test/test_authenticate_v1.py index 6b0ad2df7..8213a7724 100644 --- a/api/ceramic_cache/test/test_authenticate_v1.py +++ b/api/ceramic_cache/test/test_authenticate_v1.py @@ -1,8 +1,10 @@ import copy +import hashlib +import hmac import json -from collections import namedtuple import pytest +from django.conf import settings from django.test import Client from ninja_jwt.tokens import AccessToken @@ -70,10 +72,20 @@ def json(self): assert auth_response.status_code == 200 assert "access" in json_data + assert "intercom_user_hash" in json_data token = AccessToken(json_data["access"]) assert token["did"] == payload["issuer"] + assert ( + json_data["intercom_user_hash"] + == hmac.new( + bytes(settings.INTERCOM_SECRET_KEY, encoding="utf-8"), + bytes(payload["issuer"], encoding="utf-8"), + digestmod=hashlib.sha256, + ).hexdigest() + ) + def test_authenticate_fails_to_validate_invalid_payload(self, mocker): """ We expect that the authenticate request: diff --git a/api/scorer/settings/base.py b/api/scorer/settings/base.py index c3db86abc..5e5e535bf 100644 --- a/api/scorer/settings/base.py +++ b/api/scorer/settings/base.py @@ -20,6 +20,7 @@ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = env("SECRET_KEY") +INTERCOM_SECRET_KEY = env("INTERCOM_SECRET_KEY", default="TEST123") # SECURITY WARNING: don't run with debug turned on in production! DEBUG = env("DEBUG", default=True)