This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / knot2 / crates / knot-ssh / src / server.rs
5.0 kB 183 lines
1use std::collections::{HashMap, HashSet}; 2use std::net::{IpAddr, SocketAddr}; 3use std::sync::Arc; 4 5use knot_runtime::{Clock, HttpTransport}; 6use knot_types::OfferedKey; 7use russh::keys::ssh_key; 8use russh::server::{Auth, Handler, Msg, Server, Session}; 9use russh::{Channel, ChannelId}; 10use tokio_util::task::TaskTracker; 11 12use crate::SshState; 13use crate::exec::run_exec; 14 15pub(crate) struct KnotSshServer<H, C> { 16 pub(crate) state: Arc<SshState<H, C>>, 17 pub(crate) tracker: TaskTracker, 18} 19 20impl<H: HttpTransport, C: Clock> Server for KnotSshServer<H, C> { 21 type Handler = KnotSession<H, C>; 22 23 fn new_client(&mut self, peer: Option<SocketAddr>) -> Self::Handler { 24 KnotSession::new( 25 Arc::clone(&self.state), 26 self.tracker.clone(), 27 peer.map(|addr| addr.ip()), 28 ) 29 } 30} 31 32pub(crate) struct KnotSession<H, C> { 33 state: Arc<SshState<H, C>>, 34 tracker: TaskTracker, 35 key: Option<OfferedKey>, 36 channels: HashMap<ChannelId, Channel<Msg>>, 37 protocols: HashSet<ChannelId>, 38 peer: Option<IpAddr>, 39} 40 41impl<H, C> KnotSession<H, C> { 42 fn new(state: Arc<SshState<H, C>>, tracker: TaskTracker, peer: Option<IpAddr>) -> Self { 43 Self { 44 state, 45 tracker, 46 key: None, 47 channels: HashMap::new(), 48 protocols: HashSet::new(), 49 peer, 50 } 51 } 52} 53 54impl<H: HttpTransport, C: Clock> Handler for KnotSession<H, C> { 55 type Error = russh::Error; 56 57 async fn auth_publickey( 58 &mut self, 59 _user: &str, 60 public_key: &ssh_key::PublicKey, 61 ) -> Result<Auth, Self::Error> { 62 let reject = Auth::Reject { 63 proceed_with_methods: None, 64 partial_success: false, 65 }; 66 let Ok(blob) = public_key.to_bytes() else { 67 return Ok(reject); 68 }; 69 let key = OfferedKey::from_bytes(blob); 70 if self 71 .state 72 .roster 73 .recognizes_fresh(&key, &self.state.index, &self.state.atproto) 74 .await 75 { 76 self.key = Some(key); 77 Ok(Auth::Accept) 78 } else { 79 Ok(reject) 80 } 81 } 82 83 async fn channel_open_session( 84 &mut self, 85 channel: Channel<Msg>, 86 _session: &mut Session, 87 ) -> Result<bool, Self::Error> { 88 self.channels.insert(channel.id(), channel); 89 Ok(true) 90 } 91 92 async fn env_request( 93 &mut self, 94 channel: ChannelId, 95 variable_name: &str, 96 variable_value: &str, 97 _session: &mut Session, 98 ) -> Result<(), Self::Error> { 99 if variable_name == "GIT_PROTOCOL" 100 && variable_value 101 .split(':') 102 .any(|token| token.trim() == "version=2") 103 { 104 self.protocols.insert(channel); 105 } 106 Ok(()) 107 } 108 109 async fn channel_eof( 110 &mut self, 111 channel: ChannelId, 112 _session: &mut Session, 113 ) -> Result<(), Self::Error> { 114 self.protocols.remove(&channel); 115 Ok(()) 116 } 117 118 async fn channel_close( 119 &mut self, 120 channel: ChannelId, 121 _session: &mut Session, 122 ) -> Result<(), Self::Error> { 123 self.channels.remove(&channel); 124 self.protocols.remove(&channel); 125 Ok(()) 126 } 127 128 #[allow(clippy::too_many_arguments)] 129 async fn pty_request( 130 &mut self, 131 channel: ChannelId, 132 _term: &str, 133 _col_width: u32, 134 _row_height: u32, 135 _pix_width: u32, 136 _pix_height: u32, 137 _modes: &[(russh::Pty, u32)], 138 session: &mut Session, 139 ) -> Result<(), Self::Error> { 140 session.channel_success(channel)?; 141 Ok(()) 142 } 143 144 async fn shell_request( 145 &mut self, 146 channel: ChannelId, 147 session: &mut Session, 148 ) -> Result<(), Self::Error> { 149 let Some(handle) = self.channels.remove(&channel) else { 150 session.channel_failure(channel)?; 151 return Ok(()); 152 }; 153 session.channel_success(channel)?; 154 let state = Arc::clone(&self.state); 155 let key = self.key.clone(); 156 self.tracker.spawn(async move { 157 crate::exec::run_greeting(state, key, handle).await; 158 }); 159 Ok(()) 160 } 161 162 async fn exec_request( 163 &mut self, 164 channel: ChannelId, 165 data: &[u8], 166 session: &mut Session, 167 ) -> Result<(), Self::Error> { 168 let Some(handle) = self.channels.remove(&channel) else { 169 session.channel_failure(channel)?; 170 return Ok(()); 171 }; 172 session.channel_success(channel)?; 173 let protocol_v2 = self.protocols.remove(&channel); 174 let state = Arc::clone(&self.state); 175 let key = self.key.clone(); 176 let peer = self.peer; 177 let command = data.to_vec(); 178 self.tracker.spawn(async move { 179 run_exec(state, key, handle, &command, protocol_v2, peer).await; 180 }); 181 Ok(()) 182 } 183}