Fixed UI for TXT records, updated all dependencies, made better connectivity, added log info to network thread.

This commit is contained in:
Revertron
2024-07-10 20:15:10 +02:00
parent 28431ec053
commit de46148e01
9 changed files with 393 additions and 481 deletions
Generated
+249 -363
View File
File diff suppressed because it is too large Load Diff
+27 -27
View File
@@ -12,50 +12,50 @@ exclude = ["blockchain.db", "alfis.toml"]
[dependencies]
getopts = "0.2.21"
log = "0.4.17"
simplelog = "0.12.0"
toml = "0.8.8"
digest = "0.10.5"
sha2 = "0.10.6"
ed25519-dalek = "2.0.0"
x25519-dalek = { version = "2.0.0", features = ["reusable_secrets"] }
ecies-ed25519-ng = { git = "https://github.com/Revertron/ecies-ed25519-ng", rev = "577c4f2", version = "0.5.2" }
log = "0.4.22"
simplelog = "0.12.2"
toml = "0.8.14"
digest = "0.10.7"
sha2 = "0.10.8"
ed25519-dalek = "2.1.1"
x25519-dalek = { version = "2.0.1", features = ["reusable_secrets"] }
ecies-ed25519-ng = { git = "https://github.com/Revertron/ecies-ed25519-ng", rev = "554ca29", version = "0.5.3" }
chacha20poly1305 = "0.10.1"
signature = "2.0.0"
signature = "2.2.0"
blakeout = "0.3.0"
num_cpus = "1.13.1"
byteorder = "1.4.3"
serde = { version = "1.0.144", features = ["derive"] }
serde_json = "1.0.85"
num_cpus = "1.16.0"
byteorder = "1.5.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
bincode = "1.3.3"
serde_cbor = "0.11.2"
base64 = "0.21.0"
num-bigint = "0.4.3"
num-traits = "0.2.15"
chrono = { version = "0.4.20", features = ["serde"] }
time = "0.3.14"
base64 = "0.22.1"
num-bigint = "0.4.6"
num-traits = "0.2.19"
chrono = { version = "0.4.38", features = ["serde"] }
time = "0.3.36"
rand = { package = "rand", version = "0.8.5" }
sqlite = "0.32.0"
uuid = { version = "1.3.0", features = ["serde", "v4"] }
mio = { version = "0.8.11", features = ["os-poll", "net"] }
sqlite = "0.36.0"
uuid = { version = "1.7.0", features = ["serde", "v4"] }
mio = { version = "1.0.0", features = ["os-poll", "net"] }
ureq = { version = "2.9", optional = true, git = "https://github.com/algesten/ureq" }
lru = "0.12"
derive_more = "0.99.17"
lazy_static = "1.4.0"
derive_more = "0.99.18"
lazy_static = "1.5.0"
spmc = "0.3.0"
# Optional dependencies regulated by features
web-view = { git = "https://github.com/Boscop/web-view", features = [], optional = true }
tinyfiledialogs = { version = "3.9.1", optional = true }
open = { version = "5.0.0", optional = true }
open = { version = "5.2.0", optional = true }
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.9", features = ["impl-default", "wincon", "shellscalingapi"] }
windows-service = "0.6.0"
thread-priority = "0.15.1"
windows-service = "0.7.0"
thread-priority = "1.1.0"
[target.'cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies]
thread-priority = "0.15.1"
thread-priority = "1.1.0"
[build-dependencies]
winres = "0.1.12"
+1 -1
View File
@@ -97,7 +97,7 @@ impl Block {
bincode::serialize(&self).unwrap()
}
/// Checks if this block is superior than the other
/// Checks if this block is superior to the other
pub fn is_better_than(&self, other: &Block) -> bool {
if self.transaction.is_some() && other.transaction.is_none() {
return true;
+41 -53
View File
@@ -161,7 +161,7 @@ impl Network {
//debug!("Accepted connection from: {} to local IP: {}", address, local_ip);
let token = self.next_token();
poll.registry().register(&mut stream, token, Interest::READABLE).expect("Error registering poll");
let peer = Peer::new(address, stream, State::Connected, true);
let peer = Peer::new(address, stream, State::Connected{ from: Instant::now() }, true);
self.peers.add_peer(token, peer);
}
if let Err(e) = poll.registry().reregister(&mut server, SERVER, Interest::READABLE) {
@@ -169,7 +169,11 @@ impl Network {
}
}
token => {
let _ = debug_send.send(String::from("Handle connection event"));
let peer = match self.peers.get_peer(&token) {
None => "None".to_string(),
Some(p) => p.to_string()
};
let _ = debug_send.send(format!("Handle connection event: {:?} for peer {}", &event, &peer));
if !self.handle_connection_event(poll.registry(), event, &mut seen_blocks, &mut buffer) {
let _ = self.peers.close_peer(poll.registry(), &token);
let blocks = self.context.lock().unwrap().chain.get_height();
@@ -282,7 +286,7 @@ impl Network {
return false;
}
match *peer.get_state() {
State::Connected => {
State::Connected { .. } => {
let stream = peer.get_stream();
return match read_client_handshake(stream) {
Ok(key) => {
@@ -291,12 +295,12 @@ impl Network {
let public_key: PublicKey = PublicKey::from(buf);
let shared = self.secret_key.diffie_hellman(&public_key);
let mut nonce = [0u8; 12];
let mut rng = rand::thread_rng();
let mut rng = thread_rng();
rng.fill(&mut nonce);
let chacha = Chacha::new(shared.as_bytes(), &nonce);
registry.reregister(stream, event.token(), Interest::WRITABLE).unwrap();
peer.set_cipher(chacha);
peer.set_state(State::ServerHandshake);
peer.set_state(State::ServerHandshake{ from: Instant::now() });
//trace!("Client hello read successfully");
true
}
@@ -306,7 +310,7 @@ impl Network {
}
};
}
State::ServerHandshake => {
State::ServerHandshake { .. } => {
let stream = peer.get_stream();
return match read_server_handshake(stream) {
Ok(data) => {
@@ -345,17 +349,8 @@ impl Network {
if let Ok(data_size) = data_size {
let data = {
match self.peers.get_peer(&event.token()) {
Some(peer) => {
match decode_message(&buf[0..data_size], peer.get_cipher()) {
Ok(data) => data,
Err(_) => {
vec![]
}
}
}
None => {
vec![]
}
Some(peer) => decode_message(&buf[0..data_size], peer.get_cipher()).unwrap_or_else(|_| vec![]),
None => vec![],
}
};
match Message::from_bytes(data) {
@@ -371,8 +366,8 @@ impl Network {
peer.set_state(State::Message { data });
}
State::Connecting => {}
State::Connected => {}
State::ServerHandshake => {}
State::Connected { .. } => {}
State::ServerHandshake { .. } => {}
State::HandshakeFinished => {}
State::Idle { .. } => {
peer.set_state(State::idle());
@@ -426,13 +421,15 @@ impl Network {
if send_client_handshake(peer.get_stream(), self.public_key.as_bytes()).is_err() {
return false;
}
peer.set_state(State::ServerHandshake);
peer.set_state(State::ServerHandshake{ from: Instant::now() });
peer.set_active(true);
}
State::ServerHandshake => {
State::ServerHandshake { .. } => {
if send_server_handshake(peer, self.public_key.as_bytes()).is_err() {
return false;
}
peer.set_state(State::HandshakeFinished);
peer.set_active(true);
//trace!("Server handshake sent");
}
State::HandshakeFinished => {
@@ -445,9 +442,10 @@ impl Network {
};
send_message(peer.get_stream(), &data).unwrap_or_else(|e| warn!("Error sending hello {}", e));
peer.set_state(State::idle());
peer.set_active(true);
//debug!("Sent hello to {}", &peer.get_addr());
}
State::Connected => {}
State::Connected { .. } => {}
State::Message { data } => {
//debug!("Sending data to {}: {}", &peer.get_addr(), &String::from_utf8(data.clone()).unwrap());
if let Ok(data) = encode_bytes(&data, peer.get_cipher()) {
@@ -825,7 +823,7 @@ fn read_message(stream: &mut TcpStream, buf: &mut [u8]) -> Result<usize, Error>
/// Sends one byte [garbage_size], [random bytes], and [public_key]
fn send_client_handshake(stream: &mut TcpStream, public_key: &[u8]) -> io::Result<()> {
let mut rng = rand::thread_rng();
let mut rng = thread_rng();
let packet_size: usize = rng.gen_range(64..255);
let mut buf = vec![0u8; packet_size];
rng.fill_bytes(&mut buf);
@@ -839,6 +837,19 @@ fn send_client_handshake(stream: &mut TcpStream, public_key: &[u8]) -> io::Resul
}
fn read_client_handshake(stream: &mut TcpStream) -> Result<Vec<u8>, Error> {
read_garbage_header(stream)?;
// Then we have public key for ECDH
let mut buf = vec![0u8; 32];
match stream.read_exact(&mut buf) {
Ok(_) => Ok(buf),
Err(e) => {
warn!("Error reading handshake!");
Err(e)
}
}
}
fn read_garbage_header(stream: &mut TcpStream) -> Result<(), Error> {
// First, we read garbage size
let data_size = match stream.read_u8() {
Ok(size) => (size ^ 0xA) as usize,
@@ -855,19 +866,11 @@ fn read_client_handshake(stream: &mut TcpStream) -> Result<Vec<u8>, Error> {
return Err(e);
}
}
// Then we have public key for ECDH
let mut buf = vec![0u8; 32];
match stream.read_exact(&mut buf) {
Ok(_) => Ok(buf),
Err(e) => {
warn!("Error reading handshake!");
Err(e)
}
}
Ok(())
}
fn send_server_handshake(peer: &mut Peer, public_key: &[u8]) -> io::Result<()> {
let mut rng = rand::thread_rng();
let mut rng = thread_rng();
let packet_size: usize = rng.gen_range(64..255);
let mut buf = vec![0u8; packet_size];
rng.fill_bytes(&mut buf);
@@ -887,22 +890,7 @@ fn send_server_handshake(peer: &mut Peer, public_key: &[u8]) -> io::Result<()> {
}
fn read_server_handshake(stream: &mut TcpStream) -> Result<Vec<u8>, Error> {
// First, we read garbage size
let data_size = match stream.read_u8() {
Ok(size) => (size ^ 0xA) as usize,
Err(e) => {
error!("Error reading from socket! {}", e);
return Err(e);
}
};
// Read the garbage
let mut buf = vec![0u8; data_size];
match stream.read_exact(&mut buf) {
Ok(_) => {}
Err(e) => {
return Err(e);
}
}
read_garbage_header(stream)?;
// Then we have public key for ECDH, plus nonce 12 bytes
let mut buf = vec![0u8; 32 + 12];
match stream.read_exact(&mut buf) {
@@ -946,12 +934,12 @@ fn wait_for_internet(timeout: Duration) {
trace!("Waiting for internet connection has timed out.")
}
fn would_block(err: &io::Error) -> bool {
err.kind() == io::ErrorKind::WouldBlock
fn would_block(err: &Error) -> bool {
err.kind() == ErrorKind::WouldBlock
}
fn interrupted(err: &io::Error) -> bool {
err.kind() == io::ErrorKind::Interrupted
fn interrupted(err: &Error) -> bool {
err.kind() == ErrorKind::Interrupted
}
fn write_all(connection: &mut TcpStream, mut buf: &[u8]) -> io::Result<()> {
+33
View File
@@ -1,3 +1,4 @@
use std::fmt::Display;
use std::net::SocketAddr;
use std::time::Instant;
@@ -138,6 +139,18 @@ impl Peer {
}
pub fn active(&self) -> bool {
match &self.state {
State::Connected { from } => {
return from.elapsed().as_secs() < 5;
}
State::Idle { from } => {
return from.elapsed().as_secs() < 120;
}
State::ServerHandshake { from } => {
return from.elapsed().as_secs() < 10;
}
_ => {}
}
self.active && self.last_active.elapsed().as_secs() < 120
}
@@ -174,4 +187,24 @@ impl Peer {
self.addr.ip() == addr.ip()
}
}
}
impl Display for Peer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let state = match &self.state {
State::Connecting => "Connecting",
State::Connected { .. } => "Connected",
State::ServerHandshake { .. } => "ServerHandshake",
State::HandshakeFinished => "HandshakeFinished",
State::Idle { .. } => "Idle",
State::Message { .. } => "Message",
State::Error => "Error",
State::Banned => "Banned",
State::SendLoop => "SendLoop",
State::Loop => "Loop",
State::Twin => "Twin",
State::Offline { .. } => "Offline"
};
write!(f, "{:?} {}", &self.addr, state)
}
}
+4 -3
View File
@@ -61,7 +61,7 @@ impl Peers {
State::Connecting => {
debug!("Peer connection {} to {:?} has timed out", &token.0, &addr);
}
State::Connected => {
State::Connected { .. } => {
debug!("Peer connection {} to {:?} disconnected", &token.0, &addr);
}
State::Idle { .. } | State::Message { .. } => {
@@ -86,8 +86,8 @@ impl Peers {
State::Twin => {
debug!("Peer connection {} to {:?} is a twin", &token.0, &addr);
}
State::ServerHandshake => {
debug!("Peer connection {} from {:?} didn't shake hands", &token.0, &addr);
State::ServerHandshake { from } => {
debug!("Peer connection {} from {:?} didn't shake hands for {}ms", &token.0, &addr, from.elapsed().as_millis());
}
State::HandshakeFinished => {
debug!("Peer connection {} from {:?} shook hands, but then failed", &token.0, &addr);
@@ -269,6 +269,7 @@ impl Peers {
}
} else {
if !matches!(peer.get_state(), State::Connecting {..}) && (peer.get_state().is_timed_out() || !peer.active()) {
debug!("Stale peer: {}, state: {:?}", peer.get_addr(), peer.get_state());
stale_tokens.push((token.clone(), peer.get_addr()));
continue;
}
+5 -2
View File
@@ -5,8 +5,8 @@ use crate::p2p::Message;
#[derive(Debug, Clone, PartialEq)]
pub enum State {
Connecting,
Connected,
ServerHandshake,
Connected { from: Instant },
ServerHandshake { from: Instant },
HandshakeFinished,
Idle { from: Instant },
Message { data: Vec<u8> },
@@ -43,6 +43,9 @@ impl State {
State::Idle { from } => {
from.elapsed().as_secs() > 60
}
State::Connected { from } => {
from.elapsed().as_secs() > 10
}
_ => false
}
}
+5 -4
View File
@@ -56,7 +56,7 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
MineDomain { name, data, signing, encryption, renewal } => {
action_create_domain(Arc::clone(&context), Arc::clone(&miner), web_view, name, data, signing, encryption, renewal);
}
TransferDomain { .. } => {}
TransferDomain { name, owner} => { info!("Transferring '{name}' to '{owner}'"); }
StopMining => { post(Event::ActionStopMining); }
Open { link } => {
if open::that(&link).is_err() {
@@ -360,10 +360,11 @@ fn load_domains(context: &mut MutexGuard<Context>, handle: &Handle<()>) {
web_view.eval("clearMyDomains();")
});
let domains = context.chain.get_my_domains(context.get_keystore());
//debug!("Domains: {:?}", &domains.values());
for (_identity, (domain, timestamp, data)) in domains {
let mut domains = domains.iter().map(|(_, d)| d).collect::<Vec<_>>();
domains.sort_by(|a, b| a.0.cmp(&b.0));
for (domain, timestamp, data) in domains {
let d = serde_json::to_string(&data).unwrap();
let d = d.replace("'", "\\'").replace("\\n", "\\\\n");
let d = d.replace("'", "\\'").replace("\\n", "\\\\n").replace("\"", "\\\"");
let command = format!("addMyDomain('{}', {}, {}, '{}');", &domain, timestamp, timestamp + DOMAIN_LIFETIME, &d);
let _ = handle.dispatch(move |web_view|{
web_view.eval(&command)
+28 -28
View File
@@ -34,7 +34,7 @@ function delRecord(index) {
}
function refreshRecordsList() {
var buf = "";
let buf = "";
if (recordsBuffer.length > 0) {
buf = "<label class=\"label\">Records:</label>\n";
}
@@ -46,28 +46,28 @@ function refreshRecordsList() {
}
function makeRecord(value, index, array) {
var data = value.addr;
let data = value.addr;
if (value.type == "MX") {
data = value.priority + " " + value.host;
} else if (value.type == "CNAME" || value.type == "NS") {
data = value.host;
} else if (value.type == "TXT" || value.type == "TLSA") {
data = value.data;
data = value.data.toString();
} else if (value.type == "SRV") {
data = value.priority + " " + value.weight + " " + value.port + " " + value.host;
}
var text = "<div class=\"field is-grouped\">" +
"<input class=\"input\" type=\"text\" value=\"{1}\" readonly>" +
"<input class=\"input ml-3 has-text-centered\" type=\"text\" size=\"6\" style=\"width: 20%;\" value=\"{2}\" readonly>" +
"<input class=\"input ml-3 has-text-centered\" type=\"text\" size=\"6\" style=\"width: 20%;\" value=\"{3}\" readonly>" +
"<input class=\"input ml-3\" type=\"text\" value=\"{4}\" readonly>" +
"<button class=\"button is-danger is-outlined ml-3\" id=\"record_delete\" onclick=\"delRecord({5});\">" +
" <span class=\"icon is-small\">" +
" <svg viewBox=\"0 0 24 24\" style=\"width: 20px; height: 20px;\"><path d=\"M22.54 16.88L20.41 19L22.54 21.12L21.12 22.54L19 20.41L16.88 22.54L15.47 21.12L17.59 19L15.47 16.88L16.88 15.47L19 17.59L21.12 15.46L22.54 16.88M12 13C10.9 13 10 13.9 10 15S10.9 17 12 17 14 16.1 14 15 13.1 13 12 13M13.35 21H5.5C4.58 21 3.81 20.38 3.58 19.54L1.04 10.27C1 10.18 1 10.09 1 10C1 9.45 1.45 9 2 9H6.79L11.17 2.45C11.36 2.16 11.68 2 12 2S12.64 2.16 12.83 2.44L17.21 9H22C22.55 9 23 9.45 23 10L22.97 10.27L22 13.81C21.43 13.5 20.79 13.24 20.12 13.11L20.7 11H3.31L5.5 19H13C13 19.7 13.13 20.37 13.35 21M9.2 9H14.8L12 4.8L9.2 9Z\"></path></svg>" +
" </span>" +
"</button>" +
"</div>";
const text = "<div class=\"field is-grouped\">" +
"<input class=\"input\" type=\"text\" value=\"{1}\" readonly>" +
"<input class=\"input ml-3 has-text-centered\" type=\"text\" size=\"6\" style=\"width: 20%;\" value=\"{2}\" readonly>" +
"<input class=\"input ml-3 has-text-centered\" type=\"text\" size=\"6\" style=\"width: 20%;\" value=\"{3}\" readonly>" +
"<input class=\"input ml-3\" type=\"text\" value='{4}' readonly>" +
"<button class=\"button is-danger is-outlined ml-3\" id=\"record_delete\" onclick=\"delRecord({5});\">" +
" <span class=\"icon is-small\">" +
" <svg viewBox=\"0 0 24 24\" style=\"width: 20px; height: 20px;\"><path d=\"M22.54 16.88L20.41 19L22.54 21.12L21.12 22.54L19 20.41L16.88 22.54L15.47 21.12L17.59 19L15.47 16.88L16.88 15.47L19 17.59L21.12 15.46L22.54 16.88M12 13C10.9 13 10 13.9 10 15S10.9 17 12 17 14 16.1 14 15 13.1 13 12 13M13.35 21H5.5C4.58 21 3.81 20.38 3.58 19.54L1.04 10.27C1 10.18 1 10.09 1 10C1 9.45 1.45 9 2 9H6.79L11.17 2.45C11.36 2.16 11.68 2 12 2S12.64 2.16 12.83 2.44L17.21 9H22C22.55 9 23 9.45 23 10L22.97 10.27L22 13.81C21.43 13.5 20.79 13.24 20.12 13.11L20.7 11H3.31L5.5 19H13C13 19.7 13.13 20.37 13.35 21M9.2 9H14.8L12 4.8L9.2 9Z\"></path></svg>" +
" </span>" +
"</button>" +
"</div>";
buf += text.replace("{1}", value.domain)
.replace("{2}", value.type)
.replace("{3}", value.ttl)
@@ -144,19 +144,19 @@ function formatDate(date) {
}
function refreshMyDomains() {
var row = '<tr class="is-clickable" onclick="editDomain(\'{domain}\', event);"><td class="has-text-weight-semibold">{title}</td><td class="w100"><div class="tags">{tags}</div></td><td>{date1}</td><td>{date2}</td></tr>';
var tag = '<span class="tag" title="{ip}">{domain}</span>';
var rows = "";
const row = '<tr class="is-clickable" onclick="editDomain(\'{domain}\', event);"><td class="has-text-weight-semibold">{title}</td><td class="w100"><div class="tags">{tags}</div></td><td>{date1}</td><td>{date2}</td></tr>';
const tag = '<span class="tag" title="{ip}">{domain}</span>';
let rows = "";
myDomains.forEach(function(value, index, array) {
var title = value.name;
var domain_data = JSON.parse(value.data);
var start = formatDate(new Date(value.timestamp * 1000));
var expire = formatDate(new Date(value.expire * 1000));
var tags = "";
const title = value.name;
const domain_data = JSON.parse(value.data);
const start = formatDate(new Date(value.timestamp * 1000));
const expire = formatDate(new Date(value.expire * 1000));
let tags = "";
if (typeof domain_data.records !== 'undefined') {
domain_data.records.forEach(function(v, i, a) {
if (typeof v.domain !== 'undefined') {
var buf = tag.replace("{domain}", v.domain);
let buf = tag.replace("{domain}", v.domain);
if (typeof v.addr !== 'undefined') {
buf = buf.replace("{ip}", v.addr);
} else if (typeof v.host !== 'undefined') {
@@ -171,7 +171,7 @@ function refreshMyDomains() {
rows = rows + row.replace("{title}", title).replace("{domain}", title).replace("{tags}", tags).replace("{date1}", start).replace("{date2}", expire);
});
document.getElementById("my_domains").innerHTML = rows;
if (rows != "") {
if (rows !== "") {
document.getElementById("my_domains_table").style.display = 'table';
} else {
document.getElementById("my_domains_table").style.display = 'none';
@@ -180,11 +180,11 @@ function refreshMyDomains() {
function editDomain(domain, event) {
myDomains.forEach(function(value, index, array) {
if (domain != value.name) {
if (domain !== value.name) {
return;
}
var title = value.name;
var domain_data = JSON.parse(value.data);
const title = value.name;
const domain_data = JSON.parse(value.data);
recordsBuffer = [];
if (typeof domain_data.records !== 'undefined') {
domain_data.records.forEach(function(v, i, a) {
@@ -197,7 +197,7 @@ function editDomain(domain, event) {
document.getElementById("info_text").value = domain_data.info;
}
if (typeof domain_data.contacts !== 'undefined') {
var count = 1;
let count = 1;
domain_data.contacts.forEach(function(v, i, a) {
document.getElementById("contact" + count + "_name").value = decodeURIComponent(v.name);
document.getElementById("contact" + count + "_value").value = decodeURIComponent(v.value);