aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src-tauri/Cargo.lock44
-rw-r--r--src-tauri/Cargo.toml4
-rw-r--r--src-tauri/src/constants.rs3
-rw-r--r--src-tauri/src/github/release_notes.rs45
-rw-r--r--src-tauri/src/main.rs1
-rw-r--r--src-tauri/src/mod_management/mod.rs12
-rw-r--r--src-tauri/src/platform_specific/mod.rs10
-rw-r--r--src-tauri/src/platform_specific/windows.rs70
-rw-r--r--src-tauri/tauri.conf.json2
-rw-r--r--src-vue/src/views/DeveloperView.vue12
10 files changed, 177 insertions, 26 deletions
diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock
index db7379e2..1e7eacbc 100644
--- a/src-tauri/Cargo.lock
+++ b/src-tauri/Cargo.lock
@@ -1165,7 +1165,7 @@ dependencies = [
[[package]]
name = "flightcore"
-version = "2.23.2"
+version = "2.24.0"
dependencies = [
"anyhow",
"async-recursion",
@@ -1179,6 +1179,7 @@ dependencies = [
"octocrab",
"open 5.3.0",
"pretty_env_logger",
+ "rand 0.8.5",
"regex",
"remove-markdown-links",
"reqwest 0.11.27",
@@ -1716,9 +1717,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
-version = "0.3.2"
+version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
name = "hex"
@@ -2504,13 +2505,14 @@ dependencies = [
[[package]]
name = "mio"
-version = "0.8.9"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0"
+checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4"
dependencies = [
+ "hermit-abi",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -2686,16 +2688,6 @@ dependencies = [
]
[[package]]
-name = "num_cpus"
-version = "1.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
-dependencies = [
- "hermit-abi",
- "libc",
-]
-
-[[package]]
name = "num_enum"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5041,28 +5033,27 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
-version = "1.38.0"
+version = "1.39.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
+checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1"
dependencies = [
"backtrace",
"bytes",
"libc",
"mio",
- "num_cpus",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"socket2 0.5.5",
"tokio-macros",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
]
[[package]]
name = "tokio-macros"
-version = "2.3.0"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
+checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
dependencies = [
"proc-macro2",
"quote",
@@ -5922,6 +5913,15 @@ dependencies = [
]
[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.0",
+]
+
+[[package]]
name = "windows-targets"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index c9a559a7..210c76b8 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "flightcore"
-version = "2.23.2"
+version = "2.24.0"
description = "Mod-manager for Northstar"
authors = ["https://github.com/R2NorthstarTools/FlightCore/graphs/contributors"]
license = "MIT"
@@ -65,6 +65,8 @@ semver = "1.0"
# simplified filesystem access
glob = "0.3.1"
dirs = "5"
+# Random number stuff
+rand = "0.8.5"
# Interacting with GitHub
octocrab = "0.38.0"
diff --git a/src-tauri/src/constants.rs b/src-tauri/src/constants.rs
index 47eeef19..3ad2d6e8 100644
--- a/src-tauri/src/constants.rs
+++ b/src-tauri/src/constants.rs
@@ -26,6 +26,9 @@ pub const BLACKLISTED_MODS: [&str; 3] = [
"ebkr-r2modman",
];
+/// List of Thunderstoremods that have some specific install requirements that makes them different from standard mods
+pub const MODS_WITH_SPECIAL_REQUIREMENTS: [&str; 1] = ["NanohmProtogen-VanillaPlus"];
+
/// Order in which the sections for release notes should be displayed
pub const SECTION_ORDER: [&str; 11] = [
"feat", "fix", "docs", "style", "refactor", "build", "test", "i18n", "ci", "chore", "other",
diff --git a/src-tauri/src/github/release_notes.rs b/src-tauri/src/github/release_notes.rs
index e3a14537..4adfb24b 100644
--- a/src-tauri/src/github/release_notes.rs
+++ b/src-tauri/src/github/release_notes.rs
@@ -1,3 +1,4 @@
+use rand::prelude::SliceRandom;
use serde::{Deserialize, Serialize};
use std::vec::Vec;
use ts_rs::TS;
@@ -168,9 +169,51 @@ pub async fn generate_release_note_announcement() -> Result<String, String> {
let modders_info = "Mod compatibility should not be impacted";
let server_hosters_info = "REPLACE ME";
+ let mut rng = rand::thread_rng();
+ let attributes = vec![
+ "adorable",
+ "amazing",
+ "beautiful",
+ "blithsome",
+ "brilliant",
+ "compassionate",
+ "dazzling",
+ "delightful",
+ "distinguished",
+ "elegant",
+ "enigmatic",
+ "enthusiastic",
+ "fashionable",
+ "fortuitous",
+ "friendly",
+ "generous",
+ "gleeful",
+ "gorgeous",
+ "handsome",
+ "lively",
+ "lovely",
+ "lucky",
+ "lustrous",
+ "marvelous",
+ "merry",
+ "mirthful",
+ "phantasmagorical",
+ "pretty",
+ "propitious",
+ "ravishing",
+ "sincere",
+ "sophisticated fellow",
+ "stupendous",
+ "vivacious",
+ "wonderful",
+ "zestful",
+ ];
+
+ let selected_attribute = attributes.choose(&mut rng).unwrap();
+
// Build announcement string
let return_string = format!(
- r"Hello beautiful people <3
+ r"Hello {selected_attribute} people <3
**Northstar `{current_ns_version}` is out!**
{general_info}
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index ee7da27f..a9f484f5 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -136,6 +136,7 @@ fn main() {
northstar::profile::delete_profile,
northstar::profile::fetch_profiles,
northstar::profile::validate_profile,
+ platform_specific::check_cgnat,
platform_specific::get_host_os,
platform_specific::get_local_northstar_proton_wrapper_version,
platform_specific::install_northstar_proton_wrapper,
diff --git a/src-tauri/src/mod_management/mod.rs b/src-tauri/src/mod_management/mod.rs
index ebbcf431..2a018920 100644
--- a/src-tauri/src/mod_management/mod.rs
+++ b/src-tauri/src/mod_management/mod.rs
@@ -1,6 +1,6 @@
// This file contains various mod management functions
-use crate::constants::{BLACKLISTED_MODS, CORE_MODS};
+use crate::constants::{BLACKLISTED_MODS, CORE_MODS, MODS_WITH_SPECIAL_REQUIREMENTS};
use async_recursion::async_recursion;
use thermite::prelude::ThermiteError;
@@ -609,6 +609,16 @@ pub async fn fc_download_mod_and_install(
}
}
+ // Prevent installing mods that have specific install requirements
+ for special_mod in MODS_WITH_SPECIAL_REQUIREMENTS {
+ if thunderstore_mod_string.contains(special_mod) {
+ return Err(format!(
+ "{} has special install requirements and cannot be installed with FlightCore",
+ thunderstore_mod_string
+ ));
+ }
+ }
+
// Get download URL for the specified mod
let download_url = get_ns_mod_download_url(thunderstore_mod_string).await?;
diff --git a/src-tauri/src/platform_specific/mod.rs b/src-tauri/src/platform_specific/mod.rs
index 6fdb1ed1..4e0514d4 100644
--- a/src-tauri/src/platform_specific/mod.rs
+++ b/src-tauri/src/platform_specific/mod.rs
@@ -38,3 +38,13 @@ pub async fn get_local_northstar_proton_wrapper_version() -> Result<String, Stri
#[cfg(target_os = "windows")]
Err("Not supported on Windows".to_string())
}
+
+/// Check whether the current device might be behind a CGNAT
+#[tauri::command]
+pub async fn check_cgnat() -> Result<String, String> {
+ #[cfg(target_os = "linux")]
+ return Err("Not supported on Linux".to_string());
+
+ #[cfg(target_os = "windows")]
+ windows::check_cgnat().await
+}
diff --git a/src-tauri/src/platform_specific/windows.rs b/src-tauri/src/platform_specific/windows.rs
index 678e5be5..fc6aab5d 100644
--- a/src-tauri/src/platform_specific/windows.rs
+++ b/src-tauri/src/platform_specific/windows.rs
@@ -1,5 +1,6 @@
/// Windows specific code
use anyhow::{anyhow, Result};
+use std::net::Ipv4Addr;
#[cfg(target_os = "windows")]
use winreg::{enums::HKEY_LOCAL_MACHINE, RegKey};
@@ -32,3 +33,72 @@ pub fn origin_install_location_detection() -> Result<String, anyhow::Error> {
Err(anyhow!("No Origin / EA App install path found"))
}
+
+/// Check whether the current device might be behind a CGNAT
+pub async fn check_cgnat() -> Result<String, String> {
+ // Use external service to grap IP
+ let url = "https://api.ipify.org";
+ let response = reqwest::get(url).await.unwrap().text().await.unwrap();
+
+ // Check if valid IPv4 address and return early if not
+ if response.parse::<Ipv4Addr>().is_err() {
+ return Err(format!("Not valid IPv4 address: {}", response));
+ }
+
+ let hops_count = run_tracert(&response)?;
+ Ok(format!("Counted {} hops to {}", hops_count, response))
+}
+
+/// Count number of hops in tracert output
+fn count_hops(output: &str) -> usize {
+ // Split the output into lines
+ let lines: Vec<&str> = output.lines().collect();
+
+ // Filter lines that appear to represent hops
+ let hop_lines: Vec<&str> = lines
+ .iter()
+ .filter(|&line| line.contains("ms") || line.contains("*")) // TODO check if it contains just the `ms` surrounded by whitespace, otherwise it might falsely pick up some domain names as well
+ .cloned()
+ .collect();
+
+ // Return the number of hops
+ hop_lines.len()
+}
+
+/// Run `tracert`
+fn run_tracert(target_ip: &str) -> Result<usize, String> {
+ // Ensure valid IPv4 address to avoid prevent command injection
+ assert!(target_ip.parse::<Ipv4Addr>().is_ok());
+
+ // Execute the `tracert` command
+ let output = match std::process::Command::new("tracert")
+ .arg("-4") // Force IPv4
+ .arg("-d") // Prevent resolving intermediate IP addresses
+ .arg("-w") // Set timeout to 1 second
+ .arg("1000")
+ .arg("-h") // Set max hop count
+ .arg("5")
+ .arg(target_ip)
+ .output()
+ {
+ Ok(res) => res,
+ Err(err) => return Err(format!("Failed running tracert: {}", err)),
+ };
+
+ // Check if the command was successful
+ if output.status.success() {
+ // Convert the output to a string
+ let stdout =
+ std::str::from_utf8(&output.stdout).expect("Invalid UTF-8 sequence in command output");
+ println!("{}", stdout);
+
+ // Count the number of hops
+ let hop_count = count_hops(stdout);
+ Ok(hop_count)
+ } else {
+ let stderr = std::str::from_utf8(&output.stderr)
+ .expect("Invalid UTF-8 sequence in command error output");
+ println!("{}", stderr);
+ Err(format!("Failed collecting tracert output: {}", stderr))
+ }
+}
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 63721461..182c907d 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -8,7 +8,7 @@
},
"package": {
"productName": "FlightCore",
- "version": "2.23.2"
+ "version": "2.24.0"
},
"tauri": {
"allowlist": {
diff --git a/src-vue/src/views/DeveloperView.vue b/src-vue/src/views/DeveloperView.vue
index a08c73f3..19214157 100644
--- a/src-vue/src/views/DeveloperView.vue
+++ b/src-vue/src/views/DeveloperView.vue
@@ -65,6 +65,9 @@
<h3>Repair:</h3>
+ <el-button type="primary" @click="checkCgnat">
+ Run tracert and collect hop count
+ </el-button>
<el-button type="primary" @click="getInstalledMods">
Get installed mods
@@ -330,6 +333,15 @@ export default defineComponent({
.then((message) => { showNotification(`NSProton Version`, message as string); })
.catch((error) => { showNotification(`Error`, error, "error"); })
},
+ async checkCgnat() {
+ await invoke<string>("check_cgnat")
+ .then((message) => {
+ showNotification(message);
+ })
+ .catch((error) => {
+ showErrorNotification(error);
+ });
+ },
async copyReleaseNotesToClipboard() {
navigator.clipboard.writeText(this.release_notes_text)
.then(() => {