diff --git a/Cargo.lock b/Cargo.lock index 9b148b9..bfc5f76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "dnapi-rs" -version = "0.2.1" +version = "0.2.2" dependencies = [ "base64 0.21.5", "base64-serde", @@ -3085,6 +3085,7 @@ dependencies = [ "diesel", "diesel-async", "diesel_migrations", + "dnapi-rs", "env_logger", "hex", "log", diff --git a/dnapi-rs/Cargo.toml b/dnapi-rs/Cargo.toml index 22492aa..39572c2 100644 --- a/dnapi-rs/Cargo.toml +++ b/dnapi-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dnapi-rs" -version = "0.2.1" +version = "0.2.2" edition = "2021" description = "A rust client for the Defined Networking API" license = "AGPL-3.0-or-later" diff --git a/dnapi-rs/src/message.rs b/dnapi-rs/src/message.rs index e3a934f..c272a6e 100644 --- a/dnapi-rs/src/message.rs +++ b/dnapi-rs/src/message.rs @@ -13,7 +13,7 @@ pub const DO_UPDATE: &str = "DoUpdate"; base64_serde_type!(Base64Standard, base64::engine::general_purpose::STANDARD); -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] /// `RequestV1` is the version 1 `DNClient` request message. pub struct RequestV1 { /// Version is always 1 @@ -30,7 +30,7 @@ pub struct RequestV1 { pub signature: Vec, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] /// `RequestWrapper` wraps a `DNClient` request message. It consists of a /// type and value, with the type string indicating how to interpret the value blob. pub struct RequestWrapper { @@ -48,14 +48,14 @@ pub struct RequestWrapper { pub timestamp: String, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] /// `SignedResponseWrapper` contains a response message and a signature to validate inside `data`. pub struct SignedResponseWrapper { /// The response data contained in this message pub data: SignedResponse, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] /// `SignedResponse` contains a response message and a signature to validate. pub struct SignedResponse { /// The API version - always 1 @@ -68,14 +68,14 @@ pub struct SignedResponse { pub signature: Vec, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] /// `CheckForUpdateResponseWrapper` contains a response to `CheckForUpdate` inside "data." pub struct CheckForUpdateResponseWrapper { /// The response data contained in this message pub data: CheckForUpdateResponse, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] /// `CheckForUpdateResponse` is the response generated for a `CheckForUpdate` request. pub struct CheckForUpdateResponse { #[serde(rename = "updateAvailable")] @@ -83,7 +83,7 @@ pub struct CheckForUpdateResponse { pub update_available: bool, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] /// `DoUpdateRequest` is the request sent for a `DoUpdate` request. pub struct DoUpdateRequest { #[serde(rename = "edPubkeyPEM")] @@ -100,7 +100,7 @@ pub struct DoUpdateRequest { pub nonce: Vec, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] /// A server response to a `DoUpdateRequest`, with the updated config and key information pub struct DoUpdateResponse { #[serde(with = "Base64Standard")] @@ -141,7 +141,7 @@ pub struct EnrollRequest { pub timestamp: String, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] #[serde(untagged)] /// The response to an `EnrollRequest` pub enum EnrollResponse { @@ -157,7 +157,7 @@ pub enum EnrollResponse { }, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] /// The data included in an successful enrollment. pub struct EnrollResponseData { #[serde(with = "Base64Standard")] @@ -176,7 +176,7 @@ pub struct EnrollResponseData { pub organization: EnrollResponseDataOrg, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] /// The organization data that this node is now a part of pub struct EnrollResponseDataOrg { /// The organization ID that this node is now a part of @@ -185,7 +185,7 @@ pub struct EnrollResponseDataOrg { pub name: String, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] /// `APIError` represents a single error returned in an API error response. pub struct APIError { /// The error code diff --git a/trifid-api/Cargo.toml b/trifid-api/Cargo.toml index 63abcf7..5feb8fb 100644 --- a/trifid-api/Cargo.toml +++ b/trifid-api/Cargo.toml @@ -30,4 +30,5 @@ trifid-pki = { version = "0.1", path = "../trifid-pki", features = ["serde_deriv chacha20poly1305 = "0.10" hex = "0.4" thiserror = "1" -chrono = "0.4" \ No newline at end of file +chrono = "0.4" +dnapi-rs = { version = "0.2", path = "../dnapi-rs" } \ No newline at end of file diff --git a/trifid-api/migrations/2023-12-24-220412_create_table_roles/up.sql b/trifid-api/migrations/2023-12-24-220412_create_table_roles/up.sql index f3261b8..bb2b41c 100644 --- a/trifid-api/migrations/2023-12-24-220412_create_table_roles/up.sql +++ b/trifid-api/migrations/2023-12-24-220412_create_table_roles/up.sql @@ -2,5 +2,5 @@ CREATE TABLE roles ( id VARCHAR NOT NULL PRIMARY KEY, name VARCHAR NOT NULL, description VARCHAR NOT NULL, - organizationId VARCHAR NOT NULL REFERENCES organizations(id) + organization_id VARCHAR NOT NULL REFERENCES organizations(id) ); \ No newline at end of file diff --git a/trifid-api/migrations/2023-12-24-220423_create_table_role_firewall_rules/up.sql b/trifid-api/migrations/2023-12-24-220423_create_table_role_firewall_rules/up.sql index 34fd074..95bc0fb 100644 --- a/trifid-api/migrations/2023-12-24-220423_create_table_role_firewall_rules/up.sql +++ b/trifid-api/migrations/2023-12-24-220423_create_table_role_firewall_rules/up.sql @@ -1,9 +1,9 @@ CREATE TABLE role_firewall_rules ( - id VARCHAR NOT NULL UNIQUE, - roleId VARCHAR NOT NULL REFERENCES roles(id), + id VARCHAR NOT NULL PRIMARY KEY, + role_id VARCHAR NOT NULL REFERENCES roles(id), protocol VARCHAR NOT NULL, description VARCHAR NOT NULL, - allowedRoleId VARCHAR NULL, - allowedTags VARCHAR[], - portRange int4range NULL + allowed_role_id VARCHAR NULL, + allowed_tags text[] NOT NULL, + port_range int4range NULL ); \ No newline at end of file diff --git a/trifid-api/migrations/2023-12-24-220434_create_table_hosts/up.sql b/trifid-api/migrations/2023-12-24-220434_create_table_hosts/up.sql index bcb58c1..6d032e3 100644 --- a/trifid-api/migrations/2023-12-24-220434_create_table_hosts/up.sql +++ b/trifid-api/migrations/2023-12-24-220434_create_table_hosts/up.sql @@ -1,21 +1,21 @@ CREATE TABLE hosts ( id VARCHAR NOT NULL PRIMARY KEY, - organizationId VARCHAR NOT NULL REFERENCES organizations(id), - networkId VARCHAR NOT NULL REFERENCES networks(id), - roleId VARCHAR NULL REFERENCES roles(id), + organization_id VARCHAR NOT NULL REFERENCES organizations(id), + network_id VARCHAR NOT NULL REFERENCES networks(id), + role_id VARCHAR NULL REFERENCES roles(id), name VARCHAR NOT NULL, - ipAddress VARCHAR NOT NULL, - staticAddresses VARCHAR[] NOT NULL, - listenPort int2 NOT NULL, - isLighthouse BOOLEAN NOT NULL, - isRelay BOOLEAN NOT NULL, - createdAt TIMESTAMP NOT NULL, - isBlocked BOOLEAN NOT NULL, + ip_address VARCHAR NOT NULL, + static_addresses text[] NOT NULL, + listen_port int2 NOT NULL, + is_lighthouse BOOLEAN NOT NULL, + is_relay BOOLEAN NOT NULL, + created_at TIMESTAMP NOT NULL, + is_blocked BOOLEAN NOT NULL, - lastSeenAt TIMESTAMP NULL, - clientVersion VARCHAR NULL, + last_seen_at TIMESTAMP NULL, + client_version VARCHAR NULL, platform VARCHAR NULL, - updateAvailable BOOLEAN NULL, + update_available BOOLEAN NULL, - tags VARCHAR[] NOT NULL + tags text[] NOT NULL ); \ No newline at end of file diff --git a/trifid-api/migrations/2023-12-24-222225_create_table_host_overrides/up.sql b/trifid-api/migrations/2023-12-24-222225_create_table_host_overrides/up.sql index 9ae401f..078cda2 100644 --- a/trifid-api/migrations/2023-12-24-222225_create_table_host_overrides/up.sql +++ b/trifid-api/migrations/2023-12-24-222225_create_table_host_overrides/up.sql @@ -1,6 +1,6 @@ CREATE TABLE host_overrides ( id VARCHAR NOT NULL PRIMARY KEY, - hostId VARCHAR NOT NULL REFERENCES hosts(id), + host_id VARCHAR NOT NULL REFERENCES hosts(id), key VARCHAR NOT NULL, value jsonb NOT NULL ); \ No newline at end of file diff --git a/trifid-api/migrations/2023-12-24-222227_create_table_host_keys/down.sql b/trifid-api/migrations/2023-12-24-222227_create_table_host_keys/down.sql index d9a93fe..2a70353 100644 --- a/trifid-api/migrations/2023-12-24-222227_create_table_host_keys/down.sql +++ b/trifid-api/migrations/2023-12-24-222227_create_table_host_keys/down.sql @@ -1 +1 @@ --- This file should undo anything in `up.sql` +DROP TABLE host_keys; \ No newline at end of file diff --git a/trifid-api/migrations/2023-12-24-222227_create_table_host_keys/up.sql b/trifid-api/migrations/2023-12-24-222227_create_table_host_keys/up.sql index 23c7dbd..e61c0c3 100644 --- a/trifid-api/migrations/2023-12-24-222227_create_table_host_keys/up.sql +++ b/trifid-api/migrations/2023-12-24-222227_create_table_host_keys/up.sql @@ -1,11 +1,11 @@ CREATE TABLE host_keys ( id VARCHAR NOT NULL PRIMARY KEY, - hostId VARCHAR NOT NULL REFERENCES hosts(id), + host_id VARCHAR NOT NULL REFERENCES hosts(id), counter INT NOT NULL, client_ed_pub bytea NOT NULL, client_dh_pub bytea NOT NULL, client_cert bytea NOT NULL, - UNIQUE (hostId, counter) + UNIQUE (host_id, counter) ); \ No newline at end of file diff --git a/trifid-api/migrations/2023-12-25-192018_create_table_enrollment_codes/down.sql b/trifid-api/migrations/2023-12-25-192018_create_table_enrollment_codes/down.sql new file mode 100644 index 0000000..ec2503a --- /dev/null +++ b/trifid-api/migrations/2023-12-25-192018_create_table_enrollment_codes/down.sql @@ -0,0 +1 @@ +DROP TABLE enrollment_codes; \ No newline at end of file diff --git a/trifid-api/migrations/2023-12-25-192018_create_table_enrollment_codes/up.sql b/trifid-api/migrations/2023-12-25-192018_create_table_enrollment_codes/up.sql new file mode 100644 index 0000000..e878e4b --- /dev/null +++ b/trifid-api/migrations/2023-12-25-192018_create_table_enrollment_codes/up.sql @@ -0,0 +1,5 @@ +CREATE TABLE enrollment_codes ( + id VARCHAR NOT NULL PRIMARY KEY, + host_id VARCHAR NOT NULL REFERENCES hosts(id), + expires TIMESTAMP NOT NULL +); \ No newline at end of file diff --git a/trifid-api/src/ca.rs b/trifid-api/src/ca.rs index a150e2b..45fd023 100644 --- a/trifid-api/src/ca.rs +++ b/trifid-api/src/ca.rs @@ -112,7 +112,8 @@ pub fn sign_cert_with_ca( .map_err(|_| CryptographyError::InvalidKeyLength)?; let salt_u24: [u8; 24] = ca - .salt.clone() + .salt + .clone() .try_into() .map_err(|_| CryptographyError::InvalidSaltLength)?; diff --git a/trifid-api/src/id.rs b/trifid-api/src/id.rs index c4b7805..590040c 100644 --- a/trifid-api/src/id.rs +++ b/trifid-api/src/id.rs @@ -31,10 +31,11 @@ macro_rules! randid { } pub fn random_with_charset(len: u32, charset: &[u8]) -> String { - (0..(len-2)) + (0..(len - 2)) .map(|_| { let idx = rand::thread_rng().gen_range(0..charset.len()); charset[idx] as char }) - .collect::() + "tf" + .collect::() + + "tf" } diff --git a/trifid-api/src/models.rs b/trifid-api/src/models.rs index 02043a0..4293d64 100644 --- a/trifid-api/src/models.rs +++ b/trifid-api/src/models.rs @@ -1,6 +1,7 @@ use diesel::{Associations, Identifiable, Insertable, Queryable, Selectable}; use serde::{Deserialize, Serialize}; use serde_json::Value; +use std::ops::{Bound, Range}; use std::time::SystemTime; #[derive( @@ -206,3 +207,155 @@ pub struct NetworkNormalized { pub name: String, pub lighthouses_as_relays: bool, } + +#[derive( + Queryable, + Selectable, + Insertable, + Identifiable, + Associations, + Debug, + PartialEq, + Clone, + Serialize, + Deserialize, +)] +#[diesel(belongs_to(Organization))] +#[diesel(table_name = crate::schema::roles)] +#[diesel(check_for_backend(diesel::pg::Pg))] +pub struct Role { + pub id: String, + pub name: String, + pub description: String, + pub organization_id: String, +} + +#[derive( + Queryable, + Selectable, + Insertable, + Identifiable, + Associations, + Debug, + PartialEq, + Clone, + Serialize, + Deserialize, +)] +#[diesel(belongs_to(Role))] +#[diesel(table_name = crate::schema::role_firewall_rules)] +#[diesel(check_for_backend(diesel::pg::Pg))] +pub struct RoleFirewallRule { + pub id: String, + pub role_id: String, + pub protocol: String, + pub description: String, + pub allowed_role_id: Option, + pub allowed_tags: Vec>, // postgres WHYYY + pub port_range: Option<(Bound, Bound)>, +} + +#[derive( + Queryable, + Selectable, + Insertable, + Identifiable, + Associations, + Debug, + PartialEq, + Clone, + Serialize, + Deserialize, +)] +#[diesel(belongs_to(Organization))] +#[diesel(belongs_to(Network))] +#[diesel(belongs_to(Role))] +#[diesel(table_name = crate::schema::hosts)] +#[diesel(check_for_backend(diesel::pg::Pg))] +pub struct Host { + pub id: String, + pub organization_id: String, + pub network_id: String, + pub role_id: Option, + pub name: String, + pub ip_address: String, + pub static_addresses: Vec>, + pub listen_port: i16, + pub is_lighthouse: bool, + pub is_relay: bool, + pub created_at: SystemTime, + pub is_blocked: bool, + pub last_seen_at: Option, + pub client_version: Option, + pub platform: Option, + pub update_available: Option, + pub tags: Vec>, +} + +#[derive( + Queryable, + Selectable, + Insertable, + Identifiable, + Associations, + Debug, + PartialEq, + Clone, + Serialize, + Deserialize, +)] +#[diesel(belongs_to(Host))] +#[diesel(table_name = crate::schema::host_overrides)] +#[diesel(check_for_backend(diesel::pg::Pg))] +pub struct HostOverride { + pub id: String, + pub host_id: String, + pub key: String, + pub value: Value, +} + +#[derive( + Queryable, + Selectable, + Insertable, + Identifiable, + Associations, + Debug, + PartialEq, + Clone, + Serialize, + Deserialize, +)] +#[diesel(belongs_to(Host))] +#[diesel(table_name = crate::schema::host_keys)] +#[diesel(check_for_backend(diesel::pg::Pg))] +pub struct HostKey { + pub id: String, + pub host_id: String, + + pub counter: i32, + pub client_ed_pub: Vec, + pub client_dh_pub: Vec, + pub client_cert: Vec, +} + +#[derive( + Queryable, + Selectable, + Insertable, + Identifiable, + Associations, + Debug, + PartialEq, + Clone, + Serialize, + Deserialize, +)] +#[diesel(belongs_to(Host))] +#[diesel(table_name = crate::schema::enrollment_codes)] +#[diesel(check_for_backend(diesel::pg::Pg))] +pub struct EnrollmentCode { + pub id: String, + pub host_id: String, + pub expires: SystemTime, +} diff --git a/trifid-api/src/routes/mod.rs b/trifid-api/src/routes/mod.rs index a3a6d96..ae6adc7 100644 --- a/trifid-api/src/routes/mod.rs +++ b/trifid-api/src/routes/mod.rs @@ -1 +1,2 @@ pub mod v1; +pub mod v2; diff --git a/trifid-api/src/routes/v1/networks.rs b/trifid-api/src/routes/v1/networks.rs index 592b4af..c8baf8e 100644 --- a/trifid-api/src/routes/v1/networks.rs +++ b/trifid-api/src/routes/v1/networks.rs @@ -1,18 +1,18 @@ use crate::ca::create_signing_ca; use crate::models::{Network, NetworkNormalized, Organization, SigningCA, User}; use crate::response::JsonAPIResponse; -use crate::schema::{users}; +use crate::schema::networks::dsl::networks; +use crate::schema::organizations::dsl::organizations; +use crate::schema::signing_cas::dsl::signing_cas; +use crate::schema::users; use crate::{auth, enforce, randid, AppState}; use actix_web::web::{Data, Json}; use actix_web::HttpRequest; +use chrono::{DateTime, SecondsFormat, Utc}; use diesel::{ExpressionMethods, QueryDsl, SelectableHelper}; use diesel_async::RunQueryDsl; use serde::{Deserialize, Serialize}; use std::time::{Duration, SystemTime}; -use chrono::{DateTime, SecondsFormat, Utc}; -use crate::schema::networks::dsl::networks; -use crate::schema::organizations::dsl::organizations; -use crate::schema::signing_cas::dsl::signing_cas; #[derive(Deserialize, Debug)] pub struct CreateNetworkReq { @@ -79,21 +79,36 @@ pub async fn create_network_req( lighthouses_as_relays: true, }; - handle_error!(diesel::insert_into(organizations) - .values(&new_org) - .execute(&mut conn).await); - handle_error!(diesel::insert_into(signing_cas) - .values(&ca_oneyear) - .execute(&mut conn).await); - handle_error!(diesel::insert_into(signing_cas) - .values(&ca_twoyears) - .execute(&mut conn).await); - handle_error!(diesel::insert_into(signing_cas) - .values(&ca_threeyears) - .execute(&mut conn).await); - handle_error!(diesel::insert_into(networks) - .values(&new_network) - .execute(&mut conn).await); + handle_error!( + diesel::insert_into(organizations) + .values(&new_org) + .execute(&mut conn) + .await + ); + handle_error!( + diesel::insert_into(signing_cas) + .values(&ca_oneyear) + .execute(&mut conn) + .await + ); + handle_error!( + diesel::insert_into(signing_cas) + .values(&ca_twoyears) + .execute(&mut conn) + .await + ); + handle_error!( + diesel::insert_into(signing_cas) + .values(&ca_threeyears) + .execute(&mut conn) + .await + ); + handle_error!( + diesel::insert_into(networks) + .values(&new_network) + .execute(&mut conn) + .await + ); let cdt: DateTime = DateTime::from(new_network.created_at); diff --git a/trifid-api/src/routes/v2/enroll.rs b/trifid-api/src/routes/v2/enroll.rs new file mode 100644 index 0000000..9a78cd0 --- /dev/null +++ b/trifid-api/src/routes/v2/enroll.rs @@ -0,0 +1,13 @@ +use crate::response::JsonAPIResponse; +use crate::AppState; +use actix_web::web::{Data, Json}; +use dnapi_rs::message::{EnrollRequest, EnrollResponse}; + +pub async fn enroll_req( + req: Json, + state: Data, +) -> JsonAPIResponse { + let mut conn = handle_error!(state.pool.get().await); + + todo!() +} diff --git a/trifid-api/src/routes/v2/mod.rs b/trifid-api/src/routes/v2/mod.rs new file mode 100644 index 0000000..fa6b687 --- /dev/null +++ b/trifid-api/src/routes/v2/mod.rs @@ -0,0 +1 @@ +pub mod enroll; diff --git a/trifid-api/src/schema.rs b/trifid-api/src/schema.rs index be252bc..770dac9 100644 --- a/trifid-api/src/schema.rs +++ b/trifid-api/src/schema.rs @@ -8,6 +8,56 @@ diesel::table! { } } +diesel::table! { + enrollment_codes (id) { + id -> Varchar, + host_id -> Varchar, + expires -> Timestamp, + } +} + +diesel::table! { + host_keys (id) { + id -> Varchar, + host_id -> Varchar, + counter -> Int4, + client_ed_pub -> Bytea, + client_dh_pub -> Bytea, + client_cert -> Bytea, + } +} + +diesel::table! { + host_overrides (id) { + id -> Varchar, + host_id -> Varchar, + key -> Varchar, + value -> Jsonb, + } +} + +diesel::table! { + hosts (id) { + id -> Varchar, + organization_id -> Varchar, + network_id -> Varchar, + role_id -> Nullable, + name -> Varchar, + ip_address -> Varchar, + static_addresses -> Array>, + listen_port -> Int2, + is_lighthouse -> Bool, + is_relay -> Bool, + created_at -> Timestamp, + is_blocked -> Bool, + last_seen_at -> Nullable, + client_version -> Nullable, + platform -> Nullable, + update_available -> Nullable, + tags -> Array>, + } +} + diesel::table! { magic_links (id) { id -> Varchar, @@ -36,6 +86,27 @@ diesel::table! { } } +diesel::table! { + role_firewall_rules (id) { + id -> Varchar, + role_id -> Varchar, + protocol -> Varchar, + description -> Varchar, + allowed_role_id -> Nullable, + allowed_tags -> Array>, + port_range -> Nullable, + } +} + +diesel::table! { + roles (id) { + id -> Varchar, + name -> Varchar, + description -> Varchar, + organization_id -> Varchar, + } +} + diesel::table! { session_tokens (id) { id -> Varchar, @@ -77,19 +148,33 @@ diesel::table! { } diesel::joinable!(auth_tokens -> users (user_id)); +diesel::joinable!(enrollment_codes -> hosts (host_id)); +diesel::joinable!(host_keys -> hosts (host_id)); +diesel::joinable!(host_overrides -> hosts (host_id)); +diesel::joinable!(hosts -> networks (network_id)); +diesel::joinable!(hosts -> organizations (organization_id)); +diesel::joinable!(hosts -> roles (role_id)); diesel::joinable!(magic_links -> users (user_id)); diesel::joinable!(networks -> organizations (organization_id)); diesel::joinable!(networks -> signing_cas (signing_ca_id)); diesel::joinable!(organizations -> users (owner_id)); +diesel::joinable!(role_firewall_rules -> roles (role_id)); +diesel::joinable!(roles -> organizations (organization_id)); diesel::joinable!(session_tokens -> users (user_id)); diesel::joinable!(signing_cas -> organizations (organization_id)); diesel::joinable!(totp_authenticators -> users (user_id)); diesel::allow_tables_to_appear_in_same_query!( auth_tokens, + enrollment_codes, + host_keys, + host_overrides, + hosts, magic_links, networks, organizations, + role_firewall_rules, + roles, session_tokens, signing_cas, totp_authenticators,