Merge remote-tracking branch 'refs/remotes/origin/main'
This commit is contained in:
commit
7873f33d23
9 changed files with 177 additions and 31 deletions
|
|
@ -428,7 +428,7 @@ pub async fn run_command(command: &str) {
|
||||||
{
|
{
|
||||||
log!("Created user {}", user.user_id);
|
log!("Created user {}", user.user_id);
|
||||||
} else {
|
} else {
|
||||||
log!("Failed to create user");
|
log!("User creation: Failed to create user. See errors above.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
["user", "remove", username] => {
|
["user", "remove", username] => {
|
||||||
|
|
@ -436,7 +436,7 @@ pub async fn run_command(command: &str) {
|
||||||
user_manager::remove_user(user.user_id);
|
user_manager::remove_user(user.user_id);
|
||||||
log!("Removed user {}", user.user_id);
|
log!("Removed user {}", user.user_id);
|
||||||
} else {
|
} else {
|
||||||
log!("Failed to find user");
|
log!("User removal: Username doesn't exist");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
["user", "list"] => {
|
["user", "list"] => {
|
||||||
|
|
@ -457,7 +457,7 @@ pub async fn run_command(command: &str) {
|
||||||
user_manager::remove_user(user.user_id);
|
user_manager::remove_user(user.user_id);
|
||||||
log!("Removed user {}", user.user_id);
|
log!("Removed user {}", user.user_id);
|
||||||
} else {
|
} else {
|
||||||
log!("Failed to find user");
|
log!("User info: Username doesn't exist");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
["reload"] | ["restart"] => {
|
["reload"] | ["restart"] => {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ pub enum UserChoice {
|
||||||
AcceptAll,
|
AcceptAll,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)] // ui is unused
|
||||||
pub struct TermsCheckerScreen {
|
pub struct TermsCheckerScreen {
|
||||||
_ui: Arc<UI>,
|
_ui: Arc<UI>,
|
||||||
sender: Option<oneshot::Sender<UserChoice>>,
|
sender: Option<oneshot::Sender<UserChoice>>,
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,7 @@ use ratatui::{Terminal, backend::CrosstermBackend, init};
|
||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
io::Stdout,
|
io::Stdout,
|
||||||
sync::{
|
sync::{Arc, Mutex, atomic::Ordering},
|
||||||
Arc, Mutex,
|
|
||||||
atomic::{AtomicBool, Ordering},
|
|
||||||
},
|
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
use tokio::{sync::RwLock, time::Instant};
|
use tokio::{sync::RwLock, time::Instant};
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use iota_util::file_util::{download_and_extract_zip, has_dir};
|
||||||
use omikron_connector as omikron;
|
use omikron_connector as omikron;
|
||||||
|
|
||||||
#[tokio::main(flavor = "multi_thread", worker_threads = 16)]
|
#[tokio::main(flavor = "multi_thread", worker_threads = 16)]
|
||||||
#[allow(unused_must_use, dead_code)]
|
#[allow(unused_must_use, dead_code, unused_assignments)]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
while *RELOAD.read().await {
|
while *RELOAD.read().await {
|
||||||
*RELOAD.write().await = false;
|
*RELOAD.write().await = false;
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ use anyhow::{Context, Result, anyhow};
|
||||||
use iota_logger::log;
|
use iota_logger::log;
|
||||||
use self_replace::self_replace;
|
use self_replace::self_replace;
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use std::fs::File;
|
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
|
|
||||||
const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION");
|
const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ impl ConnectionState {
|
||||||
// Omikron Connection (Client-side with auto-reconnect)
|
// Omikron Connection (Client-side with auto-reconnect)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
|
#[allow(dead_code)] // message_send_times is unused.
|
||||||
pub struct OmikronConnection {
|
pub struct OmikronConnection {
|
||||||
state: Arc<RwLock<ConnectionState>>,
|
state: Arc<RwLock<ConnectionState>>,
|
||||||
sender: Arc<RwLock<Option<Arc<Sender>>>>,
|
sender: Arc<RwLock<Option<Arc<Sender>>>>,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use base64::{Engine as _, engine::general_purpose::STANDARD};
|
use base64::{Engine as _, engine::general_purpose::STANDARD};
|
||||||
use hex;
|
use hex;
|
||||||
use iota_logger::{PrintType, log, log_cv};
|
use iota_logger::{PrintType, log, log_cv, log_t};
|
||||||
use iota_state::{RELOAD, SHUTDOWN};
|
use iota_state::{RELOAD, SHUTDOWN};
|
||||||
use iota_storage::users::user_manager::{add_user, save_users};
|
use iota_storage::users::user_manager::{add_user, save_users};
|
||||||
use iota_storage::users::user_profile::UserProfile;
|
use iota_storage::users::user_profile::UserProfile;
|
||||||
|
|
@ -15,27 +15,36 @@ use x448::{PublicKey, Secret};
|
||||||
use crate::omikron_connection::OMIKRON_CONNECTION;
|
use crate::omikron_connection::OMIKRON_CONNECTION;
|
||||||
|
|
||||||
pub async fn create_user(username: &str) -> (Option<UserProfile>, Option<String>) {
|
pub async fn create_user(username: &str) -> (Option<UserProfile>, Option<String>) {
|
||||||
let register_cv = CommunicationValue::new(CommunicationType::get_register);
|
let register_communication_value = CommunicationValue::new(CommunicationType::get_register);
|
||||||
|
|
||||||
let conn = OMIKRON_CONNECTION.clone();
|
let connection = OMIKRON_CONNECTION.clone();
|
||||||
|
|
||||||
let response_cv = match conn
|
let response_communication_value = match connection
|
||||||
.await_response(®ister_cv, Some(Duration::from_secs(20)))
|
.await_response(®ister_communication_value, Some(Duration::from_secs(20)))
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(cv) => cv,
|
Ok(communication_value) => communication_value,
|
||||||
Err(_) => return (None, None),
|
Err(e) => {
|
||||||
|
log_t!("User creation: {}", e);
|
||||||
|
return (None, None);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
log_cv!(PrintType::Omega, response_cv);
|
log_cv!(PrintType::Omega, response_communication_value);
|
||||||
|
|
||||||
let user_id = match response_cv.get_data(DataTypes::user_id).as_number() {
|
let user_id = match response_communication_value
|
||||||
|
.get_data(DataTypes::user_id)
|
||||||
|
.as_number()
|
||||||
|
{
|
||||||
Some(id) => id,
|
Some(id) => id,
|
||||||
None => return (None, None),
|
None => {
|
||||||
|
log_t!("User creation: Response returned none");
|
||||||
|
return (None, None);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let mut buf = [0u8; 56];
|
let mut buffer = [0u8; 56];
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
rng.fill_bytes(&mut buf);
|
rng.fill_bytes(&mut buffer);
|
||||||
let private_key = Secret::from_bytes(&buf).unwrap();
|
let private_key = Secret::from_bytes(&buffer).unwrap();
|
||||||
let public_key = PublicKey::from(&private_key);
|
let public_key = PublicKey::from(&private_key);
|
||||||
|
|
||||||
let mut hasher = Sha256::new();
|
let mut hasher = Sha256::new();
|
||||||
|
|
@ -47,7 +56,7 @@ pub async fn create_user(username: &str) -> (Option<UserProfile>, Option<String>
|
||||||
OsRng.fill_bytes(&mut bytes);
|
OsRng.fill_bytes(&mut bytes);
|
||||||
let reset_token = STANDARD.encode(&bytes);
|
let reset_token = STANDARD.encode(&bytes);
|
||||||
|
|
||||||
let up = UserProfile::new(
|
let user_profile = UserProfile::new(
|
||||||
user_id,
|
user_id,
|
||||||
username.to_string(),
|
username.to_string(),
|
||||||
None,
|
None,
|
||||||
|
|
@ -56,7 +65,7 @@ pub async fn create_user(username: &str) -> (Option<UserProfile>, Option<String>
|
||||||
reset_token.clone(),
|
reset_token.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let cv = CommunicationValue::new(CommunicationType::complete_register_user)
|
let communication_value = CommunicationValue::new(CommunicationType::complete_register_user)
|
||||||
.add_data(DataTypes::user_id, DataValue::Number(user_id))
|
.add_data(DataTypes::user_id, DataValue::Number(user_id))
|
||||||
.add_data(DataTypes::username, DataValue::Str(username.to_string()))
|
.add_data(DataTypes::username, DataValue::Str(username.to_string()))
|
||||||
.add_data(
|
.add_data(
|
||||||
|
|
@ -66,16 +75,17 @@ pub async fn create_user(username: &str) -> (Option<UserProfile>, Option<String>
|
||||||
.add_data(DataTypes::iota_id, DataValue::Number(user_id))
|
.add_data(DataTypes::iota_id, DataValue::Number(user_id))
|
||||||
.add_data(DataTypes::reset_token, DataValue::Str(reset_token));
|
.add_data(DataTypes::reset_token, DataValue::Str(reset_token));
|
||||||
|
|
||||||
let response_cv = conn
|
let response_communication_value = connection
|
||||||
.await_response(&cv, Some(Duration::from_secs(20)))
|
.await_response(&communication_value, Some(Duration::from_secs(20)))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
if let Ok(resp) = response_cv {
|
if let Ok(response) = response_communication_value {
|
||||||
log_cv!(PrintType::Omega, resp);
|
log_cv!(PrintType::Omega, response);
|
||||||
if !resp.is_type(CommunicationType::success) {
|
if !response.is_type(CommunicationType::success) {
|
||||||
return (None, None);
|
return (None, None);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
log_t!("User creation: Response returned none");
|
||||||
return (None, None);
|
return (None, None);
|
||||||
}
|
}
|
||||||
*SHUTDOWN.write().await = true;
|
*SHUTDOWN.write().await = true;
|
||||||
|
|
@ -87,7 +97,10 @@ pub async fn create_user(username: &str) -> (Option<UserProfile>, Option<String>
|
||||||
&format!("{}::{}", user_id, STANDARD.encode(&private_key.as_bytes())),
|
&format!("{}::{}", user_id, STANDARD.encode(&private_key.as_bytes())),
|
||||||
);
|
);
|
||||||
|
|
||||||
add_user(up.clone());
|
add_user(user_profile.clone());
|
||||||
save_users();
|
save_users();
|
||||||
(Some(up), Some(STANDARD.encode(&private_key.as_bytes())))
|
(
|
||||||
|
Some(user_profile),
|
||||||
|
Some(STANDARD.encode(&private_key.as_bytes())),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
BIN
src/.DS_Store
vendored
Normal file
BIN
src/.DS_Store
vendored
Normal file
Binary file not shown.
135
src/util/auto_update.rs
Normal file
135
src/util/auto_update.rs
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
/* This file is used for the auto update function for the Iota.
|
||||||
|
* It connects to the git server from methanium and checks if
|
||||||
|
* the version has updated inside the cargo.toml file.*/
|
||||||
|
|
||||||
|
use anyhow::{Context, Result, anyhow};
|
||||||
|
use semver::Version;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::copy;
|
||||||
|
use tempfile::NamedTempFile;
|
||||||
|
|
||||||
|
use crate::log; // For logging messages into the iota
|
||||||
|
|
||||||
|
const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
|
const API_BASE: &str = "https://git.methanium.net/api/v1";
|
||||||
|
const OWNER: &str = "Tensamin";
|
||||||
|
const REPO: &str = "Iota";
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct Release {
|
||||||
|
tag_name: String,
|
||||||
|
assets: Vec<Asset>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct Asset {
|
||||||
|
name: String,
|
||||||
|
browser_download_url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn latest_release() -> Result<Release> {
|
||||||
|
let url = format!("{API_BASE}/repos/{OWNER}/{REPO}/releases/latest");
|
||||||
|
|
||||||
|
let response = reqwest::get(&url)
|
||||||
|
.await
|
||||||
|
.context("failed to query latest release.")?;
|
||||||
|
|
||||||
|
if !response.status().is_success() {
|
||||||
|
return Err(anyhow!("release API returned {}", response.status()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(response
|
||||||
|
.json()
|
||||||
|
.await
|
||||||
|
.context("failed to parse release JSON")?)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn parse_tag_version(tag: &str) -> Result<Version> {
|
||||||
|
let normalized = tag.strip_prefix('v').unwrap_or(tag);
|
||||||
|
Ok(Version::parse(normalized)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn current_version() -> Result<Version> {
|
||||||
|
Ok(Version::parse(CURRENT_VERSION)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn asset_name_for_current_platform() -> String {
|
||||||
|
let os = std::env::consts::OS;
|
||||||
|
let arch = std::env::consts::ARCH;
|
||||||
|
|
||||||
|
match (os, arch) {
|
||||||
|
("linux", "x86_64") => "iota-linux-x86_64".to_string(),
|
||||||
|
("linux", "aarch64") => "iota-linux-aarch64".to_string(),
|
||||||
|
("windows", "x86_64") => "iota-windows-x86_64.exe".to_string(),
|
||||||
|
("macos", "x86_64") => "iota-macos-x86_64".to_string(),
|
||||||
|
("macos", "aarch64") => "iota-macos-aarch64".to_string(),
|
||||||
|
_ => panic!("unsupported platform: {os}/{arch}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn download_asset(url: &str) -> Result<NamedTempFile> {
|
||||||
|
let mut response = reqwest::get(url)
|
||||||
|
.await
|
||||||
|
.context("failed to download asset")?;
|
||||||
|
|
||||||
|
if !response.status().is_success() {
|
||||||
|
return Err(anyhow!("asset download returned {}", response.status()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let tmp = NamedTempFile::new().context("failed to create temp file")?;
|
||||||
|
let mut out = File::create(tmp.path()).context("failed to open temp file")?;
|
||||||
|
|
||||||
|
let bytes = response
|
||||||
|
.bytes()
|
||||||
|
.await
|
||||||
|
.context("failed to read response bytes")?;
|
||||||
|
|
||||||
|
std::fs::write(tmp.path(), &bytes).context("failed to write file")?;
|
||||||
|
|
||||||
|
Ok(tmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn check_for_update() -> Result<Option<Release>> {
|
||||||
|
let current = current_version().await?;
|
||||||
|
let release = latest_release().await?;
|
||||||
|
let latest = parse_tag_version(&release.tag_name).await?;
|
||||||
|
|
||||||
|
if latest > current {
|
||||||
|
Ok(Some(release))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn perform_update() -> Result<bool> {
|
||||||
|
let Some(release) = check_for_update().await? else {
|
||||||
|
return Ok(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
let wanted_asset = asset_name_for_current_platform().await;
|
||||||
|
|
||||||
|
let asset = release
|
||||||
|
.assets
|
||||||
|
.iter()
|
||||||
|
.find(|a| a.name == wanted_asset)
|
||||||
|
.ok_or_else(|| anyhow!("no matching asset found: {}", wanted_asset))?;
|
||||||
|
|
||||||
|
log!("Downloading update: {}", asset.name);
|
||||||
|
|
||||||
|
let downloaded = download_asset(&asset.browser_download_url).await?;
|
||||||
|
|
||||||
|
self_replace::self_replace(downloaded.path())
|
||||||
|
.context("failed to replace current executable")?;
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn check_update() -> Result<bool> {
|
||||||
|
if perform_update().await? {
|
||||||
|
return Ok(true);
|
||||||
|
} else {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue