implement auth wrapper for stream

This commit is contained in:
yggverse 2024-11-16 14:10:26 +02:00
parent f487215ca9
commit 5bb0617c57

View File

@ -21,7 +21,7 @@ use crate::Profile;
use gtk::{ use gtk::{
gdk_pixbuf::Pixbuf, gdk_pixbuf::Pixbuf,
gio::{ gio::{
Cancellable, SocketClient, SocketClientEvent, SocketConnectable, SocketProtocol, Cancellable, IOStream, SocketClient, SocketClientEvent, SocketConnectable, SocketProtocol,
TlsCertificate, TlsCertificateFlags, TlsClientConnection, TlsCertificate, TlsCertificateFlags, TlsClientConnection,
}, },
glib::{ glib::{
@ -29,7 +29,7 @@ use gtk::{
UriFlags, UriHideFlags, UriFlags, UriHideFlags,
}, },
prelude::{ prelude::{
CancellableExt, EditableExt, IOStreamExt, OutputStreamExt, SocketClientExt, CancellableExt, Cast, EditableExt, IOStreamExt, IsA, OutputStreamExt, SocketClientExt,
TlsConnectionExt, TlsConnectionExt,
}, },
}; };
@ -428,6 +428,21 @@ impl Page {
// Use local namespaces @TODO // Use local namespaces @TODO
// use gemini::client::response:: // use gemini::client::response::
// Wrapper for TLS connection
fn auth(
connection: impl IsA<IOStream>,
certificate: Option<TlsCertificate>,
) -> impl IsA<IOStream> {
if let Some(certificate) = certificate {
let tls_connection =
TlsClientConnection::new(&connection, None::<&SocketConnectable>).unwrap(); // @TODO handle
tls_connection.set_certificate(&certificate);
tls_connection.upcast::<IOStream>()
} else {
connection.upcast::<IOStream>()
}
}
// Init shared objects (async) // Init shared objects (async)
let cancellable = self.cancellable.borrow().clone(); let cancellable = self.cancellable.borrow().clone();
let update = self.browser_action.update().clone(); let update = self.browser_action.update().clone();
@ -443,20 +458,21 @@ impl Page {
client.set_protocol(SocketProtocol::Tcp); client.set_protocol(SocketProtocol::Tcp);
// Check request match configured identity in profile database // Check request match configured identity in profile database
let auth = if let Some(pem) = self let certificate = match self
.profile .profile
.identity .identity
.gemini(&self.navigation.request().widget().gobject().text()) .gemini(&self.navigation.request().widget().gobject().text())
{ {
match TlsCertificate::from_pem(&pem) { Some(pem) => match TlsCertificate::from_pem(&pem) {
Ok(certificate) => Some(certificate), Ok(certificate) => Some(certificate),
Err(_) => todo!(), Err(_) => todo!(),
} },
} else { None => {
// Use unauthorized connection // Use unauthorized connection
client.set_tls_validation_flags(TlsCertificateFlags::INSECURE); client.set_tls_validation_flags(TlsCertificateFlags::INSECURE);
client.set_tls(true); client.set_tls(true);
None None
}
}; };
// Listen for connection status updates // Listen for connection status updates
@ -488,23 +504,11 @@ impl Page {
Some(&cancellable.clone()), Some(&cancellable.clone()),
move |connect| match connect { move |connect| match connect {
Ok(connection) => { Ok(connection) => {
// Wrap connection with TLS // Encrypt stream using authorization TLS
if let Some(certificate) = auth { let stream = auth(connection, certificate);
let connection = TlsClientConnection::new(
&connection.clone(),
None::<&SocketConnectable>,
)
.unwrap(); // @TODO handle
// Apply authorization
connection.set_certificate(
&certificate,
);
// Validate @TODO
// connection.connect_accept_certificate(|_, _, _| true);
}
// Send request // Send request
connection.output_stream().write_bytes_async( stream.output_stream().write_bytes_async(
&Bytes::from(gformat!("{url}\r\n").as_bytes()), &Bytes::from(gformat!("{url}\r\n").as_bytes()),
Priority::DEFAULT, Priority::DEFAULT,
Some(&cancellable.clone()), Some(&cancellable.clone()),
@ -512,7 +516,7 @@ impl Page {
Ok(_) => { Ok(_) => {
// Read meta from input stream // Read meta from input stream
gemini::client::response::Meta::from_stream_async( gemini::client::response::Meta::from_stream_async(
connection.clone(), stream.clone(),
Some(Priority::DEFAULT), Some(Priority::DEFAULT),
Some(cancellable.clone()), Some(cancellable.clone()),
move |result| match result move |result| match result
@ -561,7 +565,7 @@ impl Page {
Some(gemini::client::response::meta::Mime::TextGemini) => { Some(gemini::client::response::meta::Mime::TextGemini) => {
// Read entire input stream to buffer // Read entire input stream to buffer
gemini::client::response::data::Text::from_stream_async( gemini::client::response::data::Text::from_stream_async(
connection, stream,
Some(Priority::DEFAULT), Some(Priority::DEFAULT),
Some(cancellable.clone()), Some(cancellable.clone()),
move |result|{ move |result|{
@ -629,7 +633,7 @@ impl Page {
// Asynchronously move `InputStream` data from `SocketConnection` into the local `MemoryInputStream` // Asynchronously move `InputStream` data from `SocketConnection` into the local `MemoryInputStream`
// this action allows to count the bytes for loading widget and validate max size for incoming data // this action allows to count the bytes for loading widget and validate max size for incoming data
gemini::gio::memory_input_stream::from_stream_async( gemini::gio::memory_input_stream::from_stream_async(
connection, stream,
Some(cancellable.clone()), Some(cancellable.clone()),
Priority::DEFAULT, Priority::DEFAULT,
0x400, // 1024 bytes per chunk, optional step for images download tracking 0x400, // 1024 bytes per chunk, optional step for images download tracking