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, hide_short_help = true)]
38 pub no_qr: bool,
39
40 #[clap(
42 long,
43 visible_alias = "expiry",
44 value_name = "SECONDS",
45 default_value = "300"
46 )]
47 pub timeout: u64,
48
49 #[clap(long, hide_short_help = true)]
51 pub offline: bool,
52
53 #[clap(
55 long,
56 value_delimiter = ',',
57 default_value = "sign_commit",
58 hide_short_help = true
59 )]
60 pub capabilities: Vec<String>,
61
62 #[cfg(feature = "lan-pairing")]
64 #[clap(long, hide_short_help = true)]
65 pub no_mdns: bool,
66}
67
68pub fn handle_pair(cmd: PairCommand, env_config: &EnvironmentConfig) -> Result<()> {
78 match (&cmd.join, &cmd.registry, cmd.offline) {
79 (None, _, true) => {
81 offline::handle_initiate_offline(cmd.no_qr, cmd.timeout, &cmd.capabilities)
82 }
83
84 (Some(code), Some(registry), _) => {
86 let rt = tokio::runtime::Runtime::new()?;
87 rt.block_on(join::handle_join(code, registry, env_config))
88 }
89
90 #[cfg(feature = "lan-pairing")]
92 (Some(code), None, _) => {
93 let rt = tokio::runtime::Runtime::new()?;
94 rt.block_on(lan::handle_join_lan(code, env_config))
95 }
96
97 #[cfg(not(feature = "lan-pairing"))]
99 (Some(code), None, _) => {
100 let rt = tokio::runtime::Runtime::new()?;
101 rt.block_on(join::handle_join(code, DEFAULT_REGISTRY, env_config))
102 }
103
104 (None, Some(registry), _) => {
106 let rt = tokio::runtime::Runtime::new()?;
107 rt.block_on(online::handle_initiate_online(
108 registry,
109 cmd.no_qr,
110 cmd.timeout,
111 &cmd.capabilities,
112 env_config,
113 ))
114 }
115
116 #[cfg(feature = "lan-pairing")]
118 (None, None, false) => {
119 let rt = tokio::runtime::Runtime::new()?;
120 rt.block_on(lan::handle_initiate_lan(
121 cmd.no_qr,
122 cmd.no_mdns,
123 cmd.timeout,
124 &cmd.capabilities,
125 env_config,
126 ))
127 }
128
129 #[cfg(not(feature = "lan-pairing"))]
131 (None, None, false) => {
132 let rt = tokio::runtime::Runtime::new()?;
133 rt.block_on(online::handle_initiate_online(
134 DEFAULT_REGISTRY,
135 cmd.no_qr,
136 cmd.timeout,
137 &cmd.capabilities,
138 env_config,
139 ))
140 }
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use auths_core::pairing::normalize_short_code;
147
148 #[test]
149 fn test_code_normalization() {
150 let codes = vec![
151 ("AB3DEF", "AB3DEF"),
152 ("ab3def", "AB3DEF"),
153 ("AB3 DEF", "AB3DEF"),
154 ("AB3-DEF", "AB3DEF"),
155 ("a b 3 d e f", "AB3DEF"),
156 ];
157
158 for (input, expected) in codes {
159 let normalized = normalize_short_code(input);
160 assert_eq!(normalized, expected, "Input: '{}'", input);
161 }
162 }
163}