diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e18e49c..ea0dd8e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.7", "3.8", "3.9", "3.10"] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} @@ -29,6 +29,10 @@ jobs: uses: actions/setup-python@v3 with: python-version: ${{ matrix.python-version }} + - if: matrix.os == 'macos-latest' && matrix.python-version == '3.11' + name: Install build tools + run: | + brew install automake - name: Install Poetry uses: abatilo/actions-poetry@v2 diff --git a/src/babble/auth.py b/src/babble/auth.py index 4a3aca9..8030d03 100644 --- a/src/babble/auth.py +++ b/src/babble/auth.py @@ -7,6 +7,7 @@ from .config import AUTH_SERVER from .crypto.identity import Identity +from .encoding import to_base64, from_base64 @dataclass @@ -17,43 +18,62 @@ class TokenMetadata: expires_at: datetime -def authenticate(identity: Identity) -> Tuple[str, TokenMetadata]: +def authenticate(identity: Identity, name: str = None) -> Tuple[str, TokenMetadata]: r = requests.post( - f"{AUTH_SERVER}/request_token", + f"{AUTH_SERVER}/auth/login/wallet/challenge", json={ "address": identity.address, - "public_key": identity.public_key, + "client_id": name if name else "uagent", }, ) r.raise_for_status() + resp = r.json() - payload = r.json()["payload"] + payload = resp["challenge"] # create the signature - signed_bytes, signature = identity.sign_arbitrary(payload.encode()) + _, signature = identity.sign_arbitrary(payload.encode()) - r = requests.post( - f"{AUTH_SERVER}/login", - json={ - "public_key": identity.public_key, - "signed_bytes": signed_bytes, - "signature": signature, + login_request = { + "address": identity.address, + "public_key": { + "value": to_base64(bytes.fromhex(identity.public_key)), + "type": "tendermint/PubKeySecp256k1", }, + "nonce": resp["nonce"], + "challenge": resp["challenge"], + "signature": signature, + "client_id": name if name else "uagent", + "scope": "", + } + + r = requests.post( + f"{AUTH_SERVER}/auth/login/wallet/verify", + json=login_request, + ) + r.raise_for_status() + + r = requests.post( + f"{AUTH_SERVER}/tokens", + json=r.json(), ) r.raise_for_status() # extract the token - token = str(r.json()["token"]) + token = str(r.json()["access_token"]) # parse the token token_data = jwt.decode( - token, algorithms=["RS*"], options={"verify_signature": False} + token, + algorithms=["RS*"], + options={"verify_signature": False}, + issuer="fetch.ai", ) # build the token metadata metadata = TokenMetadata( - address=str(token_data["name"]), - public_key=str(token_data["pubkey"]), + address=identity.address, + public_key=from_base64(str(token_data["pk"])).hex(), issued_at=datetime.fromtimestamp(token_data["iat"], timezone.utc), expires_at=datetime.fromtimestamp(token_data["exp"], timezone.utc), ) diff --git a/src/babble/client.py b/src/babble/client.py index b922caf..f1eb761 100644 --- a/src/babble/client.py +++ b/src/babble/client.py @@ -43,6 +43,7 @@ def __init__( signed_obj_base64: str, identity: Identity, chain_id: str, + name: str = None, ): _validate_address(delegate_address) @@ -53,6 +54,7 @@ def __init__( self._signed_obj_base64 = signed_obj_base64 self._identity = identity self._chain_id = chain_id + self._name = name # build and restore the delivered set self._last_rx_timestamp = self._now() @@ -70,7 +72,7 @@ def _update_authentication(self): or self._token_metadata.expires_at < self._now() - timedelta(seconds=EXPIRATION_BUFFER_SECONDS) ): - self._token, self._token_metadata = authenticate(self._identity) + self._token, self._token_metadata = authenticate(self._identity, self._name) def __repr__(self): return f"{self._delegate_address} ({self._identity.public_key})" diff --git a/src/babble/config.py b/src/babble/config.py index cf756de..e8c456c 100644 --- a/src/babble/config.py +++ b/src/babble/config.py @@ -1,8 +1,6 @@ import os -AUTH_SERVER = os.environ.get( - "AUTH_SERVER", "https://auth-attila.sandbox-london-b.fetch-ai.com" -) +AUTH_SERVER = os.environ.get("AUTH_SERVER", "https://accounts.fetch.ai/v1") MEMORANDUM_SERVER = os.environ.get( "MEMORANDUM_SERVER", "https://messaging-server.sandbox-london-b.fetch-ai.com/graphql",