gl_client/pairing/
new_device.rs1use super::PairingSessionData;
2use crate::{
3 credentials::{Device, TlsConfigProvider},
4 pb::scheduler::{pairing_client::PairingClient, PairDeviceRequest},
5 tls::{self, TlsConfig},
6};
7use log::debug;
8use tokio::sync::mpsc;
9use tonic::transport::Channel;
10
11type Result<T, E = super::Error> = core::result::Result<T, E>;
12
13pub struct Unconnected();
14pub struct Connected(PairingClient<Channel>);
15
16pub struct Client<T> {
17 inner: T,
18 uri: String,
19 tls: TlsConfig,
20}
21
22impl Client<Unconnected> {
23 pub fn new<T>(creds: T) -> Client<Unconnected>
24 where
25 T: TlsConfigProvider,
26 {
27 Client {
28 inner: Unconnected(),
29 uri: crate::utils::scheduler_uri(),
30 tls: creds.tls_config(),
31 }
32 }
33}
34
35impl Client<Unconnected> {
36 pub fn with_uri(mut self, uri: String) -> Client<Unconnected> {
37 self.uri = uri;
38 self
39 }
40
41 pub async fn connect(self) -> Result<Client<Connected>> {
42 let channel = tonic::transport::Endpoint::from_shared(self.uri.clone())?
43 .tls_config(self.tls.inner.clone())?
44 .tcp_keepalive(Some(crate::TCP_KEEPALIVE))
45 .http2_keep_alive_interval(crate::TCP_KEEPALIVE)
46 .keep_alive_timeout(crate::TCP_KEEPALIVE_TIMEOUT)
47 .keep_alive_while_idle(true)
48 .connect_lazy();
49 Ok(Client {
50 inner: Connected(PairingClient::new(channel)),
51 uri: self.uri,
52 tls: self.tls,
53 })
54 }
55}
56
57impl Client<Connected> {
58 pub async fn pair_device(
59 &self,
60 name: &str,
61 description: &str,
62 restrictions: &str,
63 ) -> Result<mpsc::Receiver<PairingSessionData>> {
64 debug!("Start a new pairing request");
65
66 let device_name = name.to_string();
67 let description = description.to_string();
68
69 let kp = tls::generate_ecdsa_key_pair();
71
72 let device_cert = tls::generate_self_signed_device_cert(
74 &hex::encode("00"), name,
76 vec!["localhost".into()],
77 Some(kp),
78 );
79 let device_id = hex::encode(device_cert.get_key_pair().public_key_raw());
80 let csr = device_cert.serialize_request_pem()?;
81
82 let mut restriction = format!("pubkey={}", device_id.clone());
85 if !restrictions.is_empty() {
86 restriction = format!("{}&{}", restriction, restrictions);
88 }
89 let restrictions = restriction;
90
91 let (tx, rx) = mpsc::channel(1);
93
94 let mut client = self.inner.0.clone();
95 tokio::spawn(async move {
98 let request = client.pair_device(PairDeviceRequest {
101 device_id: device_id.clone(),
102 csr: csr.into_bytes(),
103 device_name,
104 description,
105 restrictions,
106 });
107
108 let data = format!("gl-pairing:{}", device_id);
111 tx.send(PairingSessionData::PairingQr(data))
112 .await
113 .expect("could not pass qr data to the channel"); let _ = match request.await {
118 Ok(r) => {
119 let mut res = r.into_inner();
120 res.device_key = device_cert.serialize_private_key_pem();
121 let creds = Device::with(
122 res.device_cert.clone().into_bytes(),
123 res.device_key.clone().into_bytes(),
124 res.rune.clone(),
125 );
126
127 res.creds = creds.into();
128 tx.send(PairingSessionData::PairingResponse(res))
129 }
130 Err(e) => {
131 debug!("got an error during pairing process {}.", e);
132 tx.send(PairingSessionData::PairingError(e))
133 }
134 }
135 .await;
136
137 return;
138 });
139
140 Ok(rx)
141 }
142}