Implemented support for multiple keys.
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "alfis"
|
name = "alfis"
|
||||||
version = "0.5.4"
|
version = "0.5.5"
|
||||||
authors = ["Revertron <alfis@revertron.com>"]
|
authors = ["Revertron <alfis@revertron.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
# The hash of first block in a chain to know with which nodes to work
|
# The hash of first block in a chain to know with which nodes to work
|
||||||
origin = "0000001D2A77D63477172678502E51DE7F346061FF7EB188A2445ECA3FC0780E"
|
origin = "0000001D2A77D63477172678502E51DE7F346061FF7EB188A2445ECA3FC0780E"
|
||||||
# A path to your key file to load automatically
|
# Paths to your key files to load automatically
|
||||||
key_file = "key1.toml"
|
key_files = ["key1.toml", "key2.toml", "key3.toml", "key4.toml", "key5.toml"]
|
||||||
# How many last blocks to check on start
|
# How many last blocks to check on start
|
||||||
check_blocks = 8
|
check_blocks = 8
|
||||||
|
|
||||||
|
|||||||
+18
-16
@@ -253,12 +253,12 @@ impl Chain {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_sign_block(&self, keystore: &Option<Keystore>) -> Option<Block> {
|
pub fn get_sign_block(&self, keys: &Vec<Keystore>) -> Option<(Block, Keystore)> {
|
||||||
if self.get_height() < BLOCK_SIGNERS_START {
|
if self.get_height() < BLOCK_SIGNERS_START {
|
||||||
trace!("Too early to start block signings");
|
trace!("Too early to start block signings");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if keystore.is_none() {
|
if keys.is_empty() {
|
||||||
trace!("We can't sign blocks without keys");
|
trace!("We can't sign blocks without keys");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -288,22 +288,24 @@ impl Chain {
|
|||||||
None => { return None; }
|
None => { return None; }
|
||||||
};
|
};
|
||||||
|
|
||||||
let keystore = keystore.clone().unwrap().clone();
|
|
||||||
let signers: HashSet<Bytes> = self.get_block_signers(&block).into_iter().collect();
|
let signers: HashSet<Bytes> = self.get_block_signers(&block).into_iter().collect();
|
||||||
if signers.contains(&keystore.get_public()) {
|
'key_loop: for keystore in keys {
|
||||||
for index in block.index..=self.get_height() {
|
if signers.contains(&keystore.get_public()) {
|
||||||
let b = self.get_block(index).unwrap();
|
for index in block.index..=self.get_height() {
|
||||||
if b.pub_key == keystore.get_public() {
|
let b = self.get_block(index).unwrap();
|
||||||
info!("We already mined signing block for block {}", block.index);
|
if b.pub_key == keystore.get_public() {
|
||||||
return None;
|
debug!("We already mined signing block for block {} by {:?}", block.index, &b.pub_key);
|
||||||
|
continue 'key_loop;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
info!("We have an honor to mine signing block!");
|
info!("We have an honor to mine signing block!");
|
||||||
let mut block = Block::new(None, Bytes::default(), last_hash, SIGNER_DIFFICULTY);
|
let mut block = Block::new(None, Bytes::default(), last_hash, SIGNER_DIFFICULTY);
|
||||||
block.index = last_index + 1;
|
block.index = last_index + 1;
|
||||||
return Some(block);
|
return Some((block, keystore.clone()));
|
||||||
} else if !signers.is_empty() {
|
}
|
||||||
|
}
|
||||||
|
if !signers.is_empty() {
|
||||||
info!("Signing block must be mined by other nodes");
|
info!("Signing block must be mined by other nodes");
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@@ -590,7 +592,7 @@ impl Chain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_my_domains(&self, keystore: &Option<Keystore>) -> HashMap<Bytes, (String, i64, DomainData)> {
|
pub fn get_my_domains(&self, keystore: Option<&Keystore>) -> HashMap<Bytes, (String, i64, DomainData)> {
|
||||||
if keystore.is_none() {
|
if keystore.is_none() {
|
||||||
return HashMap::new();
|
return HashMap::new();
|
||||||
}
|
}
|
||||||
|
|||||||
+50
-8
@@ -1,4 +1,4 @@
|
|||||||
use crate::{Chain, Keystore, Settings};
|
use crate::{Chain, Keystore, Settings, Bytes};
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use log::{trace, debug, info, warn, error};
|
use log::{trace, debug, info, warn, error};
|
||||||
use crate::miner::MinerState;
|
use crate::miner::MinerState;
|
||||||
@@ -6,29 +6,71 @@ use crate::miner::MinerState;
|
|||||||
pub struct Context {
|
pub struct Context {
|
||||||
pub app_version: String,
|
pub app_version: String,
|
||||||
pub settings: Settings,
|
pub settings: Settings,
|
||||||
pub keystore: Option<Keystore>,
|
pub keystores: Vec<Keystore>,
|
||||||
|
active_key: usize,
|
||||||
pub chain: Chain,
|
pub chain: Chain,
|
||||||
pub miner_state: MinerState,
|
pub miner_state: MinerState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
/// Creating an essential context to work with
|
/// Creating an essential context to work with
|
||||||
pub fn new(app_version: String, settings: Settings, keystore: Option<Keystore>, chain: Chain) -> Context {
|
pub fn new(app_version: String, settings: Settings, keystores: Vec<Keystore>, chain: Chain) -> Context {
|
||||||
Context {
|
Context {
|
||||||
app_version,
|
app_version,
|
||||||
settings,
|
settings,
|
||||||
keystore,
|
keystores,
|
||||||
|
active_key: 0,
|
||||||
chain,
|
chain,
|
||||||
miner_state: MinerState { mining: false, full: false }
|
miner_state: MinerState { mining: false, full: false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_keystore(&self) -> Option<Keystore> {
|
pub fn get_keystore(&self) -> Option<&Keystore> {
|
||||||
self.keystore.clone()
|
self.keystores.get(self.active_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_keystore(&mut self, keystore: Option<Keystore>) {
|
pub fn get_keystore_mut(&mut self) -> Option<&mut Keystore> {
|
||||||
self.keystore = keystore;
|
self.keystores.get_mut(self.active_key)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_keystores(&self) -> &Vec<Keystore> {
|
||||||
|
&self.keystores
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_keys(&self) -> bool {
|
||||||
|
!self.keystores.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_keystores(&mut self, keystore: Vec<Keystore>) {
|
||||||
|
self.keystores = keystore;
|
||||||
|
self.active_key = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_keystore(&mut self, keystore: Keystore) {
|
||||||
|
self.keystores.push(keystore);
|
||||||
|
self.active_key = self.keystores.len() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_key_by_index(&mut self, index: usize) -> bool {
|
||||||
|
if index < self.keystores.len() {
|
||||||
|
self.active_key = index;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_key_by_public(&mut self, public: &Bytes) -> bool {
|
||||||
|
for (i, key) in self.keystores.iter().enumerate() {
|
||||||
|
if key.get_public().eq(public) {
|
||||||
|
self.active_key = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_active_key_index(&self) -> usize {
|
||||||
|
self.active_key
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_chain(&self) -> &Chain {
|
pub fn get_chain(&self) -> &Chain {
|
||||||
|
|||||||
+1
-1
@@ -247,7 +247,7 @@ pub fn create_key(context: Arc<Mutex<Context>>) {
|
|||||||
let path = keystore.get_path().to_owned();
|
let path = keystore.get_path().to_owned();
|
||||||
let public = keystore.get_public().to_string();
|
let public = keystore.get_public().to_string();
|
||||||
info!("Key mined successfully! Public key: {}, hash: {}", &public, &hash);
|
info!("Key mined successfully! Public key: {}, hash: {}", &public, &hash);
|
||||||
context.set_keystore(Some(keystore));
|
context.add_keystore(keystore);
|
||||||
post(Event::KeyCreated { path, public, hash });
|
post(Event::KeyCreated { path, public, hash });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-5
@@ -110,7 +110,6 @@ fn main() {
|
|||||||
|
|
||||||
let settings = Settings::load(&config_name).expect(&format!("Cannot load settings from {}!", &config_name));
|
let settings = Settings::load(&config_name).expect(&format!("Cannot load settings from {}!", &config_name));
|
||||||
debug!(target: LOG_TARGET_MAIN, "Loaded settings: {:?}", &settings);
|
debug!(target: LOG_TARGET_MAIN, "Loaded settings: {:?}", &settings);
|
||||||
let keystore = Keystore::from_file(&settings.key_file, "");
|
|
||||||
let chain: Chain = Chain::new(&settings, DB_NAME);
|
let chain: Chain = Chain::new(&settings, DB_NAME);
|
||||||
if opt_matches.opt_present("b") {
|
if opt_matches.opt_present("b") {
|
||||||
for i in 1..(chain.get_height() + 1) {
|
for i in 1..(chain.get_height() + 1) {
|
||||||
@@ -121,7 +120,26 @@ fn main() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let settings_copy = settings.clone();
|
let settings_copy = settings.clone();
|
||||||
let context = Context::new(env!("CARGO_PKG_VERSION").to_owned(), settings, keystore, chain);
|
let mut keys = Vec::new();
|
||||||
|
if settings.key_files.len() > 0 {
|
||||||
|
for name in &settings.key_files {
|
||||||
|
match Keystore::from_file(name, "") {
|
||||||
|
None => { warn!("Error loading keyfile from {}", name); }
|
||||||
|
Some(keystore) => {
|
||||||
|
info!("Successfully loaded keyfile {}", name);
|
||||||
|
keys.push(keystore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match Keystore::from_file(&settings.key_file, "") {
|
||||||
|
None => { warn!("Error loading keyfile from {}", &settings.key_file); }
|
||||||
|
Some(keystore) => {
|
||||||
|
keys.push(keystore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let context = Context::new(env!("CARGO_PKG_VERSION").to_owned(), settings, keys, chain);
|
||||||
let context: Arc<Mutex<Context>> = Arc::new(Mutex::new(context));
|
let context: Arc<Mutex<Context>> = Arc::new(Mutex::new(context));
|
||||||
|
|
||||||
// If we just need to generate keys
|
// If we just need to generate keys
|
||||||
@@ -137,7 +155,7 @@ fn main() {
|
|||||||
let mining_copy = Arc::clone(&mining_copy);
|
let mining_copy = Arc::clone(&mining_copy);
|
||||||
let filename = filename.clone();
|
let filename = filename.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
if let Some(mut keystore) = context_copy.lock().unwrap().get_keystore() {
|
if let Some(keystore) = context_copy.lock().unwrap().get_keystore_mut() {
|
||||||
keystore.save(&filename, "");
|
keystore.save(&filename, "");
|
||||||
mining_copy.store(false, Ordering::Relaxed);
|
mining_copy.store(false, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
@@ -237,7 +255,7 @@ fn setup_logger(opt_matches: &Matches) {
|
|||||||
/// Gets own domains by current loaded keystore and writes them to log
|
/// Gets own domains by current loaded keystore and writes them to log
|
||||||
fn print_my_domains(context: &Arc<Mutex<Context>>) {
|
fn print_my_domains(context: &Arc<Mutex<Context>>) {
|
||||||
let context = context.lock().unwrap();
|
let context = context.lock().unwrap();
|
||||||
let domains = context.chain.get_my_domains(&context.keystore);
|
let domains = context.chain.get_my_domains(context.get_keystore());
|
||||||
debug!("Domains: {:?}", &domains);
|
debug!("Domains: {:?}", &domains);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,7 +266,7 @@ fn create_genesis_if_needed(context: &Arc<Mutex<Context>>, miner: &Arc<Mutex<Min
|
|||||||
let last_block = context.get_chain().last_block();
|
let last_block = context.get_chain().last_block();
|
||||||
let origin = context.settings.origin.clone();
|
let origin = context.settings.origin.clone();
|
||||||
if origin.is_empty() && last_block.is_none() {
|
if origin.is_empty() && last_block.is_none() {
|
||||||
if let Some(keystore) = &context.keystore {
|
if let Some(keystore) = context.get_keystore() {
|
||||||
// If blockchain is empty, we are going to mine a Genesis block
|
// If blockchain is empty, we are going to mine a Genesis block
|
||||||
let transaction = Transaction::origin(Chain::get_zones_hash(), keystore.get_public(), keystore.get_encryption_public());
|
let transaction = Transaction::origin(Chain::get_zones_hash(), keystore.get_public(), keystore.get_encryption_public());
|
||||||
let block = Block::new(Some(transaction), keystore.get_public(), Bytes::default(), ORIGIN_DIFFICULTY);
|
let block = Block::new(Some(transaction), keystore.get_public(), Bytes::default(), ORIGIN_DIFFICULTY);
|
||||||
|
|||||||
+6
-6
@@ -149,13 +149,13 @@ impl Miner {
|
|||||||
|
|
||||||
if !signing_waits {
|
if !signing_waits {
|
||||||
if let Ok(context) = context.lock() {
|
if let Ok(context) = context.lock() {
|
||||||
let keystore = context.get_keystore();
|
let keystores = context.get_keystores();
|
||||||
// Ask the blockchain if we have to sign something
|
// Ask the blockchain if we have to sign something
|
||||||
if let Some(block) = context.chain.get_sign_block(&keystore) {
|
if let Some((block, keystore)) = context.chain.get_sign_block(keystores) {
|
||||||
info!("Got signing job, adding to queue");
|
info!("Got signing job, adding to queue");
|
||||||
// We start mining sign block after some time, not everyone in the same time
|
// We start mining sign block after some time, not everyone in the same time
|
||||||
let start = Utc::now().timestamp() + (rand::random::<i64>() % BLOCK_SIGNERS_START_RANDOM);
|
let start = Utc::now().timestamp() + (rand::random::<i64>() % BLOCK_SIGNERS_START_RANDOM);
|
||||||
jobs.push(MineJob { start, block, keystore: keystore.unwrap() });
|
jobs.push(MineJob { start, block, keystore });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,13 +177,13 @@ impl Miner {
|
|||||||
} else {
|
} else {
|
||||||
// If our queue is empty
|
// If our queue is empty
|
||||||
if let Ok(context) = context.lock() {
|
if let Ok(context) = context.lock() {
|
||||||
let keystore = context.get_keystore();
|
let keystores = context.get_keystores();
|
||||||
// Ask the blockchain if we have to sign something
|
// Ask the blockchain if we have to sign something
|
||||||
if let Some(block) = context.chain.get_sign_block(&keystore) {
|
if let Some((block, keystore)) = context.chain.get_sign_block(keystores) {
|
||||||
info!("Got signing job, adding to queue");
|
info!("Got signing job, adding to queue");
|
||||||
// We start mining sign block after some time, not everyone in the same time
|
// We start mining sign block after some time, not everyone in the same time
|
||||||
let start = Utc::now().timestamp() + (rand::random::<i64>() % BLOCK_SIGNERS_START_RANDOM);
|
let start = Utc::now().timestamp() + (rand::random::<i64>() % BLOCK_SIGNERS_START_RANDOM);
|
||||||
jobs.push(MineJob { start, block, keystore: keystore.unwrap() });
|
jobs.push(MineJob { start, block, keystore });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-2
@@ -12,7 +12,10 @@ pub struct Settings {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub origin: String,
|
pub origin: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
#[deprecated]
|
||||||
pub key_file: String,
|
pub key_file: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub key_files: Vec<String>,
|
||||||
#[serde(default = "default_check_blocks")]
|
#[serde(default = "default_check_blocks")]
|
||||||
pub check_blocks: u64,
|
pub check_blocks: u64,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@@ -52,8 +55,9 @@ impl Settings {
|
|||||||
impl Default for Settings {
|
impl Default for Settings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
origin: String::from("00002883BB006454F795BE6902770B1A18D897B33A0AB1631F53C37C2F41F800"),
|
origin: String::from("0000001D2A77D63477172678502E51DE7F346061FF7EB188A2445ECA3FC0780E"),
|
||||||
key_file: String::from("default.key"),
|
key_file: String::from("key1.toml"),
|
||||||
|
key_files: Vec::new(),
|
||||||
check_blocks: default_check_blocks(),
|
check_blocks: default_check_blocks(),
|
||||||
net: Net::default(),
|
net: Net::default(),
|
||||||
dns: Default::default(),
|
dns: Default::default(),
|
||||||
|
|||||||
+56
-7
@@ -11,7 +11,7 @@ use std::time::{Duration, Instant};
|
|||||||
use chrono::{DateTime, Local};
|
use chrono::{DateTime, Local};
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use log::{debug, error, info, LevelFilter, trace, warn};
|
use log::{debug, error, info, LevelFilter, trace, warn};
|
||||||
use serde::Deserialize;
|
use serde::{Serialize, Deserialize};
|
||||||
use web_view::Content;
|
use web_view::Content;
|
||||||
|
|
||||||
use alfis::{Block, Bytes, Context, Keystore, Transaction};
|
use alfis::{Block, Bytes, Context, Keystore, Transaction};
|
||||||
@@ -52,6 +52,7 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
|
|||||||
LoadKey => { action_load_key(&context, web_view); }
|
LoadKey => { action_load_key(&context, web_view); }
|
||||||
CreateKey => { keystore::create_key(Arc::clone(&context)); }
|
CreateKey => { keystore::create_key(Arc::clone(&context)); }
|
||||||
SaveKey => { action_save_key(&context); }
|
SaveKey => { action_save_key(&context); }
|
||||||
|
SelectKey { index } => { action_select_key(&context, web_view, index); }
|
||||||
CheckRecord { data } => { action_check_record(web_view, data); }
|
CheckRecord { data } => { action_check_record(web_view, data); }
|
||||||
CheckDomain { name } => { action_check_domain(&context, web_view, name); }
|
CheckDomain { name } => { action_check_domain(&context, web_view, name); }
|
||||||
MineDomain { name, data, signing, encryption } => {
|
MineDomain { name, data, signing, encryption } => {
|
||||||
@@ -130,7 +131,7 @@ fn action_check_domain(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn action_save_key(context: &Arc<Mutex<Context>>) {
|
fn action_save_key(context: &Arc<Mutex<Context>>) {
|
||||||
if context.lock().unwrap().get_keystore().is_none() {
|
if !context.lock().unwrap().has_keys() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let result = tfd::save_file_dialog_with_filter("Save keys file", "", &["*.toml"], "Key files (*.toml)");
|
let result = tfd::save_file_dialog_with_filter("Save keys file", "", &["*.toml"], "Key files (*.toml)");
|
||||||
@@ -141,7 +142,7 @@ fn action_save_key(context: &Arc<Mutex<Context>>) {
|
|||||||
new_path.push_str(".toml");
|
new_path.push_str(".toml");
|
||||||
}
|
}
|
||||||
let path = new_path.clone();
|
let path = new_path.clone();
|
||||||
if let Some(mut keystore) = context.lock().unwrap().get_keystore() {
|
if let Some(keystore) = context.lock().unwrap().get_keystore_mut() {
|
||||||
let public = keystore.get_public().to_string();
|
let public = keystore.get_public().to_string();
|
||||||
let hash = keystore.get_hash().to_string();
|
let hash = keystore.get_hash().to_string();
|
||||||
keystore.save(&new_path, "");
|
keystore.save(&new_path, "");
|
||||||
@@ -152,6 +153,20 @@ fn action_save_key(context: &Arc<Mutex<Context>>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn action_select_key(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>, index: usize) {
|
||||||
|
if context.lock().unwrap().select_key_by_index(index) {
|
||||||
|
let (path, public, hash) = {
|
||||||
|
let keystore = context.lock().unwrap().get_keystore().cloned().unwrap();
|
||||||
|
let path = keystore.get_path().to_owned();
|
||||||
|
let public = keystore.get_public().to_string();
|
||||||
|
let hash = keystore.get_hash().to_string();
|
||||||
|
(path, public, hash)
|
||||||
|
};
|
||||||
|
post(Event::KeyLoaded { path, public, hash });
|
||||||
|
web_view.eval(&format!("keySelected({})", index)).expect("Error evaluating!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn action_load_key(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
|
fn action_load_key(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
|
||||||
let result = tfd::open_file_dialog("Open keys file", "", Some((&["*.key", "*.toml"], "Key files")));
|
let result = tfd::open_file_dialog("Open keys file", "", Some((&["*.key", "*.toml"], "Key files")));
|
||||||
match result {
|
match result {
|
||||||
@@ -169,7 +184,12 @@ fn action_load_key(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
|
|||||||
let public = keystore.get_public().to_string();
|
let public = keystore.get_public().to_string();
|
||||||
let hash = keystore.get_hash().to_string();
|
let hash = keystore.get_hash().to_string();
|
||||||
post(Event::KeyLoaded { path, public, hash });
|
post(Event::KeyLoaded { path, public, hash });
|
||||||
context.lock().unwrap().set_keystore(Some(keystore));
|
|
||||||
|
if !context.lock().unwrap().select_key_by_public(&keystore.get_public()) {
|
||||||
|
context.lock().unwrap().add_keystore(keystore);
|
||||||
|
} else {
|
||||||
|
warn!("This key is already loaded!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,6 +220,7 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
|
|||||||
let eval = match e {
|
let eval = match e {
|
||||||
Event::KeyCreated { path, public, hash } => {
|
Event::KeyCreated { path, public, hash } => {
|
||||||
load_domains(&mut context, &handle);
|
load_domains(&mut context, &handle);
|
||||||
|
send_keys_to_ui(&mut context, &handle);
|
||||||
event_handle_luck(&handle, "Key successfully created! Don\\'t forget to save it!");
|
event_handle_luck(&handle, "Key successfully created! Don\\'t forget to save it!");
|
||||||
let mut s = format!("keystoreChanged('{}', '{}', '{}');", &path, &public, &hash);
|
let mut s = format!("keystoreChanged('{}', '{}', '{}');", &path, &public, &hash);
|
||||||
s.push_str(" showSuccess('New key mined successfully! Save it to a safe place!')");
|
s.push_str(" showSuccess('New key mined successfully! Save it to a safe place!')");
|
||||||
@@ -208,6 +229,7 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
|
|||||||
Event::KeyLoaded { path, public, hash } |
|
Event::KeyLoaded { path, public, hash } |
|
||||||
Event::KeySaved { path, public, hash } => {
|
Event::KeySaved { path, public, hash } => {
|
||||||
load_domains(&mut context, &handle);
|
load_domains(&mut context, &handle);
|
||||||
|
send_keys_to_ui(&mut context, &handle);
|
||||||
format!("keystoreChanged('{}', '{}', '{}');", &path, &public, &hash)
|
format!("keystoreChanged('{}', '{}', '{}');", &path, &public, &hash)
|
||||||
}
|
}
|
||||||
Event::MinerStarted | Event::KeyGeneratorStarted => {
|
Event::MinerStarted | Event::KeyGeneratorStarted => {
|
||||||
@@ -320,6 +342,7 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
|
|||||||
if let Ok(zones) = serde_json::to_string(&zones) {
|
if let Ok(zones) = serde_json::to_string(&zones) {
|
||||||
let _ = web_view.eval(&format!("zonesChanged('{}');", &zones));
|
let _ = web_view.eval(&format!("zonesChanged('{}');", &zones));
|
||||||
}
|
}
|
||||||
|
send_keys_to_ui(&c, &web_view.handle());
|
||||||
event_info(web_view, "Application loaded");
|
event_info(web_view, "Application loaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,7 +350,7 @@ fn load_domains(context: &mut MutexGuard<Context>, handle: &Handle<()>) {
|
|||||||
let _ = handle.dispatch(move |web_view|{
|
let _ = handle.dispatch(move |web_view|{
|
||||||
web_view.eval("clearMyDomains();")
|
web_view.eval("clearMyDomains();")
|
||||||
});
|
});
|
||||||
let domains = context.chain.get_my_domains(&context.keystore);
|
let domains = context.chain.get_my_domains(context.get_keystore());
|
||||||
debug!("Domains: {:?}", &domains.values());
|
debug!("Domains: {:?}", &domains.values());
|
||||||
for (_identity, (domain, timestamp, data)) in domains {
|
for (_identity, (domain, timestamp, data)) in domains {
|
||||||
let d = serde_json::to_string(&data).unwrap();
|
let d = serde_json::to_string(&data).unwrap();
|
||||||
@@ -341,11 +364,30 @@ fn load_domains(context: &mut MutexGuard<Context>, handle: &Handle<()>) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn send_keys_to_ui(context: &MutexGuard<Context>, handle: &Handle<()>) {
|
||||||
|
let keys = {
|
||||||
|
let mut keys = Vec::new();
|
||||||
|
for key in context.get_keystores() {
|
||||||
|
let path = key.get_path().replace("\\", "/");
|
||||||
|
let parts: Vec<&str> = path.rsplitn(2, "/").collect();
|
||||||
|
keys.push(KeysForJS { file_name: parts[0].to_owned(), public: key.get_public().to_string() });
|
||||||
|
}
|
||||||
|
keys
|
||||||
|
};
|
||||||
|
if !keys.is_empty() {
|
||||||
|
let index = context.get_active_key_index();
|
||||||
|
let _ = handle.dispatch(move |web_view| {
|
||||||
|
let command = format!("keysChanged('{}'); keySelected({});", serde_json::to_string(&keys).unwrap(), index);
|
||||||
|
web_view.eval(&command)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn action_create_domain(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, web_view: &mut WebView<()>, name: String, data: String, signing: String, encryption: String) {
|
fn action_create_domain(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, web_view: &mut WebView<()>, name: String, data: String, signing: String, encryption: String) {
|
||||||
debug!("Creating domain with data: {}", &data);
|
debug!("Creating domain with data: {}", &data);
|
||||||
let c = Arc::clone(&context);
|
let c = Arc::clone(&context);
|
||||||
let context = context.lock().unwrap();
|
let context = context.lock().unwrap();
|
||||||
if context.get_keystore().is_none() {
|
if !context.has_keys() {
|
||||||
show_warning(web_view, "You don't have keys loaded!<br>Load or mine the keys and try again.");
|
show_warning(web_view, "You don't have keys loaded!<br>Load or mine the keys and try again.");
|
||||||
let _ = web_view.eval("domainMiningUnavailable();");
|
let _ = web_view.eval("domainMiningUnavailable();");
|
||||||
return;
|
return;
|
||||||
@@ -356,7 +398,7 @@ fn action_create_domain(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>,
|
|||||||
info!("Waiting for last full block to be signed. Try again later.");
|
info!("Waiting for last full block to be signed. Try again later.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let keystore = context.get_keystore().unwrap();
|
let keystore = context.get_keystore().unwrap().clone();
|
||||||
let pub_key = keystore.get_public();
|
let pub_key = keystore.get_public();
|
||||||
let data = match serde_json::from_str::<DomainData>(&data) {
|
let data = match serde_json::from_str::<DomainData>(&data) {
|
||||||
Ok(data) => { data }
|
Ok(data) => { data }
|
||||||
@@ -536,6 +578,7 @@ pub enum Cmd {
|
|||||||
LoadKey,
|
LoadKey,
|
||||||
CreateKey,
|
CreateKey,
|
||||||
SaveKey,
|
SaveKey,
|
||||||
|
SelectKey { index: usize },
|
||||||
CheckRecord { data: String },
|
CheckRecord { data: String },
|
||||||
CheckDomain { name: String },
|
CheckDomain { name: String },
|
||||||
MineDomain { name: String, data: String, signing: String, encryption: String },
|
MineDomain { name: String, data: String, signing: String, encryption: String },
|
||||||
@@ -571,6 +614,12 @@ impl Status {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct KeysForJS {
|
||||||
|
file_name: String,
|
||||||
|
public: String
|
||||||
|
}
|
||||||
|
|
||||||
fn inline_style(s: &str) -> String {
|
fn inline_style(s: &str) -> String {
|
||||||
format!(r#"<style type="text/css">{}</style>"#, s)
|
format!(r#"<style type="text/css">{}</style>"#, s)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,24 @@
|
|||||||
<svg viewBox="0 0 24 24" style="width: 20px; height: 20px;"><path d="M12,17A2,2 0 0,0 14,15C14,13.89 13.1,13 12,13A2,2 0 0,0 10,15A2,2 0 0,0 12,17M18,8A2,2 0 0,1 20,10V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V10C4,8.89 4.9,8 6,8H7V6A5,5 0 0,1 12,1A5,5 0 0,1 17,6V8H18M12,3A3,3 0 0,0 9,6V8H15V6A3,3 0 0,0 12,3Z"></path></svg>
|
<svg viewBox="0 0 24 24" style="width: 20px; height: 20px;"><path d="M12,17A2,2 0 0,0 14,15C14,13.89 13.1,13 12,13A2,2 0 0,0 10,15A2,2 0 0,0 12,17M18,8A2,2 0 0,1 20,10V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V10C4,8.89 4.9,8 6,8H7V6A5,5 0 0,1 12,1A5,5 0 0,1 17,6V8H18M12,3A3,3 0 0,0 9,6V8H15V6A3,3 0 0,0 12,3Z"></path></svg>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="control">
|
||||||
|
<div class="dropdown" id="keys_dropdown" onclick="toggle(this, event);">
|
||||||
|
<div class="dropdown-trigger">
|
||||||
|
<button class="button" aria-haspopup="true" aria-controls="keys_menu">
|
||||||
|
<span id="keys_current_name">No keys</span>
|
||||||
|
<span class="icon is-small">
|
||||||
|
<svg viewBox="0 0 24 24" style="width: 20px; height: 20px;"><path d="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z"></path></svg>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="dropdown-menu" id="keys_menu" role="menu">
|
||||||
|
<div class="dropdown-content" id="keys_links">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="buttons has-addons">
|
<div class="buttons has-addons">
|
||||||
<button class="button is-link is-light" onclick="loadKey();" title="Load keypair from file">Load key</button>
|
<button class="button is-link is-light" onclick="loadKey();" title="Load keypair from file">Load key</button>
|
||||||
<button class="button is-link is-light" id="save_key" onclick="saveKey();" disabled title="Save current keypair to file">Save key</button>
|
<button class="button is-link is-light" id="save_key" onclick="saveKey();" disabled title="Save current keypair to file">Save key</button>
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ var ownerEncryption = "";
|
|||||||
var availableZones = [];
|
var availableZones = [];
|
||||||
var myDomains = [];
|
var myDomains = [];
|
||||||
var currentZone;
|
var currentZone;
|
||||||
|
var currentSelectedKey = -1;
|
||||||
|
var keysLoaded = [];
|
||||||
|
|
||||||
document.addEventListener('click', function (event) {
|
document.addEventListener('click', function (event) {
|
||||||
closeDropdowns();
|
closeDropdowns();
|
||||||
@@ -577,3 +579,49 @@ function changeZone(zone, event) {
|
|||||||
});
|
});
|
||||||
refreshZonesList();
|
refreshZonesList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function refreshKeysMenu() {
|
||||||
|
var buf = "";
|
||||||
|
keysLoaded.forEach(function(value, index, array) {
|
||||||
|
var file_name = value.file_name;
|
||||||
|
if (file_name == "") {
|
||||||
|
file_name = "[Not saved]";
|
||||||
|
}
|
||||||
|
var public = value.public;
|
||||||
|
|
||||||
|
var add_class = "";
|
||||||
|
if (currentSelectedKey == index) {
|
||||||
|
add_class = "is-active";
|
||||||
|
}
|
||||||
|
buf += "<a id=\"key-{id}\" class=\"dropdown-item {class}\" onclick=\"selectKey({index}, event);\" title=\"{title}\">{name}</a>"
|
||||||
|
.replace("{id}", index)
|
||||||
|
.replace("{index}", index)
|
||||||
|
.replace("{class}", add_class)
|
||||||
|
.replace("{title}", public)
|
||||||
|
.replace("{name}", file_name);
|
||||||
|
});
|
||||||
|
var links = document.getElementById("keys_links");
|
||||||
|
links.innerHTML = buf;
|
||||||
|
if (currentSelectedKey >= 0) {
|
||||||
|
var cur_name = document.getElementById("keys_current_name");
|
||||||
|
cur_name.innerHTML = keysLoaded[currentSelectedKey].file_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function keysChanged(json) {
|
||||||
|
keysLoaded = JSON.parse(json);
|
||||||
|
refreshKeysMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectKey(index, event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
closeDropdowns();
|
||||||
|
if (currentSelectedKey != index) {
|
||||||
|
external.invoke(JSON.stringify({cmd: 'selectKey', index: parseInt(index)}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function keySelected(index) {
|
||||||
|
currentSelectedKey = index;
|
||||||
|
refreshKeysMenu();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user