mirror of
https://github.com/stakwork/sphinx-key.git
synced 2025-12-18 15:54:31 +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" ]
|
||||
then
|
||||
cargo build --release
|
||||
cargo build --release --bin sphinx-key
|
||||
else
|
||||
cargo build
|
||||
cargo build --bin sphinx-key
|
||||
fi &&
|
||||
|
||||
esptool.py --chip esp32-c3 elf2image ../target/riscv32imc-esp-espidf/$MODE/sphinx-key &&
|
||||
|
||||
@@ -23,7 +23,8 @@ pub struct Params {
|
||||
|
||||
#[allow(unused_variables, deprecated)]
|
||||
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> {
|
||||
let (sk1, pk1) = ecdh_keypair();
|
||||
|
||||
@@ -47,6 +48,9 @@ pub fn config_server(
|
||||
let dto = serde_json::from_str::<ConfigDTO>(¶ms.config)?;
|
||||
|
||||
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();
|
||||
*wait = Some(conf_seed_tuple);
|
||||
|
||||
@@ -33,14 +33,12 @@ pub fn start_client(
|
||||
}))?;
|
||||
info!("Wifi configured");
|
||||
|
||||
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);
|
||||
loop {
|
||||
match try_connection(&mut wifi) {
|
||||
Ok(_) => break,
|
||||
Err(e) => info!("error: {}, trying wifi connection again!", e),
|
||||
}
|
||||
}
|
||||
|
||||
// let status = wifi.get_status();
|
||||
// println!("=> wifi STATUS {:?}", status);
|
||||
@@ -66,6 +64,18 @@ pub fn start_client(
|
||||
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(
|
||||
modem: impl peripheral::Peripheral<P = esp_idf_hal::modem::Modem> + 'static,
|
||||
default_nvs: EspDefaultNvsPartition,
|
||||
|
||||
@@ -30,9 +30,9 @@ pub struct ConfigDTO {
|
||||
pub broker: String,
|
||||
pub ssid: String,
|
||||
pub pass: String,
|
||||
pub pubkey: String,
|
||||
pub seed: String, // encrypted (56 bytes)
|
||||
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())
|
||||
}
|
||||
|
||||
pub fn decrypt_seed(dto: ConfigDTO, sk1: SecretKey) -> Result<(Config, [u8; 32])> {
|
||||
let their_pk = hex::decode(dto.pubkey)?;
|
||||
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())?;
|
||||
// decrypt seed
|
||||
let cipher_seed = hex::decode(dto.seed)?;
|
||||
let cipher: [u8; PAYLOAD_LEN] = cipher_seed[..PAYLOAD_LEN].try_into()?;
|
||||
let seed = decrypt(cipher, shared_secret)?;
|
||||
|
||||
pub fn decrypt_seed(dto: ConfigDTO, sk1: SecretKey) -> Result<(Config, Option<[u8; 32]>)> {
|
||||
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 shared_secret =
|
||||
derive_shared_secret_from_slice(their_pk_bytes, sk1.secret_bytes())?;
|
||||
// decrypt seed
|
||||
let cipher_seed = hex::decode(seed_in)?;
|
||||
let cipher: [u8; PAYLOAD_LEN] = cipher_seed[..PAYLOAD_LEN].try_into()?;
|
||||
seed = Some(decrypt(cipher, shared_secret)?);
|
||||
}
|
||||
}
|
||||
Ok((
|
||||
Config {
|
||||
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(
|
||||
modem: impl peripheral::Peripheral<P = esp_idf_hal::modem::Modem> + 'static,
|
||||
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()));
|
||||
|
||||
#[allow(clippy::redundant_clone)]
|
||||
#[allow(unused_mut)]
|
||||
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();
|
||||
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 {
|
||||
break conf;
|
||||
} else {
|
||||
|
||||
@@ -4,7 +4,8 @@ mod ota;
|
||||
mod periph;
|
||||
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::periph::button::button_loop;
|
||||
use crate::periph::led::led_control_loop;
|
||||
@@ -43,11 +44,6 @@ fn main() -> Result<()> {
|
||||
// LED control thread
|
||||
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();
|
||||
println!("About to mount the sdcard...");
|
||||
while let Err(_e) = mount_sd_card() {
|
||||
@@ -59,12 +55,17 @@ fn main() -> Result<()> {
|
||||
// let default_nav_partition = EspDefaultNvs.take().unwrap();
|
||||
let default_nvs = EspDefaultNvsPartition::take()?;
|
||||
// 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() {
|
||||
let seed = flash.read_seed().expect("no seed...");
|
||||
let id = flash.read_id().expect("no id...");
|
||||
let policy = flash.read_policy().unwrap_or_default();
|
||||
let velocity = flash.read_velocity().ok();
|
||||
drop(flash);
|
||||
println!(
|
||||
"=============> START CLIENT NOW <============== {:?}",
|
||||
exist
|
||||
@@ -95,7 +96,6 @@ fn main() -> Result<()> {
|
||||
|
||||
led_tx.send(Status::ConnectingToMqtt).unwrap();
|
||||
|
||||
let flash_arc = Arc::new(Mutex::new(flash));
|
||||
loop {
|
||||
if let Ok(()) = make_and_launch_client(
|
||||
exist.clone(),
|
||||
@@ -116,13 +116,24 @@ fn main() -> Result<()> {
|
||||
} else {
|
||||
led_tx.send(Status::WifiAccessPoint).unwrap();
|
||||
println!("=============> START SERVER NOW AND WAIT <==============");
|
||||
match start_config_server_and_wait(peripherals.modem, default_nvs.clone()) {
|
||||
Ok((_wifi, config, seed)) => {
|
||||
let stored_seed = flash.read_seed().ok();
|
||||
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_seed(seed).expect("could not store seed");
|
||||
flash
|
||||
.write_id(random_word(ID_LEN))
|
||||
.expect("could not store id");
|
||||
if stored_seed.is_none() {
|
||||
match seed_opt {
|
||||
Some(s) => flash.write_seed(s).expect("could not store seed"),
|
||||
None => panic!("SEED REQUIRED!!!"),
|
||||
}
|
||||
flash
|
||||
.write_id(random_word(ID_LEN))
|
||||
.expect("could not store id");
|
||||
}
|
||||
drop(flash);
|
||||
println!("CONFIG SAVED");
|
||||
unsafe { esp_idf_sys::esp_restart() };
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use crate::status::Status;
|
||||
use crate::FlashPersister;
|
||||
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::time::Duration;
|
||||
|
||||
@@ -11,7 +13,11 @@ const PAUSE: u16 = 50;
|
||||
|
||||
// progression is waiting -> *starting -> reset1a -> reset1 -> reset2a -> reset2 -> reset3
|
||||
// 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 || {
|
||||
let mut button = PinDriver::input(gpio9).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);
|
||||
loop {
|
||||
// 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()));
|
||||
if button.is_high() {
|
||||
if pressed {
|
||||
|
||||
@@ -64,9 +64,9 @@ then
|
||||
fi
|
||||
if [ $MODE = "release" ]
|
||||
then
|
||||
cargo build --release
|
||||
cargo build --release --bin sphinx-key
|
||||
else
|
||||
cargo build
|
||||
cargo build --bin sphinx-key
|
||||
fi &&
|
||||
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 &&
|
||||
|
||||
@@ -33,6 +33,10 @@ sphinx-crypter = { git = "https://github.com/stakwork/sphinx-rs.git" }
|
||||
name = "config"
|
||||
path = "src/config.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "wifi"
|
||||
path = "src/wifi.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "config-server"
|
||||
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