Skip to content

Commit b855fab

Browse files
authored
Merge pull request interledger#10 from elijah0kello/ft/gnap-utils
feat: initial gnap and http signatures implementation
2 parents dd42c9a + a8ab4ee commit b855fab

32 files changed

Lines changed: 1564 additions & 279 deletions

.github/workflows/test.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: Test Python open payments sdk
2+
3+
on:
4+
push:
5+
branches:
6+
- '**'
7+
pull_request:
8+
branches:
9+
- '**'
10+
11+
jobs:
12+
test:
13+
runs-on: ${{ matrix.os }}
14+
15+
strategy:
16+
matrix:
17+
os: [ubuntu-latest, windows-latest]
18+
python-version: ["3.10","3.11","3.12","3.13"]
19+
20+
steps:
21+
- name: Checkout code
22+
uses: actions/checkout@v3
23+
24+
- name: Set up Python
25+
uses: actions/setup-python@v4
26+
with:
27+
python-version: ${{ matrix.python-version }}
28+
29+
- name: Setup Poetry on Windows
30+
if: runner.os == 'Windows'
31+
run: |
32+
(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -
33+
echo "$env:APPDATA\Python\Scripts" >> $env:GITHUB_PATH
34+
35+
- name: Verify Poetry and create env on Windows
36+
if: runner.os == 'Windows'
37+
run: |
38+
poetry --version
39+
poetry config virtualenvs.create false
40+
41+
42+
- name: Setup Poetry on Ubuntu
43+
if: runner.os != 'Windows'
44+
run: |
45+
curl -sSL https://install.python-poetry.org | python3 -
46+
echo "$HOME/.local/bin" >> $GITHUB_PATH
47+
poetry config virtualenvs.create false
48+
49+
- name: Install dependencies
50+
run: |
51+
poetry install --no-interaction --no-root
52+
poetry install --only dev
53+
54+
- name: Run Unit Tests
55+
run: |
56+
poetry run pytest tests/unit/
57+
58+
audit:
59+
runs-on: ubuntu-latest
60+
steps:
61+
- uses: actions/checkout@v3
62+
- name: Install dependencies
63+
run: |
64+
python3 -m pip install . # assumes dependencies declared in pyproject.toml
65+
python3 -m pip install pip-audit
66+
- name: Run pip-audit
67+
run: pip-audit .

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,4 @@ poetry.toml
170170
pyrightconfig.json
171171

172172
# End of https://www.toptal.com/developers/gitignore/api/python
173+
privkey.pem

README.md

Lines changed: 119 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,130 @@ An Open Payments server runs two sub-systems, a resource server which exposes AP
2121

2222
## Local development
2323

24-
### Dependencies
25-
2624
- Python >= 3.11
25+
26+
To install python visit [Python Download](https://www.python.org/downloads/)
27+
2728
- Poetry
29+
To install poetry visit [Poetry Documentation](https://python-poetry.org/docs/).
2830

2931
### Installation
3032

33+
1. Activate your virtual emvironment. No need to create one, Poetry creates one.
34+
Read [managing environments in Poetry](https://python-poetry.org/docs/managing-environments/).
35+
36+
2. Install the dependencies in the poetry.lock
37+
3138
```
3239
> poetry install
3340
```
41+
42+
## Usage
43+
44+
To use this SDK, you will first need to install it in your project. Currently, you will need to build from source but once it is hosted on PyPi you will be able to install it with `pip`.
45+
46+
```bash
47+
python3 -m pip install open-payments-python-sdk #currently not setup
48+
```
49+
50+
## Installing from source
51+
52+
Clone the repository
53+
54+
```bash
55+
git clone https://github.com/interledger/open-payments-python-sdk.git
56+
cd open-payments-python-sdk
57+
```
58+
59+
Build the package
60+
61+
```bash
62+
poetry build
63+
```
64+
65+
After running this command, the wheel package will be written to the `dist/` folder in the repo you just cloned
66+
67+
Install it in your project
68+
69+
```bash
70+
pip install </path/to/>open-payments-python-sdk/dist/open_payments_sdk-0.1.0-py3-none-any.whl
71+
```
72+
73+
# Initialising the Client
74+
75+
To create a client you can do so by importing the `OpenPaymentsClient` defined in the [`client`](./src/client/client.py) module and instantiating it.
76+
77+
```python
78+
from open_payments_sdk.client.client import OpenPaymentsClient
79+
80+
with open("privkey.pem","r",encoding="utf_8") as privkey:
81+
private_key = privkey.read()
82+
83+
op_client = OpenPaymentsClient(keyid="27b4f8d2-746c-4522-b3f0-874ca15bfe65",private_key=private_key)
84+
```
85+
86+
The client is to be created after you have created a key pair and have obtained the `kid` and `private_key`
87+
88+
Some helper functions have been created to ease key pair creation. A class called `KeyManager` has been created and it provides functions to create a key pair and load a private key from UTF-8 string. It also returns an object that has information to be registered at the AS when registering the public key.
89+
90+
```python
91+
import json
92+
from open_payments_sdk.gnap_utils.keys import KeyManager
93+
94+
key_manager = KeyManager()
95+
key_pair = key_manager.generate_key_pair() # generate key pair
96+
97+
with open("privkey.pem", "w",encoding="utf_8") as pem_file: # save private key to file
98+
pem_file.write(key_pair.private_key_pem)
99+
100+
101+
with open("jwks.json","w", encoding="utf_8") as jwks_file: # save jwks.json file
102+
jwks_file.write(json.dumps(key_pair.jwks.keys[0].__dict__))
103+
104+
105+
with open("privkey.pem", "r", encoding="utf_8") as privkey: # load private key from file system
106+
private_key = privkey.read()
107+
108+
private_key = key_manager.load_ed25519_private_key_from_pem(
109+
private_key
110+
) # load private key fron file utf_8 string
111+
112+
public_key = private_key.public_key() # derive public key from private key
113+
```
114+
115+
## Wallets
116+
117+
You can use the created client to interact with the resource server. In this case we will use it to interact with a wallet address to get the wallet address details and jwks.json
118+
119+
```python
120+
#get wallet address
121+
wallet_address_details = op_client.wallet.get_wallet_address("https://ilp.interledger-test.dev/elijahokellosalary")
122+
123+
# Response
124+
{'id': AnyUrl('https://ilp.interledger-test.dev/elijahokellosalary'), 'publicName': 'elijahokellosalary', 'assetCode': AssetCode(root='USD'), 'assetScale': AssetScale(root=2), 'authServer': AnyUrl('https://auth.interledger-test.dev/'), 'resourceServer': AnyUrl('https://ilp.interledger-test.dev/')}
125+
126+
```
127+
128+
Get Wallet jwks
129+
130+
```python
131+
#get wallet jwks
132+
wallet_jwks = op_client.wallet.get_keys("https://ilp.interledger-test.dev/elijahokellosalary")
133+
134+
# Response
135+
{'keys': []}
136+
137+
```
138+
139+
## Grants
140+
141+
You can use the created client to request a grant from the authorization server. In this case we will use it to request a grant for an incoming payment resource. Check the [fixtures](./tests/conftest.py) file to see the request body.
142+
143+
```python
144+
wallet = op_client.wallet.get_wallet_address("https://ilp.interledger-test.dev/5c327379")
145+
grant_response = op_client.grants.post_grant_request(grant_request=grant_req_dto,auth_server_endpoint=str(wallet.authServer))
146+
147+
# Response
148+
{'access_token': {'access': [{'actions': ['create', 'read'], 'identifier': 'https://ilp.interledger-test.dev/5c327379', 'type': 'incoming-payment'}], 'value': '2E6F040D518B6F1A0883', 'manage': 'https://auth.interledger-test.dev/token/dad85db0-804d-4778-bf78-33eb5f81d86e', 'expires_in': 600}, 'continue': {'access_token': {'value': '3A088F83D39BDCDEC995'}, 'uri': 'https://auth.interledger-test.dev/continue/d2bb7a46-8cd9-4dde-83e2-821353b50579'}}
149+
150+
```

0 commit comments

Comments
 (0)