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
use ed25519_dalek::Keypair as Ed25519Keypair; use eui48::MacAddress; use rand::{rngs::OsRng, Rng}; use serde::{Deserialize, Serialize}; use std::net::IpAddr; use crate::{accessory::AccessoryCategory, BonjourFeatureFlag, BonjourStatusFlag, Pin}; /// The `Config` struct is used to store configuration options for the HomeKit Accessory Server. /// /// # Examples /// /// ``` /// use hap::{accessory::AccessoryCategory, Config, MacAddress, Pin}; /// /// let config = Config { /// pin: Pin::new([1, 1, 1, 2, 2, 3, 3, 3]).unwrap(), /// name: "Acme Lightbulb".into(), /// device_id: MacAddress::new([10, 20, 30, 40, 50, 60]), /// category: AccessoryCategory::Lightbulb, /// ..Default::default() /// }; /// ``` #[derive(Debug, Serialize, Deserialize)] pub struct Config { /// Socket IP address to serve on. Defaults to the IP of the system's first non-loopback network interface. pub host: IpAddr, /// Port to serve on. Defaults to `32000`. pub port: u16, /// 8 digit pin used for pairing. Defaults to `11122333`. /// /// The following pins are considered too easy and are therefore not allowed: /// - `12345678` /// - `87654321` /// - `00000000` /// - `11111111` /// - `22222222` /// - `33333333` /// - `44444444` /// - `55555555` /// - `66666666` /// - `77777777` /// - `88888888` /// - `99999999` pub pin: Pin, /// Model name of the accessory. E.g. "Acme Lightbulb". pub name: String, /// Device ID of the accessory. Generated randomly if not specified. This value is also used as the accessory's /// Pairing Identifier. Must be a unique random number generated at every factory reset and must persist across /// reboots. pub device_id: MacAddress, // Bonjour: id /// pub device_ed25519_keypair: Ed25519Keypair, /// Current configuration number. Is updated when an accessory, service, or characteristic is added or removed on /// the accessory server. Accessories must increment the config number after a firmware update. pub configuration_number: u64, // Bonjour: c# /// Current state number. This must have a value of `1`. pub state_number: u8, // Bonjour: s# /// Accessory category. Indicates the category that best describes the primary function of the accessory. pub category: AccessoryCategory, // Bonjour: ci /// Protocol version string `<major>.<minor>` (e.g. `"1.0"`). Defaults to `"1.0"` Required if value is not `"1.0"`. pub protocol_version: String, // Bonjour: pv /// Bonjour Status Flag. Defaults to `StatusFlag::NotPaired` and is changed to `StatusFlag::Zero` after a /// successful pairing. pub status_flag: BonjourStatusFlag, // Bonjour: sf /// Bonjour Feature Flag. Currently only used to indicate MFi compliance. pub feature_flag: BonjourFeatureFlag, // Bonjour: ff /// Optional maximum number of paired controllers. pub max_peers: Option<usize>, } impl Config { /// Redetermines the `host` field to the IP of the system's first non-loopback network interface. pub fn redetermine_local_ip(&mut self) { self.host = get_local_ip(); } /// Derives mDNS TXT records from the `Config`. pub(crate) fn txt_records(&self) -> [String; 8] { [ format!("c#={}", self.configuration_number), format!("ff={}", self.feature_flag as u8), format!("id={}", self.device_id.to_hex_string()), format!("md={}", self.name), format!("pv={}", self.protocol_version), format!("s#={}", self.state_number), format!("sf={}", self.status_flag as u8), format!("ci={}", self.category as u8), // format!("sh={}", self.setup_hash as u8), setup hash seems to be still undocumented ] } } impl Default for Config { fn default() -> Config { Config { host: get_local_ip(), port: 32000, pin: Pin::new([1, 1, 1, 2, 2, 3, 3, 3]).unwrap(), name: "Accessory".into(), device_id: generate_random_mac_address(), device_ed25519_keypair: generate_ed25519_keypair(), configuration_number: 1, state_number: 1, category: AccessoryCategory::Other, protocol_version: "1.0".into(), status_flag: BonjourStatusFlag::NotPaired, feature_flag: BonjourFeatureFlag::Zero, max_peers: None, } } } // Generates a random MAC address. fn generate_random_mac_address() -> MacAddress { let mut csprng = OsRng {}; let eui = csprng.gen::<[u8; 6]>(); MacAddress::new(eui) } // Generates an Ed25519 keypair. fn generate_ed25519_keypair() -> Ed25519Keypair { let mut csprng = OsRng {}; Ed25519Keypair::generate(&mut csprng) } /// Returns the IP of the system's first non-loopback network interface or defaults to `127.0.0.1`. fn get_local_ip() -> IpAddr { for iface in get_if_addrs::get_if_addrs().unwrap() { if !iface.is_loopback() { return iface.ip(); } } "127.0.0.1".parse().unwrap() }