Compare commits

...

10 Commits

Author SHA1 Message Date
dependabot[bot]
c1091b56b9
Bump rustls from 0.21.7 to 0.21.11 (#7)
Some checks failed
Checkmate CI / cargo-checkmate (push) Has been cancelled
Bumps [rustls](https://github.com/rustls/rustls) from 0.21.7 to 0.21.11.
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.21.7...v/0.21.11)

---
updated-dependencies:
- dependency-name: rustls
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-19 20:01:05 +00:00
dependabot[bot]
e911350d04
Bump rustix from 0.38.11 to 0.38.31 (#6)
Bumps [rustix](https://github.com/bytecodealliance/rustix) from 0.38.11 to 0.38.31.
- [Release notes](https://github.com/bytecodealliance/rustix/releases)
- [Commits](https://github.com/bytecodealliance/rustix/compare/v0.38.11...v0.38.31)

---
updated-dependencies:
- dependency-name: rustix
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-19 19:59:35 +00:00
dependabot[bot]
cb9473cf67
Bump mio from 0.8.8 to 0.8.11 (#5)
Bumps [mio](https://github.com/tokio-rs/mio) from 0.8.8 to 0.8.11.
- [Release notes](https://github.com/tokio-rs/mio/releases)
- [Changelog](https://github.com/tokio-rs/mio/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/mio/compare/v0.8.8...v0.8.11)

---
updated-dependencies:
- dependency-name: mio
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-05 00:18:55 +02:00
17ms
5c9320b136 remove unnecessary docs section 2024-03-01 00:01:16 +02:00
dependabot[bot]
be113f59a8
Bump aes-gcm from 0.10.2 to 0.10.3 (#4)
Bumps [aes-gcm](https://github.com/RustCrypto/AEADs) from 0.10.2 to 0.10.3.
- [Commits](https://github.com/RustCrypto/AEADs/compare/aes-gcm-v0.10.2...aes-gcm-v0.10.3)

---
updated-dependencies:
- dependency-name: aes-gcm
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-22 23:58:57 +03:00
17ms
731c3e4fa5 add x64 windows build 2023-09-04 21:41:48 +03:00
17ms
67fab76476 update dependencies 2023-09-03 19:52:30 +03:00
17ms
4c7bca4571 finished docs & version bump 2023-05-31 01:09:02 +03:00
17ms
b695d2fa1c fixed public ip binding 2023-05-29 02:42:38 +03:00
17ms
e461aa962f ctrl+c handler & ascii 2023-05-29 01:50:34 +03:00
10 changed files with 441 additions and 343 deletions

View File

@ -25,13 +25,16 @@ jobs:
os: ubuntu-latest
- target: aarch64-apple-darwin
os: macos-latest
- target: x86_64-pc-windows-msvc
os: windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: taiki-e/upload-rust-binary-action@v1
with:
bin: leightbox
bin: contego
tar: unix
include: LICENSE
checksum: sha256
target: ${{ matrix.target }}
token: ${{ secrets.GITHUB_TOKEN }}

645
Cargo.lock generated Executable file → Normal file

File diff suppressed because it is too large Load Diff

11
Cargo.toml Executable file → Normal file
View File

@ -1,16 +1,17 @@
[package]
name = "contego"
description = "CLI tool for file transfer"
version = "0.3.0"
version = "0.4.0"
authors = ["17ms"]
description = "A small CLI tool for quick file transfers"
repository = "https://github.com/17ms/contego"
license = "MIT"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tokio = { version = "1.28.1", features = ["full"] }
rand = "0.7.0"
x25519-dalek = "1.2.0"
aes-gcm = "0.10.2"
aes-gcm = "0.10.3"
base64 = "0.21.2"
sha256 = "1.1.3"
ureq = "2.6.2"

View File

@ -15,15 +15,35 @@
The initial key exchange is performed with elliptic-curve Diffie-Hellman. General data exchange is encrypted with AES-GCM. During regular communication payloads are Base64 encoded before being encrypted to prevent delimiter conflicts. SHA-256 hashes of files are compared to ensure data integrity.
## Cellular networks
Most cellular ISP's tend to block port forwarding on CGNAT level, which makes it impossible to create inbound connections to such network without a VPN. Luckily many consumer VPNs and self-hosted solutions make port forwarding a trivial task. This is the main reason why the client must fetch information about the public IP from an external service (https://ipinfo.io/ip for IPv4 and https://ipv6.icanhazip.com for IPv6).
## Usage
Work in progress. Will be completed when the current release is finished.
Check [releases](https://github.com/17ms/contego/releases) for an up-to-date executables or build from source with `cargo build --release`.
### Server
```shell
cargo build --release
./target/release/contego
```
Usage: contego host [OPTIONS] --key <KEY> <--source <SOURCE>|--files <FILES>...>
Options:
-k, --key <KEY> Access key
-s, --source <SOURCE> Path to a source file (alternative to --files)
-f, --files <FILES>... Paths to shareable files (alternative to --source)
-p, --port <PORT> Host port [default: 8080]
-6, --ipv6 IPv6 instead of IPv4
-c, --chunksize <CHUNKSIZE> Transmit chunksize in bytes [default: 8192]
-l, --local Host locally
-h, --help Print help
```
### Client
```
Usage: contego connect --addr <ADDR> --out <OUT> --key <KEY>
Options:
-a, --addr <ADDR> IP address of the instance
-o, --out <OUT> Path to an output folder
-k, --key <KEY> Access key
-h, --help Print help
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -6,11 +6,11 @@ use contego::{
client::Client,
parser::{addr_parser, dirpath_parser, filepath_parser},
server::Server,
util::{filepaths, handle_exit, metadata, Ip},
util::{ascii, filepaths, metadata, Ip},
};
use env_logger::Env;
use log::error;
use tokio::sync::mpsc;
use log::{error, info};
use tokio::{signal, sync::mpsc};
#[derive(Debug, Parser)]
#[command(about, version)]
@ -60,6 +60,8 @@ enum Commands {
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
ascii();
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
let cli = Cli::parse();
@ -77,22 +79,28 @@ async fn main() -> Result<(), Box<dyn Error>> {
let paths = filepaths(source, files)?;
let (metadata, index) = metadata(&paths).await?;
let addr = match (local, ipv6) {
let (display_addr, bind_addr) = match (local, ipv6) {
(true, _) => Ip::Local.fetch(port)?,
(false, true) => Ip::V6.fetch(port)?,
(false, false) => Ip::V4.fetch(port)?,
};
let server = Server::new(addr, key, chunksize, metadata, index);
let server = Server::new(display_addr, key, chunksize, metadata, index);
tokio::spawn(async move {
match server.start(rx).await {
match server.start(rx, &bind_addr).await {
Ok(_) => {}
Err(e) => error!("Error during server execution: {}", e),
};
});
handle_exit(tx).await?;
match signal::ctrl_c().await {
Ok(_) => {
tx.send(()).await?;
info!("Captured Ctrl+C, shutting down");
}
Err(_) => error!("Failed to listen for a Ctrl+C event"),
};
}
Commands::Connect { addr, out, key } => {
let client = Client::new(addr, key, out);

View File

@ -39,15 +39,19 @@ impl Server {
pub async fn start(
self: Arc<Self>,
mut kill: mpsc::Receiver<()>,
bind_addr: &SocketAddr,
) -> Result<(), Box<dyn Error + Send + Sync>> {
tokio::select! {
_ = self.listen() => Ok(()),
_ = self.listen(bind_addr) => Ok(()),
_ = kill.recv() => Ok(()),
}
}
async fn listen(self: Arc<Self>) -> Result<(), Box<dyn Error + Send + Sync>> {
let listener = TcpListener::bind(self.addr).await?;
async fn listen(
self: Arc<Self>,
bind_addr: &SocketAddr,
) -> Result<(), Box<dyn Error + Send + Sync>> {
let listener = TcpListener::bind(bind_addr).await?;
info!("Listening on {} - Access key: {}", self.addr, self.key);

View File

@ -1,15 +1,7 @@
use std::{
collections::HashMap,
env,
error::Error,
fs,
io::{stdin, Read},
net::SocketAddr,
path::PathBuf,
};
use std::{collections::HashMap, env, error::Error, fs, net::SocketAddr, path::PathBuf};
use log::{debug, info};
use tokio::{fs::File, io::BufWriter, sync::mpsc::Sender};
use tokio::{fs::File, io::BufWriter};
use crate::crypto;
@ -24,24 +16,26 @@ pub enum Ip {
}
impl Ip {
pub fn fetch(self, port: u16) -> Result<SocketAddr, Box<dyn Error>> {
pub fn fetch(self, port: u16) -> Result<(SocketAddr, SocketAddr), Box<dyn Error>> {
let addr = match self {
Ip::V4 => PUBLIC_IPV4,
Ip::V6 => PUBLIC_IPV6,
Ip::Local => {
let addr_str = format!("127.0.0.1:{}", port);
return Ok(addr_str.parse::<SocketAddr>()?);
let addr = addr_str.parse::<SocketAddr>()?;
return Ok((addr, addr));
}
};
info!("Fetching IP information from {}", addr);
let res = format!("{}:{}", ureq::get(addr).call()?.into_string()?.trim(), port);
let addr = res.parse::<SocketAddr>()?;
let display_addr = res.parse::<SocketAddr>()?;
let bind_addr = format!("0.0.0.0:{}", port).parse::<SocketAddr>()?;
debug!("IP: {}", res);
Ok(addr)
Ok((display_addr, bind_addr))
}
}
@ -127,20 +121,12 @@ pub async fn new_file(
Ok((BufWriter::new(handle), path))
}
pub async fn handle_exit(tx: Sender<()>) -> Result<(), Box<dyn Error>> {
let mut stdin = stdin().lock().bytes();
loop {
let k = match stdin.next() {
None => continue,
Some(k) => k?,
};
if k == b'q' {
tx.send(()).await?;
break;
}
}
Ok(())
pub fn ascii() {
let ascii = " __
_________ ____ / /____ ____ _____
/ ___/ __ \\/ __ \\/ __/ _ \\/ __ `/ __ \\
/ /__/ /_/ / / / / /_/ __/ /_/ / /_/ /
\\___/\\____/_/ /_/\\__/\\___/\\__, /\\____/
/____/ ";
println!("{}\n", ascii);
}

View File

@ -24,14 +24,13 @@ async fn sockets_integration() {
.is_test(true)
.try_init()
.unwrap();
//env_logger::builder().is_test(true).try_init().unwrap();
debug!("Initializing and starting the test");
let (testdata, paths) = testdata();
let (metadata, index) = metadata(&paths).await.unwrap();
let addr = Ip::Local.fetch(8080).unwrap();
let (display_addr, bind_addr) = Ip::Local.fetch(8080).unwrap();
let outdir = PathBuf::from("./tests/output/");
let key = String::from("testkey");
let c_key = key.clone();
@ -40,14 +39,14 @@ async fn sockets_integration() {
let server_handle = tokio::spawn(async move {
debug!("Initializing the asynchronous server task");
let server = Server::new(addr, key, 8192, metadata, index);
let server = Server::new(display_addr, key, 8192, metadata, index);
debug!("Starting to listen to incoming connections");
server.start(rx).await.unwrap();
server.start(rx, &bind_addr).await.unwrap();
});
let client_handle = tokio::spawn(async move {
debug!("Initializing the asynchronous client task");
let client = Client::new(addr, c_key, outdir);
let client = Client::new(display_addr, c_key, outdir);
debug!("Connecting to the server");
client.connection().await.unwrap();
});