Files
zerotier-one-api-spec/main.tsp
T

528 lines
12 KiB
Plaintext

import "@typespec/http";
import "@typespec/openapi";
import "@typespec/json-schema";
import "./variables.tsp";
using TypeSpec.Http;
using TypeSpec.OpenAPI;
using TypeSpec.JsonSchema;
@service({
title: "ZeroTierOne Service",
version: Version,
})
@info({
license: {
name: "Apache 2.0",
url: "http://www.apache.org/licenses/LICENSE-2.0.html",
},
})
@useAuth(ApiKeyAuth<ApiKeyLocation.header, "X-ZT1-AUTH">)
@server(" http://localhost:9993", "Service API")
@doc("""
<p>This API controls the ZeroTier service that runs in the background on your computer. This is how zerotier-cli, and the macOS and Windows apps control the service. </p>
<p>API requests must be authenticated via an authentication token. ZeroTier One saves this token in the authtoken.secret file in its working directory. This token may be supplied via the X-ZT1-Auth HTTP request header. </p>
<p>For example: <code>curl -H "X-ZT1-Auth: $TOKEN" http://localhost:9993/status</code> </p>
<p>The token can be found in: <ul> <li>Mac :: ~/Library/Application Support/ZeroTier/authtoken.secret</li> <li>Windows :: \\ProgramData\\ZeroTier\\One</li> <li>Linux :: /var/lib/zerotier-one</li> </ul> </p>
<p>Learn more about the spec at <a href="https://github.com/zerotier/zerotier-one-api-spec">github</a></p>
""")
namespace Root {
@tag("Node Status")
@route("/status")
namespace node_status {
@get
@summary("Node Status")
op readStatus(): NodeStatus | AuthError;
}
@tag("Joined Networks")
@route("/network")
namespace network_membership {
@doc("All the networks that this node is joined to")
@summary("List Joined Networks")
@get
op readNetworks(): JoinedNetwork[] | AuthError;
@route("/{network_id}")
@doc("Joined Network by ID")
@summary("Get Joined Network by ID")
@get
op getNetwork(
@path network_id: ZTNetworkID,
): JoinedNetwork | AuthError | NotFoundError;
@summary("Join or Update Network Settings")
@post
op setNetwork(
@path network_id: ZTNetworkID,
@body settings: JoinedNetworkRequest,
): JoinedNetwork | AuthError | NotFoundError;
@summary("Leave Network")
@delete
op delNetwork(
@path network_id: ZTNetworkID,
): LeaveResult | AuthError | NotFoundError;
}
@tag("Peers")
@route("/peer")
namespace node_peer {
@doc("All the nodes your node knows about")
@summary("List Peers")
@get
op readNetworks(): Peer[] | AuthError;
@route("/{network_id}")
@doc("Get Peer by ID")
@summary("Get Joined Network by ID")
@get
op getNetwork(
@path network_id: ZTNetworkID,
): Peer | AuthError | NotFoundError;
}
@tag("Controller")
@route("/controller")
namespace controller {
@doc("Controller healthcheck")
@summary("Controller Status")
@get
op readControllerStatus(): ControllerStatus | AuthError;
@route("/network")
namespace network {
@doc("List IDs of all networks hosted by this controller")
@summary("List Network IDs")
@get
op readNetworks(): ControllerNetworkIDList | AuthError;
@route("/{network_id}")
namespace network {
@doc("Get details for a network by its ID.")
@summary("Get Network by ID")
@get
op readNetwork(
@path network_id: ZTNetworkID,
): ControllerNetwork | AuthError | NotFoundError;
@summary("Create or Update Network")
@post
op postNetwork(
@path network_id: ZTNetworkID,
@body network: ControllerNetworkRequest,
): ControllerNetwork | AuthError | NotFoundError;
@summary("Delete Network")
@delete
op deleteNetwork(
@path network_id: ZTNetworkID,
): ControllerNetwork | AuthError | NotFoundError;
@route("/member")
namespace networkMembers {
@doc("Object containing all member IDs as keys and their memberRevisionCounter values as values")
@summary("List Network Member IDs ")
@get
op listNetworkMembers(
@doc("Network ID of the Network")
@path
network_id: ZTNetworkID,
): ControllerNetworkMemberList | AuthError | NotFoundError;
@route("/{node_id}")
namespace networkMember {
@summary("Get Network Member by ID")
@get
op getNetworkMember(
@doc("Node ID of the Network Member")
@path
node_id: ZTAddress,
@doc("Network ID of the Network")
@path
network_id: ZTNetworkID,
): ControllerNetworkMember | AuthError | NotFoundError;
@summary("Create or Update Network Member")
@post
op postNetworkMember(
@doc("Node ID of the Network Member")
@path
node_id: ZTAddress,
@doc("Network ID of the Network")
@path
network_id: ZTNetworkID,
@body network: ControllerNetworkMemberRequest,
): ControllerNetworkMember | AuthError | NotFoundError;
@summary("Delete Network Member")
@delete
op delNetworkMember(
@doc("Node ID of the Network Member")
@path
node_id: ZTAddress,
@doc("Network ID of the Network")
@path
network_id: ZTNetworkID,
): ControllerNetworkMember | AuthError | NotFoundError;
}
}
}
@route("/")
namespace randomNetwork {
@doc("Create a new network with a random ID.")
@summary("Generate Random Network ID")
@post
op randomNetwork(
@doc("Node ID of the controller")
@body
network: ControllerNetworkRequest,
): ControllerNetwork | AuthError | NotFoundError;
}
}
}
@tag("Unstable")
@route("/unstable")
namespace unstable {
@route("/controller")
namespace controller {
@route("/network")
namespace network {
@doc("List all networks")
@summary("List all networks")
@get
op readNetworks2(): ControllerNetworks | AuthError;
@route("/{network_id}")
namespace network_id {
@route("/member")
namespace member {
@doc("List all Network Members")
@summary("List all Network Members")
@get
op listNetworkMembers2(
@doc("Network ID of the Network")
@path
network_id: ZTNetworkID,
): ControllerNetworkMemberListFull | AuthError | NotFoundError;
}
}
}
}
}
}
@jsonSchema
model LeaveResult {
result: true;
}
@jsonSchema
model NodeStatus {
address: ZTAddress;
clock: uSafeint;
config: {
settings: {
allowManagementFrom?: IPSlashPort[];
allowTcpFallbackRelay: boolean;
forceTcpRelay: boolean;
listeningOn: IPSlashPort[];
portMappingEnabled: boolean;
primaryPort: Port;
secondaryPort: Port;
softwareUpdate: string;
softwareUpdateChannel: string;
surfaceAddresses: IPSlashPort[];
tertiaryPort: Port;
};
};
online: boolean;
planetWorldId: uSafeint;
planetWorldTimestamp: uSafeint;
publicIdentity: string;
tcpFallbackActive: boolean;
version: string;
versionBuild: VersionDigit | -1;
versionMajor: VersionDigit | -1;
versionMinor: VersionDigit | -1;
versionRev: VersionDigit | -1;
}
@jsonSchema
model JoinedNetwork extends Record<unknown> {
...JoinedNetworkProps;
assignedAddresses: string[];
bridge: boolean;
broadcastEnabled: boolean;
dns: NetworkDNS | EmptyArray;
@key id: ZTNetworkID;
mac: string;
mtu: MTU;
multicastSubscriptions: Array<{
adi: uSafeint;
mac: string;
}>;
@format("uri")
authenticationURL?: string;
authenticationExpiryTime?: uSafeint;
name: string;
netconfRevision: uint16;
portDeviceName: string;
portError: int32;
routes: {
flags: uint16;
metric: uint16;
target: IPSlashPort;
via?: IP | null;
}[];
status: NetworkStatus;
type: "PUBLIC" | "PRIVATE";
}
@jsonSchema
model JoinedNetworks is JoinedNetwork[];
@jsonSchema
model JoinedNetworkRequest {
...OptionalProperties<JoinedNetworkProps>;
}
model JoinedNetworkProps {
allowDNS: boolean;
allowDefault: boolean;
allowManaged: boolean;
allowGlobal: boolean;
}
@jsonSchema
model Peer {
@key address: ZTAddress;
isBonded: boolean;
latency: uSafeint | -1;
paths: {
active: boolean;
address: IPSlashPort;
expired: boolean;
lastReceive: uSafeint;
lastSend: uSafeint;
localSocket: uSafeint;
preferred: boolean;
trustedPathId: uSafeint;
}[];
role: "LEAF" | "PLANET" | "MOON";
version: string;
versionMajor: VersionDigit | -1;
versionMinor: VersionDigit | -1;
versionRev: VersionDigit | -1;
tunneled: boolean;
}
@jsonSchema
model Peers is Peer[];
@jsonSchema
model ControllerStatus {
controller: true;
apiVersion: VersionDigit;
clock: uSafeint;
databaseReady: boolean;
}
@jsonSchema
model ControllerNetwork {
...ControllerNetworkProps;
@key id: ZTNetworkID;
nwid: ZTNetworkID;
creationTime: uSafeint;
objtype: "network";
revision: uSafeint;
capabilities: NetworkCaps;
rules: NetworkRule[];
tags: NetworkTags;
}
model ControllerNetworkMeta {
...ControllerNetwork;
meta: {
authorizedMemberCount: uSafeint;
totalMemberCount: uSafeint;
};
}
@jsonSchema
model ControllerNetworks {
data: ControllerNetwork[];
meta: {
networkCount: uSafeint;
};
}
@jsonSchema
model ControllerNetworkRequest {
...OptionalProperties<ControllerNetworkProps>;
}
model ControllerNetworkProps {
name: string;
enableBroadcast: boolean;
mtu: MTU;
dns: NetworkDNS | EmptyArray;
private: boolean;
ipAssignmentPools: {
ipRangeStart: IP;
ipRangeEnd: IP;
}[];
v4AssignMode: {
zt?: boolean;
};
v6AssignMode: {
`6plane`?: boolean;
rfc4193?: boolean;
zt?: boolean;
};
multicastLimit: uSafeint;
routes: {
target: IP;
via?: IP | null;
}[];
}
@jsonSchema
model ControllerNetworkMember {
@key id: ZTAddress;
...OptionalProperties<ControllerNetworkMemberProps>;
address: ZTAddress;
authenticationExpiryTime: uSafeint;
capabilities: uSafeint[];
creationTime: uSafeint;
identity?: string;
lastAuthorizedCredential: string | null;
lastAuthorizedCredentialType: string;
lastAuthorizedTime: uSafeint;
lastDeauthorizedTime: uSafeint;
nwid: ZTNetworkID;
objtype: "member";
remoteTraceLevel: uSafeint;
remoteTraceTarget: string | null;
revision: VersionDigit;
tags: unknown; //TODO
vMajor: VersionDigit | -1;
vMinor: VersionDigit | -1;
vProto: VersionDigit | -1;
vRev: VersionDigit | -1;
}
@jsonSchema
model ControllerNetworkMemberRequest {
...OptionalProperties<ControllerNetworkMemberProps>;
}
model ControllerNetworkMemberProps {
authorized: boolean;
activeBridge: boolean;
ipAssignments: IP[];
name: string;
noAutoAssignIps: boolean;
ssoExempt: boolean;
}
@jsonSchema
model ControllerNetworkIDList is ZTNetworkID[];
@error
model AuthError {
@statusCode statusCode: 401;
@body error: {};
}
@error
model NotFoundError {
@statusCode statusCode: 404;
@body error: {};
}
@pattern("[a-f0-9]{10}")
scalar ZTAddress extends string;
@pattern("[a-f0-9]{16}")
scalar ZTNetworkID extends string;
@format("ipv4")
scalar IPv4 extends string;
@format("ipv6")
scalar IPv6 extends string;
alias IP = IPv4 | IPv6;
scalar IPSlashPort extends string;
@minValue(1280)
scalar MTU extends uint32;
@minValue(0)
scalar VersionDigit extends uint8;
@minValue(0)
scalar Clock extends safeint;
@minValue(0)
scalar uSafeint extends safeint;
@minItems(2)
@maxItems(2)
model NetworkCap is integer[];
model NetworkCaps is NetworkCap[];
@minItems(2)
@maxItems(2)
model NetworkTag is integer[];
model NetworkTags is NetworkTag[];
model NetworkRule extends Record<unknown> {
not?: boolean;
or?: boolean;
type: string;
}
model NetworkDNS {
domain: domain | "";
servers: IP[];
}
@minItems(0)
@maxItems(0)
model EmptyArray is Array<unknown>;
@format("hostname")
scalar domain extends string;
@jsonSchema
model ControllerNetworkMemberList is Record<int32>;
@jsonSchema
model ControllerNetworkMemberListFull {
data: ControllerNetworkMember[];
meta: {
totalCount: uSafeint;
authorizedCount: uSafeint;
};
}
@minValue(0)
scalar Port extends uint16;
alias NetworkStatus =
| "REQUESTING_CONFIGURATION"
| "OK"
| "ACCESS_DENIED"
| "NOT_FOUND"
| "PORT_ERROR"
| "CLIENT_TOO_OLD"
| "AUTHENTICATION_REQUIRED";