@ -9,6 +9,13 @@ use std::{
error ,
error ,
convert ::{ TryFrom , TryInto , } ,
convert ::{ TryFrom , TryInto , } ,
} ;
} ;
use crypto ::{
password ::{
Salt ,
Password ,
SALTSIZE
} ,
} ;
#[ derive(Debug, Clone, Copy, PartialEq, Eq, Ord,PartialOrd, Hash, Serialize, Deserialize) ]
#[ derive(Debug, Clone, Copy, PartialEq, Eq, Ord,PartialOrd, Hash, Serialize, Deserialize) ]
#[ repr(u8) ]
#[ repr(u8) ]
@ -80,6 +87,32 @@ impl Header for KeyHeader
}
}
}
}
#[ instrument ]
fn decode_salt ( p : & str ) -> Result < Salt , eyre ::Report >
{
trace ! ( "Decoding salt" ) ;
let mut salt = Salt ::none ( ) ;
salt . repl_with_hex ( p ) . wrap_err_with ( | | eyre ::eyre ! ( "Failed to construct password salt from bytes" ) ) ? ;
Ok ( salt )
}
#[ instrument ]
#[ inline ] fn encode_salt_to_string ( salt : & Salt ) -> String
{
salt . to_hex_string ( )
}
#[ instrument ]
fn encode_salt ( salt : & Salt ) -> Result < [ u8 ; SALTSIZE * 2 ] , eyre ::Report >
{
let mut output = [ 0 u8 ; SALTSIZE * 2 ] ;
hex ::encode_to_slice ( salt . as_ref ( ) , & mut output [ .. ] )
. wrap_err_with ( | | eyre ::eyre ! ( "Failed to encode salt to {} hex char bytes" , SALTSIZE * 2 ) )
. with_section ( | | salt . to_hex_string ( ) . header ( "Salt was" ) ) ? ;
Ok ( output )
}
impl KeyHeader
impl KeyHeader
{
{
/// Create a new key header from these values
/// Create a new key header from these values
@ -109,7 +142,12 @@ impl KeyHeader
. wrap_err_with ( | | eyre ::eyre ! ( "Failed to serialise header to text" ) )
. wrap_err_with ( | | eyre ::eyre ! ( "Failed to serialise header to text" ) )
. with_section ( | | format! ( "{:?}" , self ) . header ( "Header was" ) ) ? ;
. with_section ( | | format! ( "{:?}" , self ) . header ( "Header was" ) ) ? ;
let mut written = 0 ;
let mut written = {
out . write_all ( TEXT_NOPASS ) . await ? ;
out . write_u8 ( b'\n' ) . await ? ;
TEXT_NOPASS . len ( ) + 1
} ;
for bytes in text . as_bytes ( ) . chunks ( 16 ) {
for bytes in text . as_bytes ( ) . chunks ( 16 ) {
out . write_all ( bytes ) . await ? ;
out . write_all ( bytes ) . await ? ;
out . write_u8 ( b'\n' ) . await ? ;
out . write_u8 ( b'\n' ) . await ? ;
@ -123,19 +161,108 @@ impl KeyHeader
pub async fn read_text < T : AsyncBufRead + Unpin + ? Sized > ( input : & mut T ) -> Result < Self , eyre ::Report >
pub async fn read_text < T : AsyncBufRead + Unpin + ? Sized > ( input : & mut T ) -> Result < Self , eyre ::Report >
{
{
let ( mut tx , mut rx ) = mpsc ::channel ( 1 ) ;
let ( mut tx , mut rx ) = mpsc ::channel ( 1 ) ;
#[ derive(Debug) ]
enum SendError
{
SendError ,
IO ( std ::io ::Error ) ,
}
impl std ::error ::Error for SendError
{
fn source ( & self ) -> Option < & ( dyn std ::error ::Error + ' static ) >
{
match & self {
Self ::IO ( io ) = > Some ( io ) ,
_ = > None ,
}
}
}
impl fmt ::Display for SendError
{
fn fmt ( & self , f : & mut fmt ::Formatter < ' _ > ) -> fmt ::Result
{
write! ( f , "line reading failed: " ) ? ;
match self {
Self ::SendError = > write! ( f , "channel closed" ) ,
Self ::IO ( _ ) = > write! ( f , "io error" ) ,
}
}
}
impl From < std ::io ::Error > for SendError
{
#[ inline ] fn from ( from : std ::io ::Error ) -> Self
{
Self ::IO ( from )
}
}
impl < T > From < tokio ::sync ::mpsc ::error ::SendError < T > > for SendError
{
#[ inline ] fn from ( _ : tokio ::sync ::mpsc ::error ::SendError < T > ) -> Self
{
Self ::SendError
}
}
let line_sender = async move { //this is actually kinda overkill for this...
let line_sender = async move { //this is actually kinda overkill for this...
let mut buffer = String ::new ( ) ;
let mut buffer = String ::new ( ) ;
while input . read_line ( & mut buffer ) . await ? ! = 0 {
while input . read_line ( & mut buffer ) . await ? ! = 0 {
tx . send ( buffer . clone ( ) ) . await ? ;
tx . send ( buffer . clone ( ) ) . await ? ;
buffer . clear ( ) ;
buffer . clear ( ) ;
}
}
Ok ::< ( ) , eyre ::Report > ( ( ) )
Ok ::< ( ) , SendError > ( ( ) )
} ;
} ;
let line_reader = async {
let line_reader = async move {
macro_rules! take_one {
( $msg :literal $( $tt :tt ) * ) = > {
loop {
if let Some ( mut line ) = rx . recv ( ) . await {
if line . trim ( ) . len ( ) = = 0 {
continue ;
}
if {
let bytes = line . as_bytes ( ) ;
if bytes . len ( ) > 0 & & bytes [ bytes . len ( ) - 1 ] = = b'\n' {
true
} else {
false
}
} {
line . truncate ( line . len ( ) - 1 ) ;
}
break line ;
} else {
return Err ( eyre ::eyre ! ( format! ( $msg $( $tt ) * ) ) ) . wrap_err ( eyre ::eyre ! ( "Failed to deserialise string" ) ) ;
}
}
}
}
trace ! ( "Reading password" ) ;
let password = {
let pass_part = take_one ! ( "Failed to read password part" ) ;
trace ! ( "Read password {}" , pass_part ) ;
if pass_part . as_bytes ( ) = = TEXT_NOPASS {
None
} else {
Some ( decode_salt ( & pass_part [ .. ] )
. with_section ( move | | pass_part . header ( "Password string part was" ) ) ? )
}
} ;
trace ! ( "Decoded hex" ) ;
let mut enc = String ::new ( ) ;
let mut enc = String ::new ( ) ;
let mut had_delim = false ;
let mut had_delim = false ;
while let Some ( line ) = rx . recv ( ) . await {
while let Some ( line ) = rx . recv ( ) . await {
let line = line . trim ( ) ;
let line = line . trim ( ) ;
if line . len ( ) = = 0 {
continue ;
}
if line = = "---" {
if line = = "---" {
had_delim = true ;
had_delim = true ;
break ;
break ;
@ -146,17 +273,32 @@ impl KeyHeader
if ! had_delim {
if ! had_delim {
warn ! ( "Buffer contained no end-of-entry delimiter" ) ;
warn ! ( "Buffer contained no end-of-entry delimiter" ) ;
}
}
//let = take_one!("Expected header line");
Ok ::< Self , eyre ::Report > ( serialise ::from_text ( & enc [ .. ] )
//let = take_one!("Expected header line");
. wrap_err_with ( | | eyre ::eyre ! ( "Failed to deserialise string" ) )
. with_section ( | | enc . header ( "Read string was" ) ) ? )
if let Some ( salt ) = password {
todo! ( )
} else {
Ok ::< Self , eyre ::Report > ( serialise ::from_text ( & enc [ .. ] )
. wrap_err_with ( | | eyre ::eyre ! ( "Failed to deserialise string" ) )
. with_section ( | | enc . header ( "Read string was" ) ) ? )
}
} ;
} ;
tokio ::pin ! ( line_sender ) ;
tokio ::pin ! ( line_sender ) ;
tokio ::pin ! ( line_reader ) ;
tokio ::pin ! ( line_reader ) ;
let ( sres , rres ) = tokio ::join ! ( line_sender , line_reader ) ;
let ( sres , rres ) = tokio ::join ! ( line_sender , line_reader ) ;
sres ? ;
match sres {
Ok ( rres ? )
Err ( x @ SendError ::IO ( _ ) ) = > Err ( x ) . with_note ( | | "In line reader" ) ,
Err ( s @ SendError ::SendError ) = > {
rres
. with_error ( move | | s ) ? ;
warn ! ( "Unreachable code entered" ) ;
Err ( SendError ::SendError )
. with_note ( | | "In line reader" )
. with_warning ( | | "`sres` failed with `SendError` but `rres` completed successfully. This should not happen" )
} ,
_ = > Ok ( rres ? ) ,
}
}
}
/// Write this key header as bytes to this stream
/// Write this key header as bytes to this stream
#[ instrument(err, skip(out)) ]
#[ instrument(err, skip(out)) ]