From 23711fa2b804feedc34eccaa7688f9613a2a9373 Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Fri, 08 Oct 2021 03:52:44 +0100 Subject: [PATCH] Use slog for chartered-git --- Cargo.lock | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ chartered-git/Cargo.toml | 8 +++++--- chartered-git/src/main.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- chartered-git/src/git/codec.rs | 2 -- 4 files changed, 162 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4abddc8..6afd0d8 100644 --- a/Cargo.lock +++ a/Cargo.lock @@ -303,9 +303,9 @@ "chartered-db", "chartered-types", "chrono", + "clap", "const-sha1", "crc", - "env_logger", "flate2", "format-bytes", "futures", @@ -313,11 +313,13 @@ "indexmap", "indoc", "itoa", - "log", "serde", "serde_json", "sha-1", "shlex", + "slog", + "slog-async", + "slog-term", "thrussh", "thrussh-keys", "tokio", @@ -471,8 +473,28 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" dependencies = [ "cfg-if", + "lazy_static", ] [[package]] @@ -575,10 +597,31 @@ ] [[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] name = "dirs-sys" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", @@ -1714,6 +1757,12 @@ "web-sys", "winapi", ] + +[[package]] +name = "rustversion" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" [[package]] name = "ryu" @@ -1868,6 +1917,37 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" + +[[package]] +name = "slog" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" + +[[package]] +name = "slog-async" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "766c59b252e62a34651412870ff55d8c4e6d04df19b43eecb2703e417b097ffe" +dependencies = [ + "crossbeam-channel", + "slog", + "take_mut", + "thread_local", +] + +[[package]] +name = "slog-term" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95c1e7e5aab61ced6006149ea772770b84a0d16ce0f7885def313e4829946d76" +dependencies = [ + "atty", + "chrono", + "slog", + "term", + "thread_local", +] [[package]] name = "smallvec" @@ -1921,6 +2001,12 @@ checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" [[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + +[[package]] name = "tempfile" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1931,6 +2017,17 @@ "rand", "redox_syscall", "remove_dir_all", + "winapi", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", "winapi", ] @@ -1970,6 +2067,15 @@ "proc-macro2", "quote", "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" +dependencies = [ + "once_cell", ] [[package]] diff --git a/chartered-git/Cargo.toml b/chartered-git/Cargo.toml index 83143b7..72cd5f5 100644 --- a/chartered-git/Cargo.toml +++ a/chartered-git/Cargo.toml @@ -11,12 +11,12 @@ anyhow = "1" arrayvec = "0.7" -async-trait = "0" +async-trait = "0.1" bytes = "1" +clap = "3.0.0-beta.4" chrono = "0.4" const-sha1 = "0.2" crc = "2" -env_logger = "0.9" flate2 = "1.0" format-bytes = "0.2" futures = "0.3" @@ -24,7 +24,9 @@ indexmap = "1" indoc = "1.0" itoa = "0.4" -log = "0.4" +slog = { version = "2.7", features = ["max_level_trace", "release_max_level_info"] } +slog-async = "2.7" +slog-term = "2.8" serde = { version = "1", features = ["derive"] } serde_json = "1" shlex = "1" diff --git a/chartered-git/src/main.rs b/chartered-git/src/main.rs index 136412f..e7581ff 100644 --- a/chartered-git/src/main.rs +++ a/chartered-git/src/main.rs @@ -19,7 +19,7 @@ use arrayvec::ArrayVec; use bytes::BytesMut; use futures::future::Future; -use log::warn; +use slog::{debug, error, info, o, warn, Drain, Logger}; use std::{fmt::Write, pin::Pin, sync::Arc}; use thrussh::{ server::{self, Auth, Session}, @@ -32,7 +32,10 @@ #[tokio::main] #[allow(clippy::semicolon_if_nothing_returned)] // broken clippy lint async fn main() { - env_logger::init(); + let decorator = slog_term::TermDecorator::new().build(); + let drain = slog_term::FullFormat::new(decorator).build().fuse(); + let drain = slog_async::Async::new(drain).build().fuse(); + let log = slog::Logger::root(drain, o!()); let config = Arc::new(thrussh::server::Config { methods: thrussh::MethodSet::PUBLICKEY, @@ -42,6 +45,7 @@ let server = Server { db: chartered_db::init().unwrap(), + log, }; thrussh::server::run(config, "127.0.0.1:2233", server) @@ -52,32 +56,40 @@ #[derive(Clone)] struct Server { db: chartered_db::ConnectionPool, + log: Logger, } impl server::Server for Server { type Handler = Handler; fn new(&mut self, ip: Option) -> Self::Handler { + let log = self.log.new(o!("ip" => ip)); + info!(log, "Connection received"); + Handler { ip, + log, codec: GitCodec::default(), input_bytes: BytesMut::default(), output_bytes: BytesMut::default(), db: self.db.clone(), authed: None, organisation: None, + is_git_protocol_v2: false, } } } struct Handler { ip: Option, + log: Logger, codec: GitCodec, input_bytes: BytesMut, output_bytes: BytesMut, db: chartered_db::ConnectionPool, organisation: Option, authed: Option, + is_git_protocol_v2: bool, } struct Authed { @@ -131,10 +143,29 @@ fn finished(self, s: Session) -> Self::FutureUnit { Box::pin(futures::future::ready(Ok((self, s)))) + } + + fn env_request( + mut self, + _channel: ChannelId, + name: &str, + value: &str, + session: Session, + ) -> Self::FutureUnit { + debug!(&self.log, "env set {}={}", name, value); + + match (name, value) { + ("GIT_PROTOCOL", "version=2") => self.is_git_protocol_v2 = true, + _ => {} + } + + Box::pin(futures::future::ready(Ok((self, session)))) } fn shell_request(mut self, channel: ChannelId, mut session: Session) -> Self::FutureUnit { Box::pin(async move { + error!(&self.log, "Attempted to open a shell, rejecting connection"); + let username = self.authed()?.user.username.clone(); // todo write!(&mut self.output_bytes, "Hi there, {}! You've successfully authenticated, but chartered does not provide shell access.\r\n", username)?; self.flush(&mut session, channel); @@ -154,8 +185,14 @@ Err(e) => return Box::pin(futures::future::err(e.into())), }; let args = shlex::split(data); + + debug!(&self.log, "exec {}", data); Box::pin(async move { + if !self.is_git_protocol_v2 { + anyhow::bail!("not git protocol v2"); + } + let mut args = args.into_iter().flat_map(Vec::into_iter); if args.next().as_deref() != Some("git-upload-pack") { @@ -177,9 +214,8 @@ session.close(channel); } - // TODO: check GIT_PROTOCOL=version=2 set self.write(PktLine::Data(b"version 2\n"))?; - self.write(PktLine::Data(b"agent=chartered/0.1.0\n"))?; + self.write(PktLine::Data(b"agent=chartered/0.1.0\n"))?; // TODO: clap::crate_name!()/clap::crate_version!() self.write(PktLine::Data(b"ls-refs=unborn\n"))?; self.write(PktLine::Data(b"fetch=shallow wait-for-done\n"))?; self.write(PktLine::Data(b"server-option\n"))?; @@ -194,10 +230,9 @@ fn subsystem_request( self, _channel: ChannelId, - data: &str, + _data: &str, session: Session, ) -> Self::FutureUnit { - eprintln!("subsystem req: {}", data); Box::pin(futures::future::ready(Ok((self, session)))) } @@ -215,7 +250,7 @@ let ssh_key = Arc::new(ssh_key); if let Err(e) = ssh_key.clone().update_last_used(self.db.clone()).await { - warn!("Failed to update last used key: {:?}", e); + warn!(&self.log, "Failed to update last used key: {:?}", e); } let auth_key = ssh_key @@ -252,7 +287,10 @@ Box::pin(async move { while let Some(frame) = self.codec.decode(&mut self.input_bytes)? { - eprintln!("{:#?}", frame); + debug!( + &self.log, + "decoded frame command={:?} metadata={:?}", frame.command, frame.metadata + ); // if the client flushed without giving us a command, we're expected to close // the connection or else the client will just hang @@ -302,8 +340,10 @@ packfile_entries, ) .await? + } + v => { + error!(&self.log, "Client sent unknown command, ignoring"; "command" => std::str::from_utf8(v).unwrap_or("invalid utf8")) } - v => eprintln!("unknown command {:?}", v), } } diff --git a/chartered-git/src/git/codec.rs b/chartered-git/src/git/codec.rs index 5d86ea8..9f5cda7 100644 --- a/chartered-git/src/git/codec.rs +++ a/chartered-git/src/git/codec.rs @@ -49,10 +49,8 @@ return Ok(Some(std::mem::take(&mut self.command))); } else if length == 1 || length == 2 { src.advance(4); - eprintln!("magic packet = {}", length); continue; } else if !(4..=65520).contains(&length) { - eprintln!("protocol abuse"); return Err( std::io::Error::new(std::io::ErrorKind::InvalidData, "protocol abuse").into(), ); -- rgit 0.1.3