Skip to content

Commit 8d73b5d

Browse files
authored
Merge pull request #52 from jagerman/v4-onion-req
v4 onion requests
2 parents 3c9c8b1 + 06c6ddc commit 8d73b5d

File tree

9 files changed

+624
-125
lines changed

9 files changed

+624
-125
lines changed

.drone.jsonnet

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ local default_deps = [
1111
'python3-uwsgidecorators',
1212
'python3-flask',
1313
'python3-cryptography',
14+
'python3-pycryptodome',
1415
'python3-nacl',
1516
'python3-pil',
1617
'python3-protobuf',

api.yaml

Lines changed: 44 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,7 +1346,7 @@ paths:
13461346
200:
13471347
$ref: "#/paths/~1batch/post/responses/200"
13481348

1349-
/oxen/v3/lsrpc:
1349+
/oxen/v4/lsrpc:
13501350
post:
13511351
tags: [Onion]
13521352
summary: "Endpoint for submitting an encrypted onion request"
@@ -1359,66 +1359,54 @@ paths:
13591359
the onion encryption layer; the onion encryption payload itself is documented elsewhere.
13601360
required: true
13611361
content:
1362-
application/json:
1362+
application/octet-stream:
13631363
schema:
1364-
type: object
1365-
required: [endpoint, method, headers]
1366-
properties:
1367-
method:
1368-
type: string
1369-
description: "The request method type as a string, i.e. `GET`, `POST`, `PUT`, `DELETE`."
1370-
endpoint:
1371-
type: string
1372-
description: >
1373-
The request path, e.g. `/room/123/messages/since/45678`. This name should be
1374-
the full path beginning with a `/`; methods without a leading / are
1375-
interpreted as legacy endpoints for older versions of Session and should not
1376-
be used.
1377-
headers:
1378-
type: object
1379-
description: >
1380-
HTTP headers for the request; should usually include the pubkey, nonce,
1381-
timestamp, and signature headers (`X-SOGS-Pubkey`, etc.), and sometimes a
1382-
`Content-Type` header (the latter, if omitted, defaults to `application/json`
1383-
if using `body`, and `application/octet-stream` if using `body_binary`).
1384-
body:
1385-
description: >
1386-
Request body of the onion request. This is typically used for text-based
1387-
values (such as JSON requests). Exclusive of `body_binary`. Not accepted for
1388-
`GET` requests.
1389-
type: string
1390-
body_binary:
1391-
description: >
1392-
Request body for a onion request to a binary endpoint, with the body encoded
1393-
in base64. Exclusive of `body`. Not accepted for `GET` requests.
1394-
1395-
1396-
The endpoint will be called with the *decoded* byte value as its body, thus
1397-
allowing you to POST to endpoints that require binary data (such as file
1398-
uploads). Note that when using the Content-Type header defaults to
1399-
`application/octet-stream`.
1400-
1401-
1402-
Note that when including a signature in the `X-SOGS-Signature` header, the
1403-
signature must use the decoded byte value of the body, *not* the encoded
1404-
base64 value.
1405-
1406-
1407-
This is somewhat wasteful because of the overhead of base64-encoding, but is a
1408-
limitation of onion requests.
1409-
type: string
1410-
format: byte
1364+
type: string
1365+
format: binary
1366+
description: >
1367+
The onion request data. This is encoded/encrypted in multiple layers, as follows.
1368+
1369+
1370+
The data is first constructed as one or two parts: the first part is json contains
1371+
request metadata with fields:
1372+
- method -- "GET", "POST", etc. of the subrequest
1373+
- endpoint -- the subrequest endpoint, e.g. `/room/some-room/messages/since/123`
1374+
- headers -- request headers, typically containing X-SOGS-* auth info and, for
1375+
POST/PUT requests, a Content-Type.
1376+
1377+
1378+
The second part is the request body, in bytes (only for POST/PUT requests).
1379+
1380+
1381+
These two pieces are encoded as a one- or two-string bencoded list, which has format:
1382+
1383+
1384+
`l123:jsone` or `l123:json456:bodye` where 123 is the length of the json and 456 is
1385+
the length of the body, if the request has a body. (Both strings are byte strings).
1386+
1387+
1388+
This data is then encrypted using onion-request style encryption; see the
1389+
oxen-storage-server for details on how this is done.
14111390
responses:
14121391
200:
14131392
description: >
1414-
Request completed. The actual response will be base64-encoded and encrypted. For
1415-
requests that fail with an HTTP response (i.e. other than 200) the response will
1416-
base64+decrypt to the json value `{"status_code": N}` where `N` is the integer error
1417-
code that occurred (e.g. 404).
1393+
Onion request completed. The subrequest response will be encoded in a two-string
1394+
bencoded list (see the request details for the encoding specifics) where the first
1395+
string contains the response metadata as json with keys:
14181396
1419-
For successful (i.e. 200) responses the returned value is whatever the body of the
1420-
request returned. (Returning headers via onion requests is not supported.)
1421-
1397+
1398+
- code -- the HTTP response code of the subrequest, e.g. 200, 404
1399+
- headers -- a dict of HTTP response headers; the header name keys are always
1400+
lower-cased.
1401+
1402+
1403+
The second part is the response body bytes; as in HTTP, interpreting this depends on the
1404+
`content-type` header in the `headers` metadata, and the details of the invoked
1405+
endpoint.
1406+
1407+
1408+
These two byte strings are bencoded, and then the bencoded data is encrypted using the
1409+
same ephemeral key and encryption type as was used in the request.
14221410
14231411
components:
14241412
schemas:

sogs/routes/general.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,15 +143,13 @@ def batch(_sequential=False):
143143
response = []
144144
for method, path, headers, json, body in subreqs:
145145
try:
146-
subres = make_subrequest(method, path, headers=headers, body=body, json=json)
146+
subres, headers = make_subrequest(method, path, headers=headers, body=body, json=json)
147147
if subres.content_type == "application/json":
148148
body = subres.get_json()
149149
else:
150150
body = subres.get_data()
151151

152-
response.append(
153-
{"code": subres.status_code, "content-type": subres.content_type, "body": body}
154-
)
152+
response.append({"code": subres.status_code, "headers": headers, "body": body})
155153
except Exception as e:
156154
app.logger.warning(f"Batch subrequest failed: {e}")
157155
response.append(

0 commit comments

Comments
 (0)