aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXe Iaso <me@christine.website>2022-07-10 20:48:13 +0000
committerXe Iaso <me@christine.website>2022-07-10 20:48:13 +0000
commit95016c89eb7707a476501f96327dcad11831b1a0 (patch)
tree4701a78f7536ee5370487b92335eefb5741f7cab
parent55bf7e4cb403566d7172ef69b8f2f7393ac8627d (diff)
downloadxesite-95016c89eb7707a476501f96327dcad11831b1a0.tar.xz
xesite-95016c89eb7707a476501f96327dcad11831b1a0.zip
add basic ts_localapi crate
Signed-off-by: Xe Iaso <me@christine.website>
-rw-r--r--Cargo.lock24
-rw-r--r--lib/ts_localapi/Cargo.toml11
-rw-r--r--lib/ts_localapi/src/lib.rs119
3 files changed, 154 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 1e55a07..a2d1948 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1228,6 +1228,19 @@ dependencies = [
]
[[package]]
+name = "hyperlocal"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fafdf7b2b2de7c9784f76e02c0935e65a8117ec3b768644379983ab333ac98c"
+dependencies = [
+ "futures-util",
+ "hex",
+ "hyper",
+ "pin-project",
+ "tokio",
+]
+
+[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2989,6 +3002,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
+name = "ts_localapi"
+version = "0.1.0"
+dependencies = [
+ "hyper",
+ "hyperlocal",
+ "serde",
+ "serde_json",
+ "thiserror",
+]
+
+[[package]]
name = "typed-arena"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/lib/ts_localapi/Cargo.toml b/lib/ts_localapi/Cargo.toml
new file mode 100644
index 0000000..20d325e
--- /dev/null
+++ b/lib/ts_localapi/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "ts_localapi"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+hyper = "0.14"
+hyperlocal = "0.8"
+serde = { version = "1", features = [ "derive" ] }
+serde_json = "1"
+thiserror = "1" \ No newline at end of file
diff --git a/lib/ts_localapi/src/lib.rs b/lib/ts_localapi/src/lib.rs
new file mode 100644
index 0000000..5201a02
--- /dev/null
+++ b/lib/ts_localapi/src/lib.rs
@@ -0,0 +1,119 @@
+use hyper::{body::Buf, Client};
+use hyperlocal::{UnixClientExt, Uri};
+use serde::{Deserialize, Serialize};
+use std::net::SocketAddr;
+
+#[derive(Debug, thiserror::Error)]
+pub enum Error {
+ #[error("hyper error: {0}")]
+ Hyper(#[from] hyper::Error),
+
+ #[error("json error: {0}")]
+ JSON(#[from] serde_json::Error),
+}
+
+#[derive(Clone, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct WhoisResponse {
+ #[serde(rename = "Node")]
+ pub node: WhoisPeer,
+ #[serde(rename = "UserProfile")]
+ pub user_profile: User,
+}
+
+pub async fn whois(ip: SocketAddr) -> Result<WhoisResponse, Error> {
+ let url = Uri::new(
+ "/var/run/tailscale/tailscaled.sock",
+ &format!("/localapi/v0/whois?addr={ip}"),
+ )
+ .into();
+ let client = Client::unix();
+
+ let resp = client.get(url).await?;
+ if !resp.status().is_success() {
+ panic!("TODO(Xe): handle {}", resp.status());
+ }
+
+ let body = hyper::body::aggregate(resp).await?;
+
+ Ok(serde_json::from_reader(body.reader())?)
+}
+
+#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
+pub struct User {
+ #[serde(rename = "ID")]
+ pub id: u64,
+ #[serde(rename = "LoginName")]
+ pub login_name: String,
+ #[serde(rename = "DisplayName")]
+ pub display_name: String,
+ #[serde(rename = "ProfilePicURL")]
+ pub profile_pic_url: String,
+ #[serde(rename = "Roles")]
+ pub roles: Vec<Option<serde_json::Value>>,
+}
+
+#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct WhoisPeer {
+ #[serde(rename = "ID")]
+ pub id: i64,
+ #[serde(rename = "StableID")]
+ pub stable_id: String,
+ #[serde(rename = "Name")]
+ pub name: String,
+ #[serde(rename = "User")]
+ pub user: i64,
+ #[serde(rename = "Key")]
+ pub key: String,
+ #[serde(rename = "KeyExpiry")]
+ pub key_expiry: String,
+ #[serde(rename = "Machine")]
+ pub machine: String,
+ #[serde(rename = "DiscoKey")]
+ pub disco_key: String,
+ #[serde(rename = "Addresses")]
+ pub addresses: Vec<String>,
+ #[serde(rename = "AllowedIPs")]
+ pub allowed_ips: Vec<String>,
+ #[serde(rename = "Endpoints")]
+ pub endpoints: Vec<String>,
+ #[serde(rename = "Hostinfo")]
+ pub hostinfo: Hostinfo,
+ #[serde(rename = "Created")]
+ pub created: String,
+ #[serde(rename = "PrimaryRoutes")]
+ pub primary_routes: Option<Vec<String>>,
+ #[serde(rename = "MachineAuthorized")]
+ pub machine_authorized: Option<bool>,
+ #[serde(rename = "Capabilities")]
+ pub capabilities: Option<Vec<String>>,
+ #[serde(rename = "ComputedName")]
+ pub computed_name: String,
+ #[serde(rename = "ComputedNameWithHost")]
+ pub computed_name_with_host: String,
+}
+
+#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Hostinfo {
+ #[serde(rename = "OS")]
+ pub os: String,
+ #[serde(rename = "Hostname")]
+ pub hostname: String,
+ #[serde(rename = "RoutableIPs")]
+ pub routable_ips: Option<Vec<String>>,
+ #[serde(rename = "Services")]
+ pub services: Vec<Service>,
+}
+
+#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Service {
+ #[serde(rename = "Proto")]
+ pub proto: String,
+ #[serde(rename = "Port")]
+ pub port: i64,
+ #[serde(rename = "Description")]
+ pub description: Option<String>,
+}