auths_cli/commands/device/pair/
mod.rs1mod common;
7mod join;
8#[cfg(feature = "lan-pairing")]
9mod lan;
10#[cfg(feature = "lan-pairing")]
11mod lan_server;
12#[cfg(feature = "lan-pairing")]
13mod mdns;
14mod offline;
15mod online;
16
17use anyhow::Result;
18use auths_core::config::EnvironmentConfig;
19use clap::Parser;
20
21#[cfg(not(feature = "lan-pairing"))]
23const DEFAULT_REGISTRY: &str = "http://localhost:3000";
24
25#[derive(Parser, Debug, Clone)]
26#[command(about = "Link devices to your identity")]
27pub struct PairCommand {
28 #[clap(long, value_name = "CODE")]
30 pub join: Option<String>,
31
32 #[clap(long, value_name = "URL")]
34 pub registry: Option<String>,
35
36 #[clap(long)]
38 pub no_qr: bool,
39
40 #[clap(long, value_name = "SECONDS", default_value = "300")]
42 pub expiry: u64,
43
44 #[clap(long)]
46 pub offline: bool,
47
48 #[clap(long, value_delimiter = ',', default_value = "sign_commit")]
50 pub capabilities: Vec<String>,
51
52 #[cfg(feature = "lan-pairing")]
54 #[clap(long)]
55 pub no_mdns: bool,
56}
57
58pub fn handle_pair(
68 cmd: PairCommand,
69 http_client: &reqwest::Client,
70 env_config: &EnvironmentConfig,
71) -> Result<()> {
72 match (&cmd.join, &cmd.registry, cmd.offline) {
73 (None, _, true) => {
75 offline::handle_initiate_offline(cmd.no_qr, cmd.expiry, &cmd.capabilities)
76 }
77
78 (Some(code), Some(registry), _) => {
80 let rt = tokio::runtime::Runtime::new()?;
81 rt.block_on(join::handle_join(code, registry))
82 }
83
84 #[cfg(feature = "lan-pairing")]
86 (Some(code), None, _) => {
87 let rt = tokio::runtime::Runtime::new()?;
88 rt.block_on(lan::handle_join_lan(code))
89 }
90
91 #[cfg(not(feature = "lan-pairing"))]
93 (Some(code), None, _) => {
94 let rt = tokio::runtime::Runtime::new()?;
95 rt.block_on(join::handle_join(code, DEFAULT_REGISTRY))
96 }
97
98 (None, Some(registry), _) => {
100 let rt = tokio::runtime::Runtime::new()?;
101 rt.block_on(online::handle_initiate_online(
102 http_client,
103 registry,
104 cmd.no_qr,
105 cmd.expiry,
106 &cmd.capabilities,
107 env_config,
108 ))
109 }
110
111 #[cfg(feature = "lan-pairing")]
113 (None, None, false) => {
114 let rt = tokio::runtime::Runtime::new()?;
115 rt.block_on(lan::handle_initiate_lan(
116 cmd.no_qr,
117 cmd.no_mdns,
118 cmd.expiry,
119 &cmd.capabilities,
120 env_config,
121 ))
122 }
123
124 #[cfg(not(feature = "lan-pairing"))]
126 (None, None, false) => {
127 let rt = tokio::runtime::Runtime::new()?;
128 rt.block_on(online::handle_initiate_online(
129 http_client,
130 DEFAULT_REGISTRY,
131 cmd.no_qr,
132 cmd.expiry,
133 &cmd.capabilities,
134 env_config,
135 ))
136 }
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use auths_core::pairing::normalize_short_code;
143
144 #[test]
145 fn test_code_normalization() {
146 let codes = vec![
147 ("AB3DEF", "AB3DEF"),
148 ("ab3def", "AB3DEF"),
149 ("AB3 DEF", "AB3DEF"),
150 ("AB3-DEF", "AB3DEF"),
151 ("a b 3 d e f", "AB3DEF"),
152 ];
153
154 for (input, expected) in codes {
155 let normalized = normalize_short_code(input);
156 assert_eq!(normalized, expected, "Input: '{}'", input);
157 }
158 }
159}