-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathopenapi.yaml
More file actions
272 lines (272 loc) · 17.7 KB
/
Copy pathopenapi.yaml
File metadata and controls
272 lines (272 loc) · 17.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
openapi: 3.1.0
info:
title: TyxNet API
version: 0.3.16
description: Experimental management, enrollment and device-control API.
servers:
- url: https://vpn.example.com
components:
securitySchemes:
bearerAuth: {type: http, scheme: bearer}
sessionCookie: {type: apiKey, in: cookie, name: tyxnet_session, description: Optional 30-day HTTPS-only browser session selected at login.}
schemas:
Error:
type: object
properties: {error: {type: object}}
Login:
type: object
required: [username, password]
properties: {username: {type: string}, password: {type: string, format: password}, remember: {type: boolean, default: false, description: Requests a 30-day Secure HttpOnly cookie and requires HTTPS.}}
DataPlaneBootstrap:
type: object
required: [protocol_version, session_id, secret, port, expires_at]
properties:
protocol_version: {type: integer, const: 1}
session_id: {type: string}
secret: {type: string, description: Base64url 256-bit secret delivered only over authenticated HTTPS.}
port: {type: integer, minimum: 1, maximum: 65535}
expires_at: {type: string, format: date-time}
PasswordUpdate:
type: object
required: [password]
properties: {password: {type: string, format: password, minLength: 12}}
TrafficFlow:
type: object
required: [source, destination, protocol, protocol_number, bytes, packets, mbps]
properties:
source: {type: string, format: ipv4}
destination: {type: string, format: ipv4}
protocol: {type: string, enum: [tcp, udp, icmp, other]}
protocol_number: {type: integer, minimum: 0, maximum: 255}
source_port: {type: integer, minimum: 0, maximum: 65535, description: Present for TCP and UDP first fragments with a complete transport header.}
destination_port: {type: integer, minimum: 0, maximum: 65535, description: Present for TCP and UDP first fragments with a complete transport header.}
icmp_type: {type: integer, minimum: 0, maximum: 255, description: Present for ICMP first fragments with a complete ICMP header.}
icmp_code: {type: integer, minimum: 0, maximum: 255, description: Present for ICMP first fragments with a complete ICMP header.}
bytes: {type: integer, minimum: 0}
packets: {type: integer, minimum: 0}
mbps: {type: number, minimum: 0, description: Five-second moving average in megabits per second.}
FlowHistoryRecord:
type: object
required: [id, recorded_at, source, destination, protocol, protocol_number, bytes, packets, storage_bytes]
properties:
id: {type: integer, minimum: 1}
recorded_at: {type: string, format: date-time, description: UTC start of the aggregated one-second bucket.}
source: {type: string, format: ipv4}
destination: {type: string, format: ipv4}
protocol: {type: string, enum: [tcp, udp, icmp, other]}
protocol_number: {type: integer, minimum: 0, maximum: 255}
source_port: {type: integer, minimum: 0, maximum: 65535}
destination_port: {type: integer, minimum: 0, maximum: 65535}
icmp_type: {type: integer, minimum: 0, maximum: 255}
icmp_code: {type: integer, minimum: 0, maximum: 255}
bytes: {type: integer, minimum: 0, description: Routed bytes in this one-second aggregate.}
packets: {type: integer, minimum: 0, description: Routed packets in this one-second aggregate.}
storage_bytes: {type: integer, minimum: 0, description: Logical metadata bytes charged to the configured flow-history budget.}
TrafficPoint:
type: object
properties:
timestamp: {type: string, format: date-time}
bytes: {type: integer, minimum: 0}
packets: {type: integer, minimum: 0}
mbps: {type: number, minimum: 0}
NetworkNode:
type: object
properties:
id: {type: string}
name: {type: string}
ip: {type: string}
kind: {type: string, enum: [server, device]}
online: {type: boolean}
platform: {type: string}
ControlCommand:
type: object
required: [protocol_version, id, type, created_at, expires_at]
properties:
protocol_version: {type: integer, const: 1}
id: {type: string}
type: {type: string, enum: [system.restart, system.shutdown, client.reconnect]}
created_at: {type: string, format: date-time}
expires_at: {type: string, format: date-time}
CommandResult:
type: object
required: [device_id, status, signature]
properties:
device_id: {type: string}
status: {type: string, enum: [accepted, succeeded, failed]}
result: {type: string, maxLength: 4096}
error: {type: string, maxLength: 4096}
signature: {type: string, description: Base64url Ed25519 signature over the domain-separated command-result proof.}
Enrollment:
type: object
required: [Token, Name, public_key]
properties:
Token: {type: string}
Name: {type: string}
OS: {type: string}
Arch: {type: string}
Version: {type: string}
public_key: {type: string, format: byte}
paths:
/healthz:
get: {responses: {'200': {description: Healthy}}}
/api/v1/auth/login:
post:
requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/Login'}}}}
responses: {'200': {description: Bearer session and optional secure persistent cookie}, '400': {description: Remembered login requested without HTTPS}, '401': {description: Invalid credentials}}
/api/v1/auth/logout:
post: {security: [{bearerAuth: []}], responses: {'204': {description: Logged out}}}
/api/v1/auth/me:
get: {security: [{bearerAuth: []}], responses: {'200': {description: Current user}}}
/api/v1/setup/status:
get: {description: Reports whether first-user setup is required and enabled for this request and returns the running server version, responses: {'200': {description: Setup state plus running version}}}
/api/v1/setup:
post: {description: Creates the first administrator on loopback or an explicitly enabled trusted-LAN listener and returns a bearer session, responses: {'201': {description: Administrator created}, '403': {description: Web setup disabled}, '409': {description: Setup already complete}}}
/api/v1/enroll:
post:
description: Consumes an enrollment token and records only the device public key.
requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/Enrollment'}}}}
responses: {'201': {description: Enrolled device}, '403': {description: Rejected}}
/control/v1/challenge:
post: {description: Issues a one-use 30-second device challenge, responses: {'200': {description: Challenge}}}
/control/v1/connect:
post: {description: Verifies Ed25519 proof and opens the versioned SSE control stream carrying authoritative virtual-IP and ping-interval state, an HTTPS-only short-lived encrypted UDP data-plane bootstrap, and allowlisted command events, responses: {'200': {description: Event stream}, '403': {description: Invalid proof}}}
/control/v1/commands/{id}/result:
post:
description: Consumes a fresh device challenge and records an Ed25519-authenticated command transition. The signature binds the challenge, device, command, status, result, and error.
parameters: [{in: path, name: id, required: true, schema: {type: string}}]
requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/CommandResult'}}}}
responses: {'200': {description: Result accepted}, '403': {description: Invalid or replayed device proof}, '409': {description: Invalid transition, target, or expiry}}
/api/v1/devices:
get: {description: Admin/operator/viewer receive all devices; member receives only devices owned by that user. Each device includes the server-authoritative Online live-connection state., security: [{bearerAuth: []}], responses: {'200': {description: Role-scoped devices}}}
/api/v1/devices/{id}:
patch:
description: Renames a device or, for administrators, assigns a persistent virtual IPv4 address inside the TyxNet network.
security: [{bearerAuth: []}]
parameters: [{in: path, name: id, required: true, schema: {type: string}}]
responses: {'200': {description: Device renamed}}
delete:
security: [{bearerAuth: []}]
parameters: [{in: path, name: id, required: true, schema: {type: string}}]
responses: {'204': {description: Revoked}}
/api/v1/devices/{id}/{action}:
post:
description: Queues restart, shutdown or disconnect. No arbitrary command text is accepted.
security: [{bearerAuth: []}]
parameters:
- {in: path, name: id, required: true, schema: {type: string}}
- {in: path, name: action, required: true, schema: {type: string, enum: [restart, shutdown, disconnect]}}
responses: {'202': {description: Queued command}}
/api/v1/users:
get: {security: [{bearerAuth: []}], responses: {'200': {description: Users}}}
post: {security: [{bearerAuth: []}], responses: {'201': {description: User created}}}
/api/v1/users/{id}:
patch:
security: [{bearerAuth: []}]
parameters: [{in: path, name: id, required: true, schema: {type: string}}]
responses: {'200': {description: Role or disabled state updated}}
delete:
security: [{bearerAuth: []}]
parameters: [{in: path, name: id, required: true, schema: {type: string}}]
responses: {'204': {description: Deleted}, '409': {description: User owns devices}}
/api/v1/users/{id}/password:
put:
description: Administrator-only password reset. Replaces the Argon2id password hash and revokes every existing session for the target user.
security: [{bearerAuth: []}]
parameters: [{in: path, name: id, required: true, schema: {type: string}}]
requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/PasswordUpdate'}}}}
responses: {'200': {description: Password updated and sessions revoked}, '400': {description: Password is shorter than 12 characters}, '403': {description: Administrator permission required}, '404': {description: User not found}}
/api/v1/tokens:
get: {security: [{bearerAuth: []}], responses: {'200': {description: Token metadata; never raw token values}}}
post: {security: [{bearerAuth: []}], responses: {'201': {description: Token value returned once}}}
/api/v1/tokens/{id}:
delete:
security: [{bearerAuth: []}]
parameters: [{in: path, name: id, required: true, schema: {type: string}}]
responses: {'204': {description: Revoked}}
/api/v1/server/status:
get: {security: [{bearerAuth: []}], responses: {'200': {description: Status counters, virtual-adapter readiness, and running server version}}}
/api/v1/network/flows:
get:
description: Returns the visible device topology plus payload-blind, in-memory IPv4 protocol/port metadata, packet counts, byte counts, five-second Mbps rates, and a 60-second series capped at 4096 unique flow keys. Admin, operator, and viewer roles are allowed; member is denied. Data remains empty while the UDP data plane is inactive.
security: [{bearerAuth: []}]
responses:
'200':
description: Live network-flow snapshot.
content:
application/json:
schema:
type: object
properties:
generated_at: {type: string, format: date-time}
window_seconds: {type: integer, const: 60}
rate_window_seconds: {type: integer, const: 5}
data_plane_ready: {type: boolean}
bytes: {type: integer, minimum: 0}
packets: {type: integer, minimum: 0}
mbps: {type: number, minimum: 0}
flows: {type: array, items: {$ref: '#/components/schemas/TrafficFlow'}}
series: {type: array, items: {$ref: '#/components/schemas/TrafficPoint'}}
nodes: {type: array, items: {$ref: '#/components/schemas/NetworkNode'}}
'403': {description: Role cannot view cross-device flow metadata.}
/api/v1/network/flows/history:
get:
description: Returns up to 500 persisted, payload-blind one-second flow aggregates. Recording is disabled by default and records are written only while the persistent setting is enabled. Admin, operator, and viewer roles are allowed.
security: [{bearerAuth: []}]
parameters:
- {in: query, name: q, schema: {type: string, maxLength: 128}, description: Case-insensitive current device name, endpoint, protocol, or port search.}
- {in: query, name: protocol, schema: {type: string, enum: [all, tcp, udp, icmp, other], default: all}}
- {in: query, name: from, schema: {type: string, format: date-time}, description: Inclusive UTC lower timestamp bound.}
- {in: query, name: to, schema: {type: string, format: date-time}, description: Inclusive UTC upper timestamp bound.}
- {in: query, name: sort, schema: {type: string, enum: [newest, oldest, bytes, packets], default: newest}}
responses:
'200':
description: Filtered flow history and current retention state.
content:
application/json:
schema:
type: object
required: [records, total, stored_bytes, recording_enabled, limit_mb]
properties:
records: {type: array, maxItems: 500, items: {$ref: '#/components/schemas/FlowHistoryRecord'}}
total: {type: integer, minimum: 0, description: Total records matching the supplied filters.}
stored_bytes: {type: integer, minimum: 0, description: Logical metadata bytes used by all flow-history records.}
recording_enabled: {type: boolean}
limit_mb: {type: integer, minimum: 1, maximum: 10240}
'400': {description: Invalid search, protocol, sort, or date range.}
'403': {description: Role cannot view cross-device flow metadata.}
delete:
description: Administrator-only deletion of every persisted flow-history record. Recording remains in its current state.
security: [{bearerAuth: []}]
responses:
'204': {description: All saved flow history deleted.}
'403': {description: Administrator permission required.}
/api/v1/server/settings:
get: {description: Returns administrator-managed persistent settings including listener ports, restart state, device ping interval, flow-history recording toggle, and logical metadata limit in MB, security: [{bearerAuth: []}], responses: {'200': {description: Server settings}}}
patch: {description: Persists one or more of api_port (1-65535), tunnel_port (1-65535), ping_interval_seconds (5-3600), flow_history_enabled, and flow_history_limit_mb (1-10240). Listener port changes take effect after server restart. Lowering the history limit immediately removes oldest records until the logical metadata budget is met., security: [{bearerAuth: []}], responses: {'200': {description: Updated settings}, '400': {description: Invalid setting or no setting supplied}}}
/api/v1/server/startup:
get: {description: Returns startup availability, registration state, and an unavailability reason when startup is managed by a container runtime, security: [{bearerAuth: []}], responses: {'200': {description: Startup capability and state}}}
patch: {description: Administrator-only creation or removal of the platform startup registration, security: [{bearerAuth: []}], responses: {'200': {description: Updated startup state}, '409': {description: Startup registration is unavailable in this runtime}}}
/api/v1/commands:
get:
description: Returns recent commands with queued, delivered, accepted, succeeded, failed, or expired status and sanitized result fields.
security: [{bearerAuth: []}]
responses: {'200': {description: Recent command delivery entries}}
/api/v1/audit:
get: {security: [{bearerAuth: []}], responses: {'200': {description: Recent audit events}}}
/api/management/login:
post: {description: Client-local allowlisted proxy to server login, responses: {'200': {description: Server bearer session}}}
/api/management/me:
get: {description: Client-local allowlisted proxy for current server user, security: [{bearerAuth: []}], responses: {'200': {description: Current role}}}
/api/management/devices:
get: {description: Client-local proxy for the role-scoped server device list, security: [{bearerAuth: []}], responses: {'200': {description: Permitted devices}}}
/api/management/devices/{id}/{action}:
post: {description: Client-local proxy for an RBAC-checked allowlisted device action, security: [{bearerAuth: []}], responses: {'202': {description: Command queued}}}
/api/management/startup:
get: {description: Returns this client's platform startup state after server-admin authentication, security: [{bearerAuth: []}], responses: {'200': {description: Startup state}}}
patch: {description: Creates or removes this client's platform startup registration after server-admin authentication, security: [{bearerAuth: []}], responses: {'200': {description: Updated startup state}}}
/api/tray:
get: {description: Token-authenticated loopback-only tray snapshot, responses: {'200': {description: Local connection, startup state and cached permitted devices}, '403': {description: Invalid local tray authentication}}}
/api/tray/startup:
post: {description: Token-authenticated loopback-only platform startup toggle, responses: {'200': {description: Updated startup state}, '403': {description: Invalid local tray authentication}}}
/api/tray/quit:
post: {description: Token-authenticated loopback-only graceful application shutdown, responses: {'202': {description: Shutdown accepted}, '403': {description: Invalid local tray authentication}}}