Compare commits
2 Commits
ced0c992e7
...
c804695725
| Author | SHA1 | Date | |
|---|---|---|---|
| c804695725 | |||
| cc09fab16d |
@@ -25,6 +25,7 @@ pub struct P2PClientApp {
|
||||
status_message: String,
|
||||
known_peers: Vec<String>,
|
||||
connect_address_input: String,
|
||||
connect_server_name_input: String,
|
||||
|
||||
// Key: Parent Directory Hash (String), Value: List of children FileNode
|
||||
loaded_fs: HashMap<String, MerkleTree>,
|
||||
@@ -48,7 +49,8 @@ impl P2PClientApp {
|
||||
network_event_rx: event_rx,
|
||||
status_message: "Client Initialized. Awaiting network status...".to_string(),
|
||||
known_peers: vec!["bob".to_string()],
|
||||
connect_address_input: "127.0.0.1:8080".to_string(),
|
||||
connect_address_input: "https://jch.irif.fr:8443".to_string(),
|
||||
connect_server_name_input: "jch.irif.fr".to_string(),
|
||||
loaded_fs,
|
||||
active_peer: None,
|
||||
server_status: ServerStatus::Loading,
|
||||
@@ -125,11 +127,13 @@ impl eframe::App for P2PClientApp {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Server IP:");
|
||||
ui.text_edit_singleline(&mut self.connect_address_input);
|
||||
ui.text_edit_singleline(&mut self.connect_server_name_input);
|
||||
if ui.button("Connect").clicked() {
|
||||
let addr = self.connect_address_input.clone();
|
||||
let serv_name = self.connect_server_name_input.clone();
|
||||
let _ = self
|
||||
.network_cmd_tx
|
||||
.send(NetworkCommand::ConnectToServer(addr));
|
||||
.send(NetworkCommand::ConnectToServer(addr, serv_name));
|
||||
self.server_status = ServerStatus::Loading;
|
||||
ui.close();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
use std::io::Read;
|
||||
|
||||
use crate::messages_structure::HandshakeMessage;
|
||||
use bytes::Bytes;
|
||||
use p256::EncodedPoint;
|
||||
use p256::ecdsa::{
|
||||
Signature, SigningKey, VerifyingKey,
|
||||
signature::{Signer, Verifier},
|
||||
@@ -9,6 +13,7 @@ use sha2::{Digest, Sha256};
|
||||
///
|
||||
/// contains the ecdsa private key, the ecdsa public key and the username
|
||||
///
|
||||
///
|
||||
pub struct CryptographicSignature {
|
||||
priv_key: SigningKey,
|
||||
pub pub_key: VerifyingKey,
|
||||
@@ -42,6 +47,53 @@ pub fn formatPubKey(crypto_pair: CryptographicSignature) -> String {
|
||||
hex::encode(pubkey_bytes)
|
||||
}
|
||||
|
||||
pub async fn get_peer_key(username: &String) -> Result<VerifyingKey, reqwest::Error> {
|
||||
let client = reqwest::Client::new();
|
||||
let uri = format!("https://jch.irif.fr:8443/peers/{}/key", username);
|
||||
let res = client.get(uri).send().await?;
|
||||
if res.status().is_success() {
|
||||
println!("Successfully retreived the peers key.");
|
||||
} else {
|
||||
eprintln!(
|
||||
"Failed to get the peers key from the server. Status: {}",
|
||||
res.status()
|
||||
);
|
||||
}
|
||||
let body: Bytes = res.bytes().await?;
|
||||
let slice: &[u8] = body.as_ref();
|
||||
let body_bytes: &[u8; 64] = slice.try_into().expect("size error");
|
||||
let received_key = convert_verifyingkey(body_bytes);
|
||||
Ok(received_key)
|
||||
}
|
||||
|
||||
fn convert_verifyingkey(raw_xy: &[u8; 64]) -> VerifyingKey {
|
||||
let mut sec1 = [0u8; 65];
|
||||
sec1[0] = 0x04;
|
||||
sec1[1..].copy_from_slice(raw_xy);
|
||||
|
||||
let ep = EncodedPoint::from_bytes(&sec1).expect("invalid point bytes");
|
||||
let pk = VerifyingKey::from_encoded_point(&ep).expect("invalid encoded point");
|
||||
VerifyingKey::from(pk)
|
||||
}
|
||||
|
||||
pub fn verify_signature(pubkey: VerifyingKey, message: &Vec<u8>) -> bool {
|
||||
let length_bytes: [u8; 2] = message[5..7].try_into().expect("Taille incorrecte");
|
||||
let length = u16::from_be_bytes(length_bytes);
|
||||
println!("message length: {}", length);
|
||||
let msg_to_hash = &message[..length as usize + 7];
|
||||
let signature_bytes = &message[length as usize + 7..length as usize + 7 + 64];
|
||||
println!("conversion start");
|
||||
let sig = match Signature::from_bytes(signature_bytes.try_into().expect("conversion error")) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return false,
|
||||
};
|
||||
println!("conversion done");
|
||||
match pubkey.verify(&msg_to_hash, &sig) {
|
||||
Ok(()) => true,
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// takes a serialized message and adds the signature using the private key
|
||||
///
|
||||
|
||||
@@ -9,7 +9,9 @@ use crate::{
|
||||
cryptographic_signature::CryptographicSignature,
|
||||
message_handling::EventType,
|
||||
messages_channels::{MultipleSenders, start_receving_thread},
|
||||
registration::{register_ip_addresses, register_with_the_server},
|
||||
registration::{
|
||||
get_socket_address, parse_addresses, register_ip_addresses, register_with_the_server,
|
||||
},
|
||||
};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{
|
||||
@@ -19,8 +21,8 @@ use std::{
|
||||
|
||||
/// Messages sent to the Network thread by the GUI.
|
||||
pub enum NetworkCommand {
|
||||
ConnectToServer(String), // ServerIP
|
||||
FetchPeerList(String), // ServerIP
|
||||
ConnectToServer(String, String), // ServerIP
|
||||
FetchPeerList(String), // ServerIP
|
||||
RegisterAsPeer(String),
|
||||
Ping(),
|
||||
ConnectPeer(String), // IP:PORT
|
||||
@@ -95,14 +97,14 @@ pub fn start_p2p_executor(
|
||||
NetworkCommand::RequestChunk(_, _) => {
|
||||
println!("[Network] RequestChunk() called");
|
||||
}
|
||||
NetworkCommand::ConnectToServer(ip) => {
|
||||
NetworkCommand::ConnectToServer(ip, server_name) => {
|
||||
println!("[Network] ConnectToServer() called");
|
||||
|
||||
// Actual server connection
|
||||
|
||||
let messages_list = HashMap::<i32, EventType>::new();
|
||||
|
||||
let username = String::from("Gamixtreize");
|
||||
let username = String::from("az");
|
||||
|
||||
let crypto_pair = CryptographicSignature::new(username);
|
||||
|
||||
@@ -119,25 +121,41 @@ pub fn start_p2p_executor(
|
||||
eprintln!("request failed: {}", e);
|
||||
}
|
||||
|
||||
match SocketAddr::from_str(&ip) {
|
||||
Ok(sockaddr) => {
|
||||
start_receving_thread(
|
||||
&shared_socket,
|
||||
&shared_messageslist,
|
||||
&shared_cryptopair,
|
||||
sockaddr,
|
||||
&shared_senders,
|
||||
);
|
||||
register_ip_addresses(
|
||||
&shared_cryptopair,
|
||||
ip,
|
||||
&shared_senders,
|
||||
&shared_messageslist,
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("failed to parse socket address: {}", e);
|
||||
println!("ip: {}", ip);
|
||||
|
||||
let server_addr_query = get_socket_address(server_name);
|
||||
|
||||
match server_addr_query.await {
|
||||
Ok(sockaddr_bytes) => {
|
||||
match String::from_utf8(sockaddr_bytes.to_vec()) {
|
||||
Ok(s) => {
|
||||
let addresses = parse_addresses(&s);
|
||||
if let Some(first) = addresses.first() {
|
||||
// first: &SocketAddr
|
||||
start_receving_thread(
|
||||
&shared_socket,
|
||||
&shared_messageslist,
|
||||
&shared_cryptopair,
|
||||
*first, // copie le SocketAddr (implémente Copy pour SocketAddr)
|
||||
&shared_senders,
|
||||
);
|
||||
register_ip_addresses(
|
||||
&shared_cryptopair,
|
||||
first.to_string(),
|
||||
&shared_senders,
|
||||
&shared_messageslist,
|
||||
545,
|
||||
);
|
||||
} else {
|
||||
eprintln!("no valid socket addresses found in: {}", s);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("invalid UTF-8 in socket address bytes: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => eprintln!("failed to retrieve socket address: {}", e),
|
||||
}
|
||||
|
||||
tokio::time::sleep(std::time::Duration::from_millis(5000)).await;
|
||||
|
||||
112
client-network/src/message_handling.rs
Normal file
112
client-network/src/message_handling.rs
Normal file
@@ -0,0 +1,112 @@
|
||||
use crate::{
|
||||
cryptographic_signature::{
|
||||
CryptographicSignature, get_peer_key, sign_message, verify_signature,
|
||||
},
|
||||
messages_channels::MultipleSenders,
|
||||
messages_structure::HandshakeMessage,
|
||||
registration,
|
||||
};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{collections::HashMap, net::SocketAddr};
|
||||
|
||||
pub enum EventType {
|
||||
ServerHelloReply,
|
||||
PeerHelloReply,
|
||||
PeerHello,
|
||||
}
|
||||
|
||||
/*pub fn handle_recevied_message(
|
||||
messages_list: &mut HashMap<i32, EventType>,
|
||||
recevied_message: &Vec<u8>,
|
||||
crypto_pair: &CryptographicSignature,
|
||||
socket_addr: &SocketAddr,
|
||||
senders: &MultipleSenders,
|
||||
) {
|
||||
let message_id: [u8; 4] = recevied_message[0..4].try_into().expect("size error");
|
||||
let id = i32::from_be_bytes(message_id);
|
||||
let eventtype = messages_list.get(&id);
|
||||
match eventtype {
|
||||
Some(EventType::ServerHelloReply) => {
|
||||
registration::register_ip_addresses(
|
||||
&crypto_pair,
|
||||
socket_addr.ip().to_string(),
|
||||
&senders,
|
||||
messages_list,
|
||||
);
|
||||
}
|
||||
Some(_) => print!("Not implemented"),
|
||||
None => print!("Message not found"),
|
||||
}
|
||||
}*/
|
||||
|
||||
pub fn handle_recevied_message(
|
||||
messages_list: &Arc<Mutex<HashMap<i32, EventType>>>,
|
||||
recevied_message: &Vec<u8>,
|
||||
crypto_pair: &CryptographicSignature,
|
||||
socket_addr: &SocketAddr,
|
||||
senders: &MultipleSenders,
|
||||
) {
|
||||
if recevied_message.len() < 4 {
|
||||
return;
|
||||
} // Basic safety check
|
||||
|
||||
let message_id: [u8; 4] = recevied_message[0..4].try_into().expect("size error");
|
||||
let id = i32::from_be_bytes(message_id);
|
||||
|
||||
// Lock the mutex to access the HashMap
|
||||
let list = messages_list.lock().unwrap();
|
||||
|
||||
let eventtype = list.get(&id); // Clone the enum so we can release the lock if needed
|
||||
match eventtype {
|
||||
Some(EventType::ServerHelloReply) => {
|
||||
/*registration::register_ip_addresses(
|
||||
crypto_pair,
|
||||
socket_addr.to_string(),
|
||||
senders,
|
||||
&messages_list, // Pass the mutable reference inside the lock
|
||||
546,
|
||||
);*/
|
||||
}
|
||||
Some(_) => print!("Not implemented"),
|
||||
None => {
|
||||
let message_type = recevied_message[4];
|
||||
if message_type == 1 {
|
||||
println!("verify the signature");
|
||||
let parsed_received_message = HandshakeMessage::parse(recevied_message.to_vec());
|
||||
let received_name = String::from_utf8(parsed_received_message.name).expect("error");
|
||||
let peer_pubkey = tokio::runtime::Runtime::new()
|
||||
.unwrap()
|
||||
.block_on(get_peer_key(&received_name))
|
||||
.expect("failed to retrieve public key");
|
||||
|
||||
if !verify_signature(peer_pubkey, recevied_message) {
|
||||
println!(
|
||||
"incorrect signature from given peer: {}, ignoring message {}",
|
||||
&received_name, id
|
||||
);
|
||||
} else {
|
||||
let username_size = crypto_pair.username.len();
|
||||
let hello_handshake = HandshakeMessage::helloReply(
|
||||
id as u32,
|
||||
username_size as u16 + 4,
|
||||
crypto_pair.username.clone(),
|
||||
);
|
||||
//HandshakeMessage::display(&hello_handshake);
|
||||
let hello_handshake_serialized = hello_handshake.serialize();
|
||||
let message_signed = sign_message(crypto_pair, &hello_handshake_serialized);
|
||||
senders.send_via(0, message_signed, socket_addr.to_string());
|
||||
let mut list = messages_list.lock().expect("Failed to lock messages_list");
|
||||
match list.get(&id) {
|
||||
Some(_) => {
|
||||
list.remove(&id);
|
||||
}
|
||||
None => {
|
||||
list.insert(id, EventType::ServerHelloReply);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
print!("Message not found for ID: {}", id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,10 @@ impl MultipleSenders {
|
||||
for msg in rx {
|
||||
// Use the cloned Arc inside the thread
|
||||
if let Err(e) = sock_clone.send_to(&msg.payload, &msg.address) {
|
||||
eprintln!("Erreur d'envoi sur canal {}: {}", i, e);
|
||||
eprintln!(
|
||||
"Erreur d'envoi sur canal {}: {}, address: {}",
|
||||
i, e, &msg.address
|
||||
);
|
||||
} else {
|
||||
let message_id: [u8; 4] = msg.payload[0..4].try_into().expect("size error");
|
||||
let id = i32::from_be_bytes(message_id);
|
||||
@@ -85,6 +88,7 @@ impl MultipleSenders {
|
||||
let sock_clone = Arc::clone(socket);
|
||||
let cryptopair_clone = Arc::clone(crypto_pair);
|
||||
let senders_clone = Arc::clone(senders);
|
||||
|
||||
let messages_clone = Arc::clone(messages_list);
|
||||
thread::spawn(move || {
|
||||
let mut buf = [0u8; 1024];
|
||||
@@ -123,9 +127,9 @@ pub fn start_receving_thread(
|
||||
loop {
|
||||
match sock_clone.recv_from(&mut buf) {
|
||||
Ok((amt, src)) => {
|
||||
// Only send the part of the buffer that contains data
|
||||
let received_data = buf[..amt].to_vec();
|
||||
|
||||
println!("Reçu {} octets de {}: {:?}", amt, src, received_data);
|
||||
handle_recevied_message(
|
||||
&messages_clone,
|
||||
&received_data,
|
||||
@@ -133,7 +137,6 @@ pub fn start_receving_thread(
|
||||
&socket_addr,
|
||||
&senders_clone,
|
||||
);
|
||||
println!("Reçu {} octets de {}: {:?}", amt, src, received_data);
|
||||
}
|
||||
Err(e) => eprintln!("Erreur de réception: {}", e),
|
||||
}
|
||||
|
||||
@@ -7,12 +7,12 @@ pub struct UDPMessage {
|
||||
}
|
||||
|
||||
pub struct HandshakeMessage {
|
||||
id: u32,
|
||||
pub id: u32,
|
||||
msg_type: u8,
|
||||
length: u16,
|
||||
extensions: u32,
|
||||
name: Vec<u8>,
|
||||
signature: Vec<u8>,
|
||||
pub name: Vec<u8>,
|
||||
pub signature: Vec<u8>,
|
||||
}
|
||||
|
||||
impl UDPMessage {
|
||||
@@ -130,9 +130,9 @@ impl HandshakeMessage {
|
||||
let extensions_bytes: [u8; 4] = received_message[7..11]
|
||||
.try_into()
|
||||
.expect("Taille incorrecte");
|
||||
let name_bytes = &received_message[11..12 + msg_length as usize];
|
||||
let name_bytes = &received_message[11..(11 + msg_length - 4) as usize];
|
||||
let signature_bytes =
|
||||
&received_message[12 + msg_length as usize..(13 + msg_length + 32) as usize];
|
||||
&received_message[(11 + msg_length - 4) as usize..(11 + msg_length - 4 + 64) as usize];
|
||||
HandshakeMessage {
|
||||
id: u32::from_be_bytes(id_bytes),
|
||||
msg_type: received_message[4],
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::messages_structure::{HandshakeMessage, UDPMessage};
|
||||
use std::collections::HashMap;
|
||||
use std::net::SocketAddr;
|
||||
use std::net::UdpSocket;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
///
|
||||
@@ -39,7 +40,7 @@ pub async fn register_with_the_server(
|
||||
/// sends a get request to the server to get the socket address of the given peer
|
||||
///
|
||||
|
||||
async fn get_socket_address(username: String) -> Result<Bytes, reqwest::Error> {
|
||||
pub async fn get_socket_address(username: String) -> Result<Bytes, reqwest::Error> {
|
||||
let client = reqwest::Client::new();
|
||||
let uri = format!("https://jch.irif.fr:8443/peers/{}/addresses", username);
|
||||
let res = client.get(uri).send().await?;
|
||||
@@ -47,7 +48,7 @@ async fn get_socket_address(username: String) -> Result<Bytes, reqwest::Error> {
|
||||
println!("Successfully retreived the addresses.");
|
||||
} else {
|
||||
eprintln!(
|
||||
"Failed to register with the server. Status: {}",
|
||||
"Failed to get the peers addresses from the server. Status: {}",
|
||||
res.status()
|
||||
);
|
||||
}
|
||||
@@ -55,6 +56,20 @@ async fn get_socket_address(username: String) -> Result<Bytes, reqwest::Error> {
|
||||
Ok(body)
|
||||
}
|
||||
|
||||
pub fn parse_addresses(input: &String) -> Vec<SocketAddr> {
|
||||
let mut addrs = Vec::new();
|
||||
for line in input.lines() {
|
||||
let s = line.trim();
|
||||
if s.is_empty() {
|
||||
continue;
|
||||
}
|
||||
if let Ok(sock) = SocketAddr::from_str(s) {
|
||||
addrs.push(sock);
|
||||
}
|
||||
}
|
||||
addrs
|
||||
}
|
||||
|
||||
///
|
||||
/// registers the IP addresses by sending a Hello request to the server.
|
||||
///
|
||||
@@ -63,21 +78,25 @@ pub fn register_ip_addresses(
|
||||
server_uri: String,
|
||||
senders: &MultipleSenders,
|
||||
messages_list: &Arc<Mutex<HashMap<i32, EventType>>>,
|
||||
id: i32,
|
||||
) {
|
||||
let username_size = crypto_pair.username.len();
|
||||
let hello_handshake =
|
||||
HandshakeMessage::hello(545, username_size as u16 + 4, crypto_pair.username.clone());
|
||||
let hello_handshake = HandshakeMessage::hello(
|
||||
id as u32,
|
||||
username_size as u16 + 4,
|
||||
crypto_pair.username.clone(),
|
||||
);
|
||||
//HandshakeMessage::display(&hello_handshake);
|
||||
let hello_handshake_serialized = hello_handshake.serialize();
|
||||
let message_signed = sign_message(crypto_pair, &hello_handshake_serialized);
|
||||
senders.send_via(0, message_signed, server_uri);
|
||||
let mut list = messages_list.lock().expect("Failed to lock messages_list");
|
||||
match list.get(&545) {
|
||||
match list.get(&id) {
|
||||
Some(_) => {
|
||||
list.remove(&545);
|
||||
list.remove(&id);
|
||||
}
|
||||
None => {
|
||||
list.insert(545, EventType::ServerHelloReply);
|
||||
list.insert(id, EventType::ServerHelloReply);
|
||||
}
|
||||
}
|
||||
// 3. Perform the insertion
|
||||
|
||||
10
todo.md
10
todo.md
@@ -5,12 +5,12 @@
|
||||
## registration with the server
|
||||
- generation of the cryptographic key OK
|
||||
- put request to the uri (check if the peer is already connected) OK
|
||||
- udp handshakes
|
||||
- get request to the uri /peers/key to get the public key of a peer
|
||||
- get request to the uri /peers/key/addresses
|
||||
- udp handshakes OK
|
||||
- get request to the uri /peers/key to get the public key of a peer OK
|
||||
- get request to the uri /peers/key/addresses OK
|
||||
|
||||
## handshake
|
||||
- handshake structure
|
||||
- handshake structure OK
|
||||
- 5min timeout after handshake
|
||||
- matain connection every 4 min
|
||||
|
||||
@@ -32,4 +32,4 @@ telechargement des fichiers
|
||||
choisir un dossier à partager
|
||||
se deconnecter du réseau
|
||||
|
||||
2 channels -> un pour envoyer et un pour recevoir
|
||||
2 channels -> un pour envoyer et un pour recevoir OK
|
||||
|
||||
Reference in New Issue
Block a user