mirror of
https://github.com/stakwork/sphinx-key.git
synced 2025-12-19 08:14:28 +01:00
sphinx-key: implement wifi reset
additional-author: evan feenstra this is an access mode that expects just the wifi config params, without the seed
This commit is contained in:
@@ -70,9 +70,9 @@ cd ../sphinx-key &&
|
|||||||
|
|
||||||
if [ $MODE = "release" ]
|
if [ $MODE = "release" ]
|
||||||
then
|
then
|
||||||
cargo build --release
|
cargo build --release --bin sphinx-key
|
||||||
else
|
else
|
||||||
cargo build
|
cargo build --bin sphinx-key
|
||||||
fi &&
|
fi &&
|
||||||
|
|
||||||
esptool.py --chip esp32-c3 elf2image ../target/riscv32imc-esp-espidf/$MODE/sphinx-key &&
|
esptool.py --chip esp32-c3 elf2image ../target/riscv32imc-esp-espidf/$MODE/sphinx-key &&
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ pub struct Params {
|
|||||||
|
|
||||||
#[allow(unused_variables, deprecated)]
|
#[allow(unused_variables, deprecated)]
|
||||||
pub fn config_server(
|
pub fn config_server(
|
||||||
mutex: Arc<(Mutex<Option<(Config, [u8; 32])>>, Condvar)>,
|
mutex: Arc<(Mutex<Option<(Config, Option<[u8; 32]>)>>, Condvar)>,
|
||||||
|
has_stored_seed: bool,
|
||||||
) -> Result<idf::Server> {
|
) -> Result<idf::Server> {
|
||||||
let (sk1, pk1) = ecdh_keypair();
|
let (sk1, pk1) = ecdh_keypair();
|
||||||
|
|
||||||
@@ -47,6 +48,9 @@ pub fn config_server(
|
|||||||
let dto = serde_json::from_str::<ConfigDTO>(¶ms.config)?;
|
let dto = serde_json::from_str::<ConfigDTO>(¶ms.config)?;
|
||||||
|
|
||||||
let conf_seed_tuple = decrypt_seed(dto, sk1)?;
|
let conf_seed_tuple = decrypt_seed(dto, sk1)?;
|
||||||
|
if !has_stored_seed && conf_seed_tuple.1.is_none() {
|
||||||
|
return Err(anyhow::anyhow!("seed required"));
|
||||||
|
}
|
||||||
|
|
||||||
let mut wait = mutex.0.lock().unwrap();
|
let mut wait = mutex.0.lock().unwrap();
|
||||||
*wait = Some(conf_seed_tuple);
|
*wait = Some(conf_seed_tuple);
|
||||||
|
|||||||
@@ -33,14 +33,12 @@ pub fn start_client(
|
|||||||
}))?;
|
}))?;
|
||||||
info!("Wifi configured");
|
info!("Wifi configured");
|
||||||
|
|
||||||
wifi.start()?;
|
loop {
|
||||||
info!("Wifi started");
|
match try_connection(&mut wifi) {
|
||||||
wifi.connect()?;
|
Ok(_) => break,
|
||||||
info!("Wifi connected");
|
Err(e) => info!("error: {}, trying wifi connection again!", e),
|
||||||
wifi.wait_netif_up()?;
|
}
|
||||||
info!("Wifi netif up");
|
}
|
||||||
let ip_info = wifi.wifi().sta_netif().get_ip_info()?;
|
|
||||||
info!("Wifi DHCP info: {:?}", ip_info);
|
|
||||||
|
|
||||||
// let status = wifi.get_status();
|
// let status = wifi.get_status();
|
||||||
// println!("=> wifi STATUS {:?}", status);
|
// println!("=> wifi STATUS {:?}", status);
|
||||||
@@ -66,6 +64,18 @@ pub fn start_client(
|
|||||||
Ok(wifi)
|
Ok(wifi)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_connection(wifi: &mut BlockingWifi<EspWifi<'static>>) -> Result<()> {
|
||||||
|
wifi.start()?;
|
||||||
|
info!("Wifi started");
|
||||||
|
wifi.connect()?;
|
||||||
|
info!("Wifi connected");
|
||||||
|
wifi.wait_netif_up()?;
|
||||||
|
info!("Wifi netif up");
|
||||||
|
let ip_info = wifi.wifi().sta_netif().get_ip_info()?;
|
||||||
|
info!("Wifi DHCP info: {:?}", ip_info);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn start_access_point(
|
pub fn start_access_point(
|
||||||
modem: impl peripheral::Peripheral<P = esp_idf_hal::modem::Modem> + 'static,
|
modem: impl peripheral::Peripheral<P = esp_idf_hal::modem::Modem> + 'static,
|
||||||
default_nvs: EspDefaultNvsPartition,
|
default_nvs: EspDefaultNvsPartition,
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ pub struct ConfigDTO {
|
|||||||
pub broker: String,
|
pub broker: String,
|
||||||
pub ssid: String,
|
pub ssid: String,
|
||||||
pub pass: String,
|
pub pass: String,
|
||||||
pub pubkey: String,
|
|
||||||
pub seed: String, // encrypted (56 bytes)
|
|
||||||
pub network: String,
|
pub network: String,
|
||||||
|
pub pubkey: Option<String>,
|
||||||
|
pub seed: Option<String>, // encrypted (56 bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -55,15 +55,20 @@ pub fn ecdh_keypair() -> (SecretKey, PublicKey) {
|
|||||||
s.generate_keypair(&mut thread_rng())
|
s.generate_keypair(&mut thread_rng())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decrypt_seed(dto: ConfigDTO, sk1: SecretKey) -> Result<(Config, [u8; 32])> {
|
pub fn decrypt_seed(dto: ConfigDTO, sk1: SecretKey) -> Result<(Config, Option<[u8; 32]>)> {
|
||||||
let their_pk = hex::decode(dto.pubkey)?;
|
let mut seed = None;
|
||||||
|
if let Some(pubkey) = dto.pubkey {
|
||||||
|
if let Some(seed_in) = dto.seed {
|
||||||
|
let their_pk = hex::decode(pubkey)?;
|
||||||
let their_pk_bytes: [u8; PUBLIC_KEY_LEN] = their_pk[..PUBLIC_KEY_LEN].try_into()?;
|
let their_pk_bytes: [u8; PUBLIC_KEY_LEN] = their_pk[..PUBLIC_KEY_LEN].try_into()?;
|
||||||
let shared_secret = derive_shared_secret_from_slice(their_pk_bytes, sk1.secret_bytes())?;
|
let shared_secret =
|
||||||
|
derive_shared_secret_from_slice(their_pk_bytes, sk1.secret_bytes())?;
|
||||||
// decrypt seed
|
// decrypt seed
|
||||||
let cipher_seed = hex::decode(dto.seed)?;
|
let cipher_seed = hex::decode(seed_in)?;
|
||||||
let cipher: [u8; PAYLOAD_LEN] = cipher_seed[..PAYLOAD_LEN].try_into()?;
|
let cipher: [u8; PAYLOAD_LEN] = cipher_seed[..PAYLOAD_LEN].try_into()?;
|
||||||
let seed = decrypt(cipher, shared_secret)?;
|
seed = Some(decrypt(cipher, shared_secret)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok((
|
Ok((
|
||||||
Config {
|
Config {
|
||||||
broker: dto.broker,
|
broker: dto.broker,
|
||||||
@@ -78,18 +83,23 @@ pub fn decrypt_seed(dto: ConfigDTO, sk1: SecretKey) -> Result<(Config, [u8; 32])
|
|||||||
pub fn start_config_server_and_wait(
|
pub fn start_config_server_and_wait(
|
||||||
modem: impl peripheral::Peripheral<P = esp_idf_hal::modem::Modem> + 'static,
|
modem: impl peripheral::Peripheral<P = esp_idf_hal::modem::Modem> + 'static,
|
||||||
default_nvs: EspDefaultNvsPartition,
|
default_nvs: EspDefaultNvsPartition,
|
||||||
) -> Result<(BlockingWifi<EspWifi<'static>>, Config, [u8; 32])> {
|
has_stored_seed: bool,
|
||||||
|
) -> Result<(BlockingWifi<EspWifi<'static>>, Config, Option<[u8; 32]>)> {
|
||||||
let mutex = Arc::new((Mutex::new(None), Condvar::new()));
|
let mutex = Arc::new((Mutex::new(None), Condvar::new()));
|
||||||
|
|
||||||
#[allow(clippy::redundant_clone)]
|
#[allow(clippy::redundant_clone)]
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
let mut wifi = conn::wifi::start_access_point(modem, default_nvs.clone())?;
|
let mut wifi = conn::wifi::start_access_point(modem, default_nvs.clone())?;
|
||||||
|
|
||||||
let httpd = conn::http::config_server(mutex.clone());
|
let httpd = conn::http::config_server(mutex.clone(), has_stored_seed)?;
|
||||||
let mut wait = mutex.0.lock().unwrap();
|
let mut wait = mutex.0.lock().unwrap();
|
||||||
log::info!("Waiting for data from the phone!");
|
if has_stored_seed {
|
||||||
|
log::info!("Waiting for wifi details from the phone!");
|
||||||
|
} else {
|
||||||
|
log::info!("Waiting for seed and data from the phone!");
|
||||||
|
}
|
||||||
|
|
||||||
let config_seed_tuple: &(Config, [u8; 32]) = loop {
|
let config_seed_tuple: &(Config, Option<[u8; 32]>) = loop {
|
||||||
if let Some(conf) = &*wait {
|
if let Some(conf) = &*wait {
|
||||||
break conf;
|
break conf;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ mod ota;
|
|||||||
mod periph;
|
mod periph;
|
||||||
mod status;
|
mod status;
|
||||||
|
|
||||||
use crate::core::control::{controller_from_seed, FlashPersister};
|
use crate::core::control::controller_from_seed;
|
||||||
|
pub use crate::core::control::FlashPersister;
|
||||||
use crate::core::{config::*, events::*};
|
use crate::core::{config::*, events::*};
|
||||||
use crate::periph::button::button_loop;
|
use crate::periph::button::button_loop;
|
||||||
use crate::periph::led::led_control_loop;
|
use crate::periph::led::led_control_loop;
|
||||||
@@ -43,11 +44,6 @@ fn main() -> Result<()> {
|
|||||||
// LED control thread
|
// LED control thread
|
||||||
led_control_loop(pins.gpio0, peripherals.rmt.channel0, led_rx);
|
led_control_loop(pins.gpio0, peripherals.rmt.channel0, led_rx);
|
||||||
|
|
||||||
// BUTTON thread
|
|
||||||
// button_loop(pins.gpio9, led_tx.clone());
|
|
||||||
|
|
||||||
// thread::sleep(Duration::from_secs(100));
|
|
||||||
|
|
||||||
led_tx.send(Status::MountingSDCard).unwrap();
|
led_tx.send(Status::MountingSDCard).unwrap();
|
||||||
println!("About to mount the sdcard...");
|
println!("About to mount the sdcard...");
|
||||||
while let Err(_e) = mount_sd_card() {
|
while let Err(_e) = mount_sd_card() {
|
||||||
@@ -59,12 +55,17 @@ fn main() -> Result<()> {
|
|||||||
// let default_nav_partition = EspDefaultNvs.take().unwrap();
|
// let default_nav_partition = EspDefaultNvs.take().unwrap();
|
||||||
let default_nvs = EspDefaultNvsPartition::take()?;
|
let default_nvs = EspDefaultNvsPartition::take()?;
|
||||||
// let default_nvs = Arc::new();
|
// let default_nvs = Arc::new();
|
||||||
let mut flash = FlashPersister::new(default_nvs.clone());
|
let flash_per = FlashPersister::new(default_nvs.clone());
|
||||||
|
let flash_arc = Arc::new(Mutex::new(flash_per));
|
||||||
|
// BUTTON thread
|
||||||
|
button_loop(pins.gpio9, led_tx.clone(), flash_arc.clone());
|
||||||
|
let mut flash = flash_arc.lock().unwrap();
|
||||||
if let Ok(exist) = flash.read_config() {
|
if let Ok(exist) = flash.read_config() {
|
||||||
let seed = flash.read_seed().expect("no seed...");
|
let seed = flash.read_seed().expect("no seed...");
|
||||||
let id = flash.read_id().expect("no id...");
|
let id = flash.read_id().expect("no id...");
|
||||||
let policy = flash.read_policy().unwrap_or_default();
|
let policy = flash.read_policy().unwrap_or_default();
|
||||||
let velocity = flash.read_velocity().ok();
|
let velocity = flash.read_velocity().ok();
|
||||||
|
drop(flash);
|
||||||
println!(
|
println!(
|
||||||
"=============> START CLIENT NOW <============== {:?}",
|
"=============> START CLIENT NOW <============== {:?}",
|
||||||
exist
|
exist
|
||||||
@@ -95,7 +96,6 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
led_tx.send(Status::ConnectingToMqtt).unwrap();
|
led_tx.send(Status::ConnectingToMqtt).unwrap();
|
||||||
|
|
||||||
let flash_arc = Arc::new(Mutex::new(flash));
|
|
||||||
loop {
|
loop {
|
||||||
if let Ok(()) = make_and_launch_client(
|
if let Ok(()) = make_and_launch_client(
|
||||||
exist.clone(),
|
exist.clone(),
|
||||||
@@ -116,13 +116,24 @@ fn main() -> Result<()> {
|
|||||||
} else {
|
} else {
|
||||||
led_tx.send(Status::WifiAccessPoint).unwrap();
|
led_tx.send(Status::WifiAccessPoint).unwrap();
|
||||||
println!("=============> START SERVER NOW AND WAIT <==============");
|
println!("=============> START SERVER NOW AND WAIT <==============");
|
||||||
match start_config_server_and_wait(peripherals.modem, default_nvs.clone()) {
|
let stored_seed = flash.read_seed().ok();
|
||||||
Ok((_wifi, config, seed)) => {
|
match start_config_server_and_wait(
|
||||||
|
peripherals.modem,
|
||||||
|
default_nvs.clone(),
|
||||||
|
stored_seed.is_some(),
|
||||||
|
) {
|
||||||
|
Ok((_wifi, config, seed_opt)) => {
|
||||||
flash.write_config(config).expect("could not store config");
|
flash.write_config(config).expect("could not store config");
|
||||||
flash.write_seed(seed).expect("could not store seed");
|
if stored_seed.is_none() {
|
||||||
|
match seed_opt {
|
||||||
|
Some(s) => flash.write_seed(s).expect("could not store seed"),
|
||||||
|
None => panic!("SEED REQUIRED!!!"),
|
||||||
|
}
|
||||||
flash
|
flash
|
||||||
.write_id(random_word(ID_LEN))
|
.write_id(random_word(ID_LEN))
|
||||||
.expect("could not store id");
|
.expect("could not store id");
|
||||||
|
}
|
||||||
|
drop(flash);
|
||||||
println!("CONFIG SAVED");
|
println!("CONFIG SAVED");
|
||||||
unsafe { esp_idf_sys::esp_restart() };
|
unsafe { esp_idf_sys::esp_restart() };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
use crate::status::Status;
|
use crate::status::Status;
|
||||||
|
use crate::FlashPersister;
|
||||||
use esp_idf_hal::gpio;
|
use esp_idf_hal::gpio;
|
||||||
use esp_idf_hal::gpio::*;
|
use esp_idf_hal::gpio::*;
|
||||||
use std::sync::mpsc;
|
use sphinx_signer::sphinx_glyph::control::ControlPersist;
|
||||||
|
use std::sync::{mpsc, Arc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
@@ -11,7 +13,11 @@ const PAUSE: u16 = 50;
|
|||||||
|
|
||||||
// progression is waiting -> *starting -> reset1a -> reset1 -> reset2a -> reset2 -> reset3
|
// progression is waiting -> *starting -> reset1a -> reset1 -> reset2a -> reset2 -> reset3
|
||||||
// state machine initialized at starting
|
// state machine initialized at starting
|
||||||
pub fn button_loop(gpio9: gpio::Gpio9, tx: mpsc::Sender<Status>) {
|
pub fn button_loop(
|
||||||
|
gpio9: gpio::Gpio9,
|
||||||
|
tx: mpsc::Sender<Status>,
|
||||||
|
flash_arc: Arc<Mutex<FlashPersister>>,
|
||||||
|
) {
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut button = PinDriver::input(gpio9).unwrap();
|
let mut button = PinDriver::input(gpio9).unwrap();
|
||||||
button.set_pull(Pull::Up).unwrap();
|
button.set_pull(Pull::Up).unwrap();
|
||||||
@@ -21,6 +27,17 @@ pub fn button_loop(gpio9: gpio::Gpio9, tx: mpsc::Sender<Status>) {
|
|||||||
let mut machine = Machine::new(tx, Status::Starting);
|
let mut machine = Machine::new(tx, Status::Starting);
|
||||||
loop {
|
loop {
|
||||||
// we are using thread::sleep here to make sure the watchdog isn't triggered
|
// we are using thread::sleep here to make sure the watchdog isn't triggered
|
||||||
|
if machine.state == Status::Reset3 {
|
||||||
|
let mut flash = flash_arc.lock().unwrap();
|
||||||
|
if let Err(_e) = flash.remove_config() {
|
||||||
|
log::error!("could not clear wifi config");
|
||||||
|
drop(flash);
|
||||||
|
} else {
|
||||||
|
log::info!("restarting esp!");
|
||||||
|
drop(flash);
|
||||||
|
unsafe { esp_idf_sys::esp_restart() };
|
||||||
|
}
|
||||||
|
}
|
||||||
thread::sleep(Duration::from_millis(PAUSE.into()));
|
thread::sleep(Duration::from_millis(PAUSE.into()));
|
||||||
if button.is_high() {
|
if button.is_high() {
|
||||||
if pressed {
|
if pressed {
|
||||||
|
|||||||
@@ -64,9 +64,9 @@ then
|
|||||||
fi
|
fi
|
||||||
if [ $MODE = "release" ]
|
if [ $MODE = "release" ]
|
||||||
then
|
then
|
||||||
cargo build --release
|
cargo build --release --bin sphinx-key
|
||||||
else
|
else
|
||||||
cargo build
|
cargo build --bin sphinx-key
|
||||||
fi &&
|
fi &&
|
||||||
esptool.py --chip esp32-c3 elf2image ../target/riscv32imc-esp-espidf/$MODE/sphinx-key &&
|
esptool.py --chip esp32-c3 elf2image ../target/riscv32imc-esp-espidf/$MODE/sphinx-key &&
|
||||||
esptool.py --chip esp32c3 -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 4MB 0x90000 ../target/riscv32imc-esp-espidf/$MODE/sphinx-key.bin &&
|
esptool.py --chip esp32c3 -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 4MB 0x90000 ../target/riscv32imc-esp-espidf/$MODE/sphinx-key.bin &&
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ sphinx-crypter = { git = "https://github.com/stakwork/sphinx-rs.git" }
|
|||||||
name = "config"
|
name = "config"
|
||||||
path = "src/config.rs"
|
path = "src/config.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "wifi"
|
||||||
|
path = "src/wifi.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "config-server"
|
name = "config-server"
|
||||||
path = "src/server.rs"
|
path = "src/server.rs"
|
||||||
|
|||||||
61
tester/src/wifi.rs
Normal file
61
tester/src/wifi.rs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
use dotenv::dotenv;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::env;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use sphinx_signer::sphinx_glyph::control::Config;
|
||||||
|
|
||||||
|
const URL: &str = "http://192.168.71.1";
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct ConfigResponse {
|
||||||
|
pub success: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> anyhow::Result<()> {
|
||||||
|
dotenv().ok();
|
||||||
|
|
||||||
|
let url: String = env::var("URL").unwrap_or(URL.to_string());
|
||||||
|
|
||||||
|
let ssid: String = env::var("SSID").expect("no ssid");
|
||||||
|
let pass: String = env::var("PASS").expect("no pass");
|
||||||
|
let broker: String = env::var("BROKER").expect("no broker");
|
||||||
|
let network: String = env::var("NETWORK").unwrap_or("regtest".to_string());
|
||||||
|
if !(network == "bitcoin"
|
||||||
|
|| network == "mainnet"
|
||||||
|
|| network == "testnet"
|
||||||
|
|| network == "signet"
|
||||||
|
|| network == "regtest")
|
||||||
|
{
|
||||||
|
panic!("invalid network string");
|
||||||
|
}
|
||||||
|
println!("network {:?}", network);
|
||||||
|
|
||||||
|
let client = reqwest::Client::builder()
|
||||||
|
.timeout(Duration::from_secs(10))
|
||||||
|
.build()
|
||||||
|
.expect("couldnt build reqwest client");
|
||||||
|
|
||||||
|
let config = Config {
|
||||||
|
ssid,
|
||||||
|
pass,
|
||||||
|
broker,
|
||||||
|
network,
|
||||||
|
};
|
||||||
|
|
||||||
|
let conf_string = serde_json::to_string(&config)?;
|
||||||
|
let conf_encoded = urlencoding::encode(&conf_string).to_owned();
|
||||||
|
|
||||||
|
let res = client
|
||||||
|
.post(format!("{}/{}={}", url, "config?config", conf_encoded))
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
let conf_res: ConfigResponse = res.json().await?;
|
||||||
|
|
||||||
|
if conf_res.success {
|
||||||
|
println!("SUCCESS!")
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user