Skip to content

Commit

Permalink
Merge branch 'warp-tech:main' into no-open-ssl
Browse files Browse the repository at this point in the history
  • Loading branch information
darleybarreto authored Feb 17, 2024
2 parents c613674 + 5c60d30 commit 2661b8f
Show file tree
Hide file tree
Showing 27 changed files with 1,257 additions and 643 deletions.
9 changes: 9 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,15 @@
"contributions": [
"code"
]
},
{
"login": "ricott1",
"name": "Alessandro Ricottone",
"avatar_url": "https://avatars.githubusercontent.com/u/16502243?v=4",
"profile": "https://github.com/ricott1",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7,
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Russh
[![Rust](https://github.com/warp-tech/russh/actions/workflows/rust.yml/badge.svg)](https://github.com/warp-tech/russh/actions/workflows/rust.yml) <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-26-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-27-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->

Low-level Tokio SSH2 client and server implementation.
Expand Down Expand Up @@ -108,6 +108,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center" valign="top" width="14.28%"><a href="http://brendonho.com"><img src="https://avatars.githubusercontent.com/u/12106620?v=4?s=100" width="100px;" alt="Brendon Ho"/><br /><sub><b>Brendon Ho</b></sub></a><br /><a href="https://github.com/warp-tech/russh/commits?author=bho01" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://samlikes.pizza/"><img src="https://avatars.githubusercontent.com/u/226872?v=4?s=100" width="100px;" alt="Samuel Ainsworth"/><br /><sub><b>Samuel Ainsworth</b></sub></a><br /><a href="https://github.com/warp-tech/russh/commits?author=samuela" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Sherlock-Holo"><img src="https://avatars.githubusercontent.com/u/10096425?v=4?s=100" width="100px;" alt="Sherlock Holo"/><br /><sub><b>Sherlock Holo</b></sub></a><br /><a href="https://github.com/warp-tech/russh/commits?author=sherlock-holo" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ricott1"><img src="https://avatars.githubusercontent.com/u/16502243?v=4?s=100" width="100px;" alt="Alessandro Ricottone"/><br /><sub><b>Alessandro Ricottone</b></sub></a><br /><a href="https://github.com/warp-tech/russh/commits?author=ricott1" title="Code">💻</a></td>
</tr>
</tbody>
</table>
Expand Down
2 changes: 1 addition & 1 deletion russh-keys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ keywords = ["ssh"]
license = "Apache-2.0"
name = "russh-keys"
repository = "https://github.com/warp-tech/russh"
version = "0.41.0-beta.3"
version = "0.42.0"
rust-version = "1.65"

[dependencies]
Expand Down
5 changes: 3 additions & 2 deletions russh/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ license = "Apache-2.0"
name = "russh"
readme = "../README.md"
repository = "https://github.com/warp-tech/russh"
version = "0.41.0-beta.4"
version = "0.43.0-beta.1"
rust-version = "1.65"

[features]
Expand Down Expand Up @@ -37,7 +37,7 @@ once_cell = "1.13"
openssl = { version = "0.10", optional = true }
rand = "0.8"
russh-cryptovec = { version = "0.7.0", path = "../cryptovec" }
russh-keys = { version = "0.41.0-beta.3", path = "../russh-keys" }
russh-keys = { version = "0.42.0", path = "../russh-keys" }
sha1 = "0.10"
sha2 = "0.10"
hex-literal = "0.4"
Expand Down Expand Up @@ -73,6 +73,7 @@ rand = "0.8.5"
shell-escape = "0.1"
tokio-fd = "0.3"
termion = "2"
ratatui = "0.26.0"

[package.metadata.docs.rs]
features = ["openssl"]
6 changes: 3 additions & 3 deletions russh/examples/client_exec_interactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ impl client::Handler for Client {
type Error = russh::Error;

async fn check_server_key(
self,
&mut self,
_server_public_key: &key::PublicKey,
) -> Result<(Self, bool), Self::Error> {
Ok((self, true))
) -> Result<bool, Self::Error> {
Ok(true)
}
}

Expand Down
6 changes: 3 additions & 3 deletions russh/examples/client_exec_simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ impl client::Handler for Client {
type Error = russh::Error;

async fn check_server_key(
self,
&mut self,
_server_public_key: &key::PublicKey,
) -> Result<(Self, bool), Self::Error> {
Ok((self, true))
) -> Result<bool, Self::Error> {
Ok(true)
}
}

Expand Down
38 changes: 18 additions & 20 deletions russh/examples/echoserver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::HashMap;
use std::sync::Arc;

use async_trait::async_trait;
use russh::server::{Msg, Session};
use russh::server::{Msg, Server as _, Session};
use russh::*;
use russh_keys::*;
use tokio::sync::Mutex;
Expand All @@ -21,13 +21,11 @@ async fn main() {
..Default::default()
};
let config = Arc::new(config);
let sh = Server {
let mut sh = Server {
clients: Arc::new(Mutex::new(HashMap::new())),
id: 0,
};
russh::server::run(config, ("0.0.0.0", 2222), sh)
.await
.unwrap();
sh.run_on_address(config, ("0.0.0.0", 2222)).await.unwrap();
}

#[derive(Clone)]
Expand Down Expand Up @@ -61,43 +59,43 @@ impl server::Handler for Server {
type Error = anyhow::Error;

async fn channel_open_session(
self,
&mut self,
channel: Channel<Msg>,
session: Session,
) -> Result<(Self, bool, Session), Self::Error> {
session: &mut Session,
) -> Result<bool, Self::Error> {
{
let mut clients = self.clients.lock().await;
clients.insert((self.id, channel.id()), session.handle());
}
Ok((self, true, session))
Ok(true)
}

async fn auth_publickey(
self,
&mut self,
_: &str,
_: &key::PublicKey,
) -> Result<(Self, server::Auth), Self::Error> {
Ok((self, server::Auth::Accept))
) -> Result<server::Auth, Self::Error> {
Ok(server::Auth::Accept)
}

async fn data(
mut self,
&mut self,
channel: ChannelId,
data: &[u8],
mut session: Session,
) -> Result<(Self, Session), Self::Error> {
session: &mut Session,
) -> Result<(), Self::Error> {
let data = CryptoVec::from(format!("Got data: {}\r\n", String::from_utf8_lossy(data)));
self.post(data.clone()).await;
session.data(channel, data);
Ok((self, session))
Ok(())
}

async fn tcpip_forward(
self,
&mut self,
address: &str,
port: &mut u32,
session: Session,
) -> Result<(Self, bool, Session), Self::Error> {
session: &mut Session,
) -> Result<bool, Self::Error> {
let handle = session.handle();
let address = address.to_string();
let port = *port;
Expand All @@ -109,6 +107,6 @@ impl server::Handler for Server {
let _ = channel.data(&b"Hello from a forwarded port"[..]).await;
let _ = channel.eof().await;
});
Ok((self, true, session))
Ok(true)
}
}
212 changes: 212 additions & 0 deletions russh/examples/ratatui_app.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
use async_trait::async_trait;
use ratatui::{
backend::CrosstermBackend,
layout::Rect,
style::{Color, Style},
widgets::{Block, Borders, Clear, Paragraph},
Terminal,
};
use russh::{server::*, Channel, ChannelId};
use russh_keys::key::PublicKey;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::Mutex;

type SshTerminal = Terminal<CrosstermBackend<TerminalHandle>>;

struct App {
pub counter: usize,
}

impl App {
pub fn new() -> App {
Self { counter: 0 }
}
}

#[derive(Clone)]
struct TerminalHandle {
handle: Handle,
// The sink collects the data which is finally flushed to the handle.
sink: Vec<u8>,
channel_id: ChannelId,
}

// The crossterm backend writes to the terminal handle.
impl std::io::Write for TerminalHandle {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.sink.extend_from_slice(buf);
Ok(buf.len())
}

fn flush(&mut self) -> std::io::Result<()> {
let handle = self.handle.clone();
let channel_id = self.channel_id.clone();
let data = self.sink.clone().into();
futures::executor::block_on(async move {
let result = handle.data(channel_id, data).await;
if result.is_err() {
eprintln!("Failed to send data: {:?}", result);
}
});

self.sink.clear();
Ok(())
}
}

#[derive(Clone)]
struct AppServer {
clients: Arc<Mutex<HashMap<usize, (SshTerminal, App)>>>,
id: usize,
}

impl AppServer {
pub fn new() -> Self {
Self {
clients: Arc::new(Mutex::new(HashMap::new())),
id: 0,
}
}

pub async fn run(&mut self) -> Result<(), anyhow::Error> {
let clients = self.clients.clone();
tokio::spawn(async move {
loop {
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;

for (_, (terminal, app)) in clients.lock().await.iter_mut() {
app.counter += 1;

terminal
.draw(|f| {
let size = f.size();
f.render_widget(Clear, size);
let style = match app.counter % 3 {
0 => Style::default().fg(Color::Red),
1 => Style::default().fg(Color::Green),
_ => Style::default().fg(Color::Blue),
};
let paragraph = Paragraph::new(format!("Counter: {}", app.counter))
.alignment(ratatui::layout::Alignment::Center)
.style(style);
let block = Block::default()
.title("Press 'c' to reset the counter!")
.borders(Borders::ALL);
f.render_widget(paragraph.block(block), size);
})
.unwrap();
}
}
});

let config = Config {
inactivity_timeout: Some(std::time::Duration::from_secs(3600)),
auth_rejection_time: std::time::Duration::from_secs(3),
auth_rejection_time_initial: Some(std::time::Duration::from_secs(0)),
keys: vec![russh_keys::key::KeyPair::generate_ed25519().unwrap()],
..Default::default()
};

self.run_on_address(Arc::new(config), ("0.0.0.0", 2222))
.await?;
Ok(())
}
}

impl Server for AppServer {
type Handler = Self;
fn new_client(&mut self, _: Option<std::net::SocketAddr>) -> Self {
let s = self.clone();
self.id += 1;
s
}
}

#[async_trait]
impl Handler for AppServer {
type Error = anyhow::Error;

async fn channel_open_session(
&mut self,
channel: Channel<Msg>,
session: &mut Session,
) -> Result<bool, Self::Error> {
{
let mut clients = self.clients.lock().await;
let terminal_handle = TerminalHandle {
handle: session.handle(),
sink: Vec::new(),
channel_id: channel.id(),
};

let backend = CrosstermBackend::new(terminal_handle.clone());
let terminal = Terminal::new(backend)?;
let app = App::new();

clients.insert(self.id, (terminal, app));
}

Ok(true)
}

async fn auth_publickey(&mut self, _: &str, _: &PublicKey) -> Result<Auth, Self::Error> {
Ok(Auth::Accept)
}

async fn data(
&mut self,
channel: ChannelId,
data: &[u8],
session: &mut Session,
) -> Result<(), Self::Error> {
match data {
// Pressing 'q' closes the connection.
b"q" => {
self.clients.lock().await.remove(&self.id);
session.close(channel);
}
// Pressing 'c' resets the counter for the app.
// Only the client with the id sees the counter reset.
b"c" => {
let mut clients = self.clients.lock().await;
let (_, app) = clients.get_mut(&self.id).unwrap();
app.counter = 0;
}
_ => {}
}

Ok(())
}

/// The client's window size has changed.
async fn window_change_request(
&mut self,
_: ChannelId,
col_width: u32,
row_height: u32,
_: u32,
_: u32,
_: &mut Session,
) -> Result<(), Self::Error> {
{
let mut clients = self.clients.lock().await;
let (terminal, _) = clients.get_mut(&self.id).unwrap();
let rect = Rect {
x: 0,
y: 0,
width: col_width as u16,
height: row_height as u16,
};
terminal.resize(rect)?;
}

Ok(())
}
}

#[tokio::main]
async fn main() {
let mut server = AppServer::new();
server.run().await.expect("Failed running server");
}
Loading

0 comments on commit 2661b8f

Please sign in to comment.