shield-python 0.1.0__tar.gz → 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {shield_python-0.1.0 → shield_python-0.1.2}/PKG-INFO +6 -6
- {shield_python-0.1.0 → shield_python-0.1.2}/README.md +255 -255
- {shield_python-0.1.0 → shield_python-0.1.2}/pyproject.toml +16 -16
- {shield_python-0.1.0 → shield_python-0.1.2}/setup.py +8 -8
- {shield_python-0.1.0 → shield_python-0.1.2}/shield/__init__.py +1 -1
- {shield_python-0.1.0 → shield_python-0.1.2}/shield/client.py +5 -2
- {shield_python-0.1.0 → shield_python-0.1.2}/shield_python.egg-info/PKG-INFO +6 -6
- {shield_python-0.1.0 → shield_python-0.1.2}/setup.cfg +0 -0
- {shield_python-0.1.0 → shield_python-0.1.2}/shield/exceptions.py +0 -0
- {shield_python-0.1.0 → shield_python-0.1.2}/shield/resources/__init__.py +0 -0
- {shield_python-0.1.0 → shield_python-0.1.2}/shield/resources/events.py +0 -0
- {shield_python-0.1.0 → shield_python-0.1.2}/shield/resources/sessions.py +0 -0
- {shield_python-0.1.0 → shield_python-0.1.2}/shield/resources/verify.py +0 -0
- {shield_python-0.1.0 → shield_python-0.1.2}/shield_python.egg-info/SOURCES.txt +0 -0
- {shield_python-0.1.0 → shield_python-0.1.2}/shield_python.egg-info/dependency_links.txt +0 -0
- {shield_python-0.1.0 → shield_python-0.1.2}/shield_python.egg-info/requires.txt +0 -0
- {shield_python-0.1.0 → shield_python-0.1.2}/shield_python.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shield-python
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Official Shield SDK for Python
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Homepage, https://getshield.dev
|
|
@@ -11,7 +11,7 @@ Requires-Dist: requests>=2.28.0
|
|
|
11
11
|
|
|
12
12
|
# Shield Python SDK
|
|
13
13
|
|
|
14
|
-
Official Python SDK for [Shield](https://getshield.dev)
|
|
14
|
+
Official Python SDK for [Shield](https://getshield.dev) ??tamper-evident session recording for online business transactions.
|
|
15
15
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
@@ -27,7 +27,7 @@ import shield
|
|
|
27
27
|
client = shield.Client(api_key="sk_live_your_api_key")
|
|
28
28
|
|
|
29
29
|
# Create a session
|
|
30
|
-
session = client.sessions.create(title="
|
|
30
|
+
session = client.sessions.create(title="Contract Negotiation with Acme Corp")
|
|
31
31
|
session_id = session["id"]
|
|
32
32
|
|
|
33
33
|
# Record events
|
|
@@ -75,8 +75,8 @@ client = shield.Client(
|
|
|
75
75
|
|
|
76
76
|
When an HMAC secret is configured, the SDK computes a signature for each request:
|
|
77
77
|
|
|
78
|
-
- `X-Shield-Timestamp`
|
|
79
|
-
- `X-Shield-Signature`
|
|
78
|
+
- `X-Shield-Timestamp` ??Unix timestamp of the request
|
|
79
|
+
- `X-Shield-Signature` ??HMAC-SHA256 of `{timestamp}.{METHOD}.{path}.{SHA256(body)}`
|
|
80
80
|
|
|
81
81
|
The server validates these headers to ensure requests have not been tampered with or replayed.
|
|
82
82
|
|
|
@@ -192,7 +192,7 @@ async def verify_session(session_id: str):
|
|
|
192
192
|
|
|
193
193
|
## Event Types Reference
|
|
194
194
|
|
|
195
|
-
Shield Standard Event Taxonomy v1.0
|
|
195
|
+
Shield Standard Event Taxonomy v1.0 ??37 event types across 7 categories:
|
|
196
196
|
|
|
197
197
|
### Party Events
|
|
198
198
|
| Event Type | Description |
|
|
@@ -1,255 +1,255 @@
|
|
|
1
|
-
# Shield Python SDK
|
|
2
|
-
|
|
3
|
-
Official Python SDK for [Shield](https://getshield.dev)
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
pip install shield-python
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Quick Start
|
|
12
|
-
|
|
13
|
-
```python
|
|
14
|
-
import shield
|
|
15
|
-
|
|
16
|
-
client = shield.Client(api_key="sk_live_your_api_key")
|
|
17
|
-
|
|
18
|
-
# Create a session
|
|
19
|
-
session = client.sessions.create(title="
|
|
20
|
-
session_id = session["id"]
|
|
21
|
-
|
|
22
|
-
# Record events
|
|
23
|
-
client.events.create(
|
|
24
|
-
session_id=session_id,
|
|
25
|
-
event_type="shield.party.joined",
|
|
26
|
-
actor="agent@example.com",
|
|
27
|
-
data={"role": "listing_agent", "name": "Jane Smith"},
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
client.events.create(
|
|
31
|
-
session_id=session_id,
|
|
32
|
-
event_type="shield.content.uploaded",
|
|
33
|
-
actor="agent@example.com",
|
|
34
|
-
data={"filename": "purchase_agreement.pdf", "hash": "sha256:abc123..."},
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
client.events.create(
|
|
38
|
-
session_id=session_id,
|
|
39
|
-
event_type="shield.agreement.signed",
|
|
40
|
-
actor="buyer@example.com",
|
|
41
|
-
data={"document": "purchase_agreement.pdf"},
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
# Verify session integrity
|
|
45
|
-
result = client.verify.session(session_id)
|
|
46
|
-
print(result["intact"]) # True
|
|
47
|
-
|
|
48
|
-
# Export session
|
|
49
|
-
pdf_bytes = client.sessions.export(session_id, format="pdf")
|
|
50
|
-
with open("audit_trail.pdf", "wb") as f:
|
|
51
|
-
f.write(pdf_bytes)
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
## HMAC Authentication
|
|
55
|
-
|
|
56
|
-
For enhanced security, provide an HMAC secret to sign every request:
|
|
57
|
-
|
|
58
|
-
```python
|
|
59
|
-
client = shield.Client(
|
|
60
|
-
api_key="sk_live_your_api_key",
|
|
61
|
-
hmac_secret="your_hmac_secret",
|
|
62
|
-
)
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
When an HMAC secret is configured, the SDK computes a signature for each request:
|
|
66
|
-
|
|
67
|
-
- `X-Shield-Timestamp`
|
|
68
|
-
- `X-Shield-Signature`
|
|
69
|
-
|
|
70
|
-
The server validates these headers to ensure requests have not been tampered with or replayed.
|
|
71
|
-
|
|
72
|
-
## Flask Integration
|
|
73
|
-
|
|
74
|
-
```python
|
|
75
|
-
from flask import Flask, request, jsonify
|
|
76
|
-
import shield
|
|
77
|
-
|
|
78
|
-
app = Flask(__name__)
|
|
79
|
-
client = shield.Client(api_key="sk_live_your_api_key")
|
|
80
|
-
|
|
81
|
-
@app.route("/sessions", methods=["POST"])
|
|
82
|
-
def create_session():
|
|
83
|
-
data = request.get_json()
|
|
84
|
-
session = client.sessions.create(title=data["title"])
|
|
85
|
-
|
|
86
|
-
# Record who created the session
|
|
87
|
-
client.events.create(
|
|
88
|
-
session_id=session["id"],
|
|
89
|
-
event_type="shield.session.created",
|
|
90
|
-
actor=data["user_email"],
|
|
91
|
-
)
|
|
92
|
-
return jsonify(session), 201
|
|
93
|
-
|
|
94
|
-
@app.route("/sessions/<session_id>/upload", methods=["POST"])
|
|
95
|
-
def upload_document(session_id):
|
|
96
|
-
file = request.files["file"]
|
|
97
|
-
# ... save file logic ...
|
|
98
|
-
|
|
99
|
-
client.events.create(
|
|
100
|
-
session_id=session_id,
|
|
101
|
-
event_type="shield.content.uploaded",
|
|
102
|
-
actor=request.headers.get("X-User-Email"),
|
|
103
|
-
data={"filename": file.filename},
|
|
104
|
-
)
|
|
105
|
-
return jsonify({"status": "uploaded"}), 200
|
|
106
|
-
|
|
107
|
-
@app.route("/sessions/<session_id>/sign", methods=["POST"])
|
|
108
|
-
def sign_agreement(session_id):
|
|
109
|
-
data = request.get_json()
|
|
110
|
-
|
|
111
|
-
client.events.create(
|
|
112
|
-
session_id=session_id,
|
|
113
|
-
event_type="shield.agreement.signed",
|
|
114
|
-
actor=data["signer_email"],
|
|
115
|
-
data={"document": data["document_name"], "ip": request.remote_addr},
|
|
116
|
-
)
|
|
117
|
-
return jsonify({"status": "signed"}), 200
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
## FastAPI Integration
|
|
121
|
-
|
|
122
|
-
```python
|
|
123
|
-
from fastapi import FastAPI, UploadFile, Header
|
|
124
|
-
from pydantic import BaseModel
|
|
125
|
-
import shield
|
|
126
|
-
|
|
127
|
-
app = FastAPI()
|
|
128
|
-
client = shield.Client(
|
|
129
|
-
api_key="sk_live_your_api_key",
|
|
130
|
-
hmac_secret="your_hmac_secret",
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
class CreateSessionRequest(BaseModel):
|
|
134
|
-
title: str
|
|
135
|
-
user_email: str
|
|
136
|
-
|
|
137
|
-
class SignRequest(BaseModel):
|
|
138
|
-
signer_email: str
|
|
139
|
-
document_name: str
|
|
140
|
-
|
|
141
|
-
@app.post("/sessions")
|
|
142
|
-
async def create_session(body: CreateSessionRequest):
|
|
143
|
-
session = client.sessions.create(title=body.title)
|
|
144
|
-
client.events.create(
|
|
145
|
-
session_id=session["id"],
|
|
146
|
-
event_type="shield.session.created",
|
|
147
|
-
actor=body.user_email,
|
|
148
|
-
)
|
|
149
|
-
return session
|
|
150
|
-
|
|
151
|
-
@app.post("/sessions/{session_id}/upload")
|
|
152
|
-
async def upload_document(
|
|
153
|
-
session_id: str,
|
|
154
|
-
file: UploadFile,
|
|
155
|
-
x_user_email: str = Header(...),
|
|
156
|
-
):
|
|
157
|
-
# ... save file logic ...
|
|
158
|
-
|
|
159
|
-
client.events.create(
|
|
160
|
-
session_id=session_id,
|
|
161
|
-
event_type="shield.content.uploaded",
|
|
162
|
-
actor=x_user_email,
|
|
163
|
-
data={"filename": file.filename},
|
|
164
|
-
)
|
|
165
|
-
return {"status": "uploaded"}
|
|
166
|
-
|
|
167
|
-
@app.post("/sessions/{session_id}/sign")
|
|
168
|
-
async def sign_agreement(session_id: str, body: SignRequest):
|
|
169
|
-
client.events.create(
|
|
170
|
-
session_id=session_id,
|
|
171
|
-
event_type="shield.agreement.signed",
|
|
172
|
-
actor=body.signer_email,
|
|
173
|
-
data={"document": body.document_name},
|
|
174
|
-
)
|
|
175
|
-
return {"status": "signed"}
|
|
176
|
-
|
|
177
|
-
@app.get("/sessions/{session_id}/verify")
|
|
178
|
-
async def verify_session(session_id: str):
|
|
179
|
-
return client.verify.session(session_id)
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
## Event Types Reference
|
|
183
|
-
|
|
184
|
-
Shield Standard Event Taxonomy v1.0
|
|
185
|
-
|
|
186
|
-
### Party Events
|
|
187
|
-
| Event Type | Description |
|
|
188
|
-
|---|---|
|
|
189
|
-
| `shield.party.joined` | A party joined the session |
|
|
190
|
-
| `shield.party.left` | A party left the session |
|
|
191
|
-
| `shield.party.identity.verified` | Party identity was verified |
|
|
192
|
-
| `shield.party.identity.failed` | Party identity verification failed |
|
|
193
|
-
| `shield.party.role.assigned` | A role was assigned to a party |
|
|
194
|
-
|
|
195
|
-
### Session Events
|
|
196
|
-
| Event Type | Description |
|
|
197
|
-
|---|---|
|
|
198
|
-
| `shield.session.created` | Session was created |
|
|
199
|
-
| `shield.session.opened` | Session was opened |
|
|
200
|
-
| `shield.session.closed` | Session was closed |
|
|
201
|
-
| `shield.session.expired` | Session expired |
|
|
202
|
-
| `shield.session.archived` | Session was archived |
|
|
203
|
-
|
|
204
|
-
### Content Events
|
|
205
|
-
| Event Type | Description |
|
|
206
|
-
|---|---|
|
|
207
|
-
| `shield.content.uploaded` | Content was uploaded |
|
|
208
|
-
| `shield.content.viewed` | Content was viewed |
|
|
209
|
-
| `shield.content.downloaded` | Content was downloaded |
|
|
210
|
-
| `shield.content.deleted` | Content was deleted |
|
|
211
|
-
| `shield.content.hash.verified` | Content hash was verified |
|
|
212
|
-
|
|
213
|
-
### Negotiation Events
|
|
214
|
-
| Event Type | Description |
|
|
215
|
-
|---|---|
|
|
216
|
-
| `shield.negotiation.terms.proposed` | Terms were proposed |
|
|
217
|
-
| `shield.negotiation.terms.accepted` | Terms were accepted |
|
|
218
|
-
| `shield.negotiation.terms.rejected` | Terms were rejected |
|
|
219
|
-
| `shield.negotiation.terms.modified` | Terms were modified |
|
|
220
|
-
| `shield.negotiation.terms.expired` | Terms expired |
|
|
221
|
-
| `shield.negotiation.message.sent` | Negotiation message sent |
|
|
222
|
-
| `shield.negotiation.message.read` | Negotiation message read |
|
|
223
|
-
|
|
224
|
-
### Agreement Events
|
|
225
|
-
| Event Type | Description |
|
|
226
|
-
|---|---|
|
|
227
|
-
| `shield.agreement.drafted` | Agreement was drafted |
|
|
228
|
-
| `shield.agreement.reviewed` | Agreement was reviewed |
|
|
229
|
-
| `shield.agreement.approved` | Agreement was approved |
|
|
230
|
-
| `shield.agreement.signed` | Agreement was signed |
|
|
231
|
-
| `shield.agreement.countersigned` | Agreement was countersigned |
|
|
232
|
-
| `shield.agreement.voided` | Agreement was voided |
|
|
233
|
-
| `shield.agreement.reached` | Agreement was reached |
|
|
234
|
-
|
|
235
|
-
### Access Events
|
|
236
|
-
| Event Type | Description |
|
|
237
|
-
|---|---|
|
|
238
|
-
| `shield.access.granted` | Access was granted |
|
|
239
|
-
| `shield.access.revoked` | Access was revoked |
|
|
240
|
-
| `shield.access.attempted` | Access was attempted |
|
|
241
|
-
| `shield.access.denied` | Access was denied |
|
|
242
|
-
|
|
243
|
-
### Disclosure Events
|
|
244
|
-
| Event Type | Description |
|
|
245
|
-
|---|---|
|
|
246
|
-
| `shield.disclosure.presented` | Disclosure was presented |
|
|
247
|
-
| `shield.disclosure.acknowledged` | Disclosure was acknowledged |
|
|
248
|
-
| `shield.disclosure.declined` | Disclosure was declined |
|
|
249
|
-
|
|
250
|
-
### Evidence Events
|
|
251
|
-
| Event Type | Description |
|
|
252
|
-
|---|---|
|
|
253
|
-
| `shield.evidence.exported` | Evidence was exported |
|
|
254
|
-
| `shield.evidence.verified` | Evidence was verified |
|
|
255
|
-
| `shield.evidence.tampered_detected` | Evidence tampering was detected |
|
|
1
|
+
# Shield Python SDK
|
|
2
|
+
|
|
3
|
+
Official Python SDK for [Shield](https://getshield.dev) ??tamper-evident session recording for online business transactions.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install shield-python
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
import shield
|
|
15
|
+
|
|
16
|
+
client = shield.Client(api_key="sk_live_your_api_key")
|
|
17
|
+
|
|
18
|
+
# Create a session
|
|
19
|
+
session = client.sessions.create(title="Contract Negotiation with Acme Corp")
|
|
20
|
+
session_id = session["id"]
|
|
21
|
+
|
|
22
|
+
# Record events
|
|
23
|
+
client.events.create(
|
|
24
|
+
session_id=session_id,
|
|
25
|
+
event_type="shield.party.joined",
|
|
26
|
+
actor="agent@example.com",
|
|
27
|
+
data={"role": "listing_agent", "name": "Jane Smith"},
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
client.events.create(
|
|
31
|
+
session_id=session_id,
|
|
32
|
+
event_type="shield.content.uploaded",
|
|
33
|
+
actor="agent@example.com",
|
|
34
|
+
data={"filename": "purchase_agreement.pdf", "hash": "sha256:abc123..."},
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
client.events.create(
|
|
38
|
+
session_id=session_id,
|
|
39
|
+
event_type="shield.agreement.signed",
|
|
40
|
+
actor="buyer@example.com",
|
|
41
|
+
data={"document": "purchase_agreement.pdf"},
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# Verify session integrity
|
|
45
|
+
result = client.verify.session(session_id)
|
|
46
|
+
print(result["intact"]) # True
|
|
47
|
+
|
|
48
|
+
# Export session
|
|
49
|
+
pdf_bytes = client.sessions.export(session_id, format="pdf")
|
|
50
|
+
with open("audit_trail.pdf", "wb") as f:
|
|
51
|
+
f.write(pdf_bytes)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## HMAC Authentication
|
|
55
|
+
|
|
56
|
+
For enhanced security, provide an HMAC secret to sign every request:
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
client = shield.Client(
|
|
60
|
+
api_key="sk_live_your_api_key",
|
|
61
|
+
hmac_secret="your_hmac_secret",
|
|
62
|
+
)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
When an HMAC secret is configured, the SDK computes a signature for each request:
|
|
66
|
+
|
|
67
|
+
- `X-Shield-Timestamp` ??Unix timestamp of the request
|
|
68
|
+
- `X-Shield-Signature` ??HMAC-SHA256 of `{timestamp}.{METHOD}.{path}.{SHA256(body)}`
|
|
69
|
+
|
|
70
|
+
The server validates these headers to ensure requests have not been tampered with or replayed.
|
|
71
|
+
|
|
72
|
+
## Flask Integration
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from flask import Flask, request, jsonify
|
|
76
|
+
import shield
|
|
77
|
+
|
|
78
|
+
app = Flask(__name__)
|
|
79
|
+
client = shield.Client(api_key="sk_live_your_api_key")
|
|
80
|
+
|
|
81
|
+
@app.route("/sessions", methods=["POST"])
|
|
82
|
+
def create_session():
|
|
83
|
+
data = request.get_json()
|
|
84
|
+
session = client.sessions.create(title=data["title"])
|
|
85
|
+
|
|
86
|
+
# Record who created the session
|
|
87
|
+
client.events.create(
|
|
88
|
+
session_id=session["id"],
|
|
89
|
+
event_type="shield.session.created",
|
|
90
|
+
actor=data["user_email"],
|
|
91
|
+
)
|
|
92
|
+
return jsonify(session), 201
|
|
93
|
+
|
|
94
|
+
@app.route("/sessions/<session_id>/upload", methods=["POST"])
|
|
95
|
+
def upload_document(session_id):
|
|
96
|
+
file = request.files["file"]
|
|
97
|
+
# ... save file logic ...
|
|
98
|
+
|
|
99
|
+
client.events.create(
|
|
100
|
+
session_id=session_id,
|
|
101
|
+
event_type="shield.content.uploaded",
|
|
102
|
+
actor=request.headers.get("X-User-Email"),
|
|
103
|
+
data={"filename": file.filename},
|
|
104
|
+
)
|
|
105
|
+
return jsonify({"status": "uploaded"}), 200
|
|
106
|
+
|
|
107
|
+
@app.route("/sessions/<session_id>/sign", methods=["POST"])
|
|
108
|
+
def sign_agreement(session_id):
|
|
109
|
+
data = request.get_json()
|
|
110
|
+
|
|
111
|
+
client.events.create(
|
|
112
|
+
session_id=session_id,
|
|
113
|
+
event_type="shield.agreement.signed",
|
|
114
|
+
actor=data["signer_email"],
|
|
115
|
+
data={"document": data["document_name"], "ip": request.remote_addr},
|
|
116
|
+
)
|
|
117
|
+
return jsonify({"status": "signed"}), 200
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## FastAPI Integration
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
from fastapi import FastAPI, UploadFile, Header
|
|
124
|
+
from pydantic import BaseModel
|
|
125
|
+
import shield
|
|
126
|
+
|
|
127
|
+
app = FastAPI()
|
|
128
|
+
client = shield.Client(
|
|
129
|
+
api_key="sk_live_your_api_key",
|
|
130
|
+
hmac_secret="your_hmac_secret",
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
class CreateSessionRequest(BaseModel):
|
|
134
|
+
title: str
|
|
135
|
+
user_email: str
|
|
136
|
+
|
|
137
|
+
class SignRequest(BaseModel):
|
|
138
|
+
signer_email: str
|
|
139
|
+
document_name: str
|
|
140
|
+
|
|
141
|
+
@app.post("/sessions")
|
|
142
|
+
async def create_session(body: CreateSessionRequest):
|
|
143
|
+
session = client.sessions.create(title=body.title)
|
|
144
|
+
client.events.create(
|
|
145
|
+
session_id=session["id"],
|
|
146
|
+
event_type="shield.session.created",
|
|
147
|
+
actor=body.user_email,
|
|
148
|
+
)
|
|
149
|
+
return session
|
|
150
|
+
|
|
151
|
+
@app.post("/sessions/{session_id}/upload")
|
|
152
|
+
async def upload_document(
|
|
153
|
+
session_id: str,
|
|
154
|
+
file: UploadFile,
|
|
155
|
+
x_user_email: str = Header(...),
|
|
156
|
+
):
|
|
157
|
+
# ... save file logic ...
|
|
158
|
+
|
|
159
|
+
client.events.create(
|
|
160
|
+
session_id=session_id,
|
|
161
|
+
event_type="shield.content.uploaded",
|
|
162
|
+
actor=x_user_email,
|
|
163
|
+
data={"filename": file.filename},
|
|
164
|
+
)
|
|
165
|
+
return {"status": "uploaded"}
|
|
166
|
+
|
|
167
|
+
@app.post("/sessions/{session_id}/sign")
|
|
168
|
+
async def sign_agreement(session_id: str, body: SignRequest):
|
|
169
|
+
client.events.create(
|
|
170
|
+
session_id=session_id,
|
|
171
|
+
event_type="shield.agreement.signed",
|
|
172
|
+
actor=body.signer_email,
|
|
173
|
+
data={"document": body.document_name},
|
|
174
|
+
)
|
|
175
|
+
return {"status": "signed"}
|
|
176
|
+
|
|
177
|
+
@app.get("/sessions/{session_id}/verify")
|
|
178
|
+
async def verify_session(session_id: str):
|
|
179
|
+
return client.verify.session(session_id)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Event Types Reference
|
|
183
|
+
|
|
184
|
+
Shield Standard Event Taxonomy v1.0 ??37 event types across 7 categories:
|
|
185
|
+
|
|
186
|
+
### Party Events
|
|
187
|
+
| Event Type | Description |
|
|
188
|
+
|---|---|
|
|
189
|
+
| `shield.party.joined` | A party joined the session |
|
|
190
|
+
| `shield.party.left` | A party left the session |
|
|
191
|
+
| `shield.party.identity.verified` | Party identity was verified |
|
|
192
|
+
| `shield.party.identity.failed` | Party identity verification failed |
|
|
193
|
+
| `shield.party.role.assigned` | A role was assigned to a party |
|
|
194
|
+
|
|
195
|
+
### Session Events
|
|
196
|
+
| Event Type | Description |
|
|
197
|
+
|---|---|
|
|
198
|
+
| `shield.session.created` | Session was created |
|
|
199
|
+
| `shield.session.opened` | Session was opened |
|
|
200
|
+
| `shield.session.closed` | Session was closed |
|
|
201
|
+
| `shield.session.expired` | Session expired |
|
|
202
|
+
| `shield.session.archived` | Session was archived |
|
|
203
|
+
|
|
204
|
+
### Content Events
|
|
205
|
+
| Event Type | Description |
|
|
206
|
+
|---|---|
|
|
207
|
+
| `shield.content.uploaded` | Content was uploaded |
|
|
208
|
+
| `shield.content.viewed` | Content was viewed |
|
|
209
|
+
| `shield.content.downloaded` | Content was downloaded |
|
|
210
|
+
| `shield.content.deleted` | Content was deleted |
|
|
211
|
+
| `shield.content.hash.verified` | Content hash was verified |
|
|
212
|
+
|
|
213
|
+
### Negotiation Events
|
|
214
|
+
| Event Type | Description |
|
|
215
|
+
|---|---|
|
|
216
|
+
| `shield.negotiation.terms.proposed` | Terms were proposed |
|
|
217
|
+
| `shield.negotiation.terms.accepted` | Terms were accepted |
|
|
218
|
+
| `shield.negotiation.terms.rejected` | Terms were rejected |
|
|
219
|
+
| `shield.negotiation.terms.modified` | Terms were modified |
|
|
220
|
+
| `shield.negotiation.terms.expired` | Terms expired |
|
|
221
|
+
| `shield.negotiation.message.sent` | Negotiation message sent |
|
|
222
|
+
| `shield.negotiation.message.read` | Negotiation message read |
|
|
223
|
+
|
|
224
|
+
### Agreement Events
|
|
225
|
+
| Event Type | Description |
|
|
226
|
+
|---|---|
|
|
227
|
+
| `shield.agreement.drafted` | Agreement was drafted |
|
|
228
|
+
| `shield.agreement.reviewed` | Agreement was reviewed |
|
|
229
|
+
| `shield.agreement.approved` | Agreement was approved |
|
|
230
|
+
| `shield.agreement.signed` | Agreement was signed |
|
|
231
|
+
| `shield.agreement.countersigned` | Agreement was countersigned |
|
|
232
|
+
| `shield.agreement.voided` | Agreement was voided |
|
|
233
|
+
| `shield.agreement.reached` | Agreement was reached |
|
|
234
|
+
|
|
235
|
+
### Access Events
|
|
236
|
+
| Event Type | Description |
|
|
237
|
+
|---|---|
|
|
238
|
+
| `shield.access.granted` | Access was granted |
|
|
239
|
+
| `shield.access.revoked` | Access was revoked |
|
|
240
|
+
| `shield.access.attempted` | Access was attempted |
|
|
241
|
+
| `shield.access.denied` | Access was denied |
|
|
242
|
+
|
|
243
|
+
### Disclosure Events
|
|
244
|
+
| Event Type | Description |
|
|
245
|
+
|---|---|
|
|
246
|
+
| `shield.disclosure.presented` | Disclosure was presented |
|
|
247
|
+
| `shield.disclosure.acknowledged` | Disclosure was acknowledged |
|
|
248
|
+
| `shield.disclosure.declined` | Disclosure was declined |
|
|
249
|
+
|
|
250
|
+
### Evidence Events
|
|
251
|
+
| Event Type | Description |
|
|
252
|
+
|---|---|
|
|
253
|
+
| `shield.evidence.exported` | Evidence was exported |
|
|
254
|
+
| `shield.evidence.verified` | Evidence was verified |
|
|
255
|
+
| `shield.evidence.tampered_detected` | Evidence tampering was detected |
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "shield-python"
|
|
7
|
-
version = "0.1.
|
|
8
|
-
description = "Official Shield SDK for Python"
|
|
9
|
-
readme = "README.md"
|
|
10
|
-
license = {text = "MIT"}
|
|
11
|
-
requires-python = ">=3.8"
|
|
12
|
-
dependencies = ["requests>=2.28.0"]
|
|
13
|
-
|
|
14
|
-
[project.urls]
|
|
15
|
-
Homepage = "https://getshield.dev"
|
|
16
|
-
Documentation = "https://docs.getshield.dev"
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "shield-python"
|
|
7
|
+
version = "0.1.2"
|
|
8
|
+
description = "Official Shield SDK for Python"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.8"
|
|
12
|
+
dependencies = ["requests>=2.28.0"]
|
|
13
|
+
|
|
14
|
+
[project.urls]
|
|
15
|
+
Homepage = "https://getshield.dev"
|
|
16
|
+
Documentation = "https://docs.getshield.dev"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from setuptools import setup, find_packages
|
|
2
|
-
|
|
3
|
-
setup(
|
|
4
|
-
name="shield-python",
|
|
5
|
-
version="0.1.
|
|
6
|
-
packages=find_packages(),
|
|
7
|
-
install_requires=["requests>=2.28.0"],
|
|
8
|
-
)
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="shield-python",
|
|
5
|
+
version="0.1.2",
|
|
6
|
+
packages=find_packages(),
|
|
7
|
+
install_requires=["requests>=2.28.0"],
|
|
8
|
+
)
|
|
@@ -18,7 +18,7 @@ class Client:
|
|
|
18
18
|
|
|
19
19
|
Args:
|
|
20
20
|
api_key: Your Shield API key.
|
|
21
|
-
base_url: Base URL for the Shield API. Defaults to https://getshield.dev/
|
|
21
|
+
base_url: Base URL for the Shield API. Defaults to https://api.getshield.dev/v1.
|
|
22
22
|
hmac_secret: Optional HMAC secret for request signing.
|
|
23
23
|
timeout: Request timeout in seconds. Defaults to 30.
|
|
24
24
|
"""
|
|
@@ -26,7 +26,7 @@ class Client:
|
|
|
26
26
|
def __init__(
|
|
27
27
|
self,
|
|
28
28
|
api_key: str,
|
|
29
|
-
base_url: str = "https://getshield.dev/
|
|
29
|
+
base_url: str = "https://api.getshield.dev/v1",
|
|
30
30
|
hmac_secret: Optional[str] = None,
|
|
31
31
|
timeout: int = 30,
|
|
32
32
|
):
|
|
@@ -79,7 +79,9 @@ class Client:
|
|
|
79
79
|
|
|
80
80
|
# HMAC signing
|
|
81
81
|
if self.hmac_secret:
|
|
82
|
+
import uuid
|
|
82
83
|
timestamp = str(int(time.time()))
|
|
84
|
+
nonce = str(uuid.uuid4())
|
|
83
85
|
body_hash = hashlib.sha256(body).hexdigest()
|
|
84
86
|
message = f"{timestamp}.{method}.{path}.{body_hash}"
|
|
85
87
|
signature = hmac_mod.new(
|
|
@@ -89,6 +91,7 @@ class Client:
|
|
|
89
91
|
).hexdigest()
|
|
90
92
|
headers["X-Shield-Signature"] = signature
|
|
91
93
|
headers["X-Shield-Timestamp"] = timestamp
|
|
94
|
+
headers["X-Shield-Nonce"] = nonce
|
|
92
95
|
|
|
93
96
|
try:
|
|
94
97
|
response = self._session.request(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shield-python
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Official Shield SDK for Python
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Homepage, https://getshield.dev
|
|
@@ -11,7 +11,7 @@ Requires-Dist: requests>=2.28.0
|
|
|
11
11
|
|
|
12
12
|
# Shield Python SDK
|
|
13
13
|
|
|
14
|
-
Official Python SDK for [Shield](https://getshield.dev)
|
|
14
|
+
Official Python SDK for [Shield](https://getshield.dev) ??tamper-evident session recording for online business transactions.
|
|
15
15
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
@@ -27,7 +27,7 @@ import shield
|
|
|
27
27
|
client = shield.Client(api_key="sk_live_your_api_key")
|
|
28
28
|
|
|
29
29
|
# Create a session
|
|
30
|
-
session = client.sessions.create(title="
|
|
30
|
+
session = client.sessions.create(title="Contract Negotiation with Acme Corp")
|
|
31
31
|
session_id = session["id"]
|
|
32
32
|
|
|
33
33
|
# Record events
|
|
@@ -75,8 +75,8 @@ client = shield.Client(
|
|
|
75
75
|
|
|
76
76
|
When an HMAC secret is configured, the SDK computes a signature for each request:
|
|
77
77
|
|
|
78
|
-
- `X-Shield-Timestamp`
|
|
79
|
-
- `X-Shield-Signature`
|
|
78
|
+
- `X-Shield-Timestamp` ??Unix timestamp of the request
|
|
79
|
+
- `X-Shield-Signature` ??HMAC-SHA256 of `{timestamp}.{METHOD}.{path}.{SHA256(body)}`
|
|
80
80
|
|
|
81
81
|
The server validates these headers to ensure requests have not been tampered with or replayed.
|
|
82
82
|
|
|
@@ -192,7 +192,7 @@ async def verify_session(session_id: str):
|
|
|
192
192
|
|
|
193
193
|
## Event Types Reference
|
|
194
194
|
|
|
195
|
-
Shield Standard Event Taxonomy v1.0
|
|
195
|
+
Shield Standard Event Taxonomy v1.0 ??37 event types across 7 categories:
|
|
196
196
|
|
|
197
197
|
### Party Events
|
|
198
198
|
| Event Type | Description |
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|