~klve/poptea

d1b2b0446db577243c3ccf2d0631c1ed2a5ebcb6 — klve bunc ntnn 1 year, 4 months ago 2d71d05
WIP file storage
5 files changed, 58 insertions(+), 16 deletions(-)

M src/bin/poptea-cli.rs
M src/infra/client.rs
A src/infra/fs.rs
M src/infra/mod.rs
M src/lib.rs
M src/bin/poptea-cli.rs => src/bin/poptea-cli.rs +4 -2
@@ 1,10 1,12 @@
use io::Write;
use poptea::GeminiClient;
use std::io;
use std::{io, sync::Arc};

fn main() {
    let url = std::env::args().nth(1).expect("please provide gemini url");
    let client = poptea::TlsClient::new();
    let fs = poptea::FileSystem::new("~/.poptea".into());

    let client = poptea::TlsClient::new(Arc::new(fs));
    let res = client.get(&url).expect("failed to make a request");

    io::stdout()

M src/infra/client.rs => src/infra/client.rs +23 -12
@@ 4,19 4,21 @@ use url::Url;
use io::{Read, Write};
use std::str::FromStr;
use std::sync::Arc;
use std::{io, io::BufRead};
use std::{io, io::BufRead, convert::Into};
use x509_parser::prelude::*;

use crate::{GemResponse, GemStatus, GeminiClient, PopResult};
use crate::{GemResponse, GemStatus, GeminiClient, PopResult, TrustStore, VerifyStatus};

fn fingerprint(cert: &rustls::Certificate) -> std::result::Result<String, String> {
fn fingerprint(cert: &rustls::Certificate) -> PopResult<(String, String)> {
    let (_, pk) = X509Certificate::from_der(cert.as_ref()).unwrap();
    let res = pk.public_key().subject_public_key.as_ref();

    Ok(format!("{:?}", res))
    Ok((pk.subject().to_string(), format!("{:?}", res)))
}

struct TofuVerification {}
struct TofuVerification {
    store: Arc<dyn TrustStore>,
}

impl rustls::client::ServerCertVerifier for TofuVerification {
    fn verify_server_cert(


@@ 31,17 33,24 @@ impl rustls::client::ServerCertVerifier for TofuVerification {
        let path = "cert.der";
        let mut file = File::create(path).unwrap();
        file.write_all(cert.as_ref()).unwrap();
        let fingerprint = fingerprint(cert).unwrap();

        Ok(rustls::client::ServerCertVerified::assertion())
        let (addr, fingerprint) = fingerprint(cert).unwrap();
        match self.store.verify(&addr, fingerprint) {
            Ok(VerifyStatus::Trusted) => Ok(rustls::client::ServerCertVerified::assertion()),
            Ok(VerifyStatus::Untrusted) => {
                Err(rustls::Error::InvalidCertificateData("untrusted".into()))
            }
            Err(_) => Err(rustls::Error::General("storage error".into())),
        }
    }
}

pub struct TlsClient {}
pub struct TlsClient {
    store: Arc<dyn TrustStore>,
}

impl TlsClient {
    pub fn new() -> Self {
        Self {}
    pub fn new(store: Arc<dyn TrustStore>) -> Self {
        Self { store }
    }

    pub fn get_plain(&self, url: &str) -> PopResult<Vec<u8>> {


@@ 61,7 70,9 @@ impl TlsClient {
            .with_no_client_auth();
        config
            .dangerous()
            .set_certificate_verifier(Arc::new(TofuVerification {}));
            .set_certificate_verifier(Arc::new(TofuVerification {
                store: self.store.clone(),
            }));
        let arc = std::sync::Arc::new(config);

        let mut sess = rustls::ClientConnection::new(arc, host.try_into().unwrap()).unwrap();

A src/infra/fs.rs => src/infra/fs.rs +16 -0
@@ 0,0 1,16 @@
use crate::{PopResult, TrustStore, VerifyStatus};

pub struct FileSystem {}

impl FileSystem {
    pub fn new(pop_dir: String) -> Self {
        Self {}
    }
}

impl TrustStore for FileSystem {
    fn verify(&self, addr: &str, fingerprint: String) -> PopResult<VerifyStatus> {
        println!("{} {}", addr, fingerprint);
        Ok(VerifyStatus::Untrusted)
    }
}

M src/infra/mod.rs => src/infra/mod.rs +2 -0
@@ 1,3 1,5 @@
mod client;
mod fs;

pub use client::TlsClient;
pub use fs::FileSystem;

M src/lib.rs => src/lib.rs +13 -2
@@ 1,7 1,8 @@
mod infra;
pub use infra::TlsClient;
use std::str::FromStr;

mod infra;
pub use infra::{TlsClient, FileSystem};

#[derive(Debug)]
pub enum GemStatus {
    Input,


@@ 58,3 59,13 @@ pub enum PopError {
}

pub type PopResult<T> = Result<T, PopError>;

pub trait TrustStore: Send + Sync {
    fn verify(&self, addr: &str, fingerprint: String) -> PopResult<VerifyStatus>;
}

pub enum VerifyStatus {
    Trusted,
    Untrusted,
}