cli: prompt for missing CurseForge credentials on add
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: Id0bbdc9ed62bc8b9582ccb89158e53786a6a6964
This commit is contained in:
parent
d2d6b7c421
commit
e7c6da593d
2 changed files with 101 additions and 3 deletions
|
|
@ -1,16 +1,99 @@
|
||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, time::Duration};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{MultiError, PakkerError, Result},
|
error::{MultiError, PakkerError, Result},
|
||||||
model::{Config, LockFile, Project, credentials::ResolvedCredentials},
|
http,
|
||||||
|
model::{
|
||||||
|
Config,
|
||||||
|
LockFile,
|
||||||
|
PakkerCredentialsFile,
|
||||||
|
Project,
|
||||||
|
Target,
|
||||||
|
credentials::ResolvedCredentials,
|
||||||
|
set_keyring_secret,
|
||||||
|
},
|
||||||
platform::create_platform,
|
platform::create_platform,
|
||||||
resolver::DependencyResolver,
|
resolver::DependencyResolver,
|
||||||
|
ui_utils::prompt_curseforge_api_key,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn get_loaders(lockfile: &LockFile) -> Vec<String> {
|
fn get_loaders(lockfile: &LockFile) -> Vec<String> {
|
||||||
lockfile.loaders.keys().cloned().collect()
|
lockfile.loaders.keys().cloned().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn needs_curseforge(target: Option<&Target>) -> bool {
|
||||||
|
matches!(
|
||||||
|
target,
|
||||||
|
Some(Target::CurseForge) | Some(Target::Multiplatform)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn ensure_curseforge_credentials() -> Result<bool> {
|
||||||
|
let creds = ResolvedCredentials::load();
|
||||||
|
if creds.curseforge_api_key().is_some() {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(key) = prompt_curseforge_api_key(false)? {
|
||||||
|
// Verify the key before saving
|
||||||
|
let client = http::create_http_client();
|
||||||
|
let response = client
|
||||||
|
.get("https://api.curseforge.com/v1/mods/238222")
|
||||||
|
.header("x-api-key", &key)
|
||||||
|
.timeout(Duration::from_secs(10))
|
||||||
|
.send()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match response {
|
||||||
|
Ok(resp) if resp.status().is_success() => {
|
||||||
|
let mut creds_file = PakkerCredentialsFile::load()?;
|
||||||
|
set_keyring_secret("curseforge_api_key", &key)?;
|
||||||
|
creds_file.curseforge_api_key = Some(key.clone());
|
||||||
|
creds_file.save()?;
|
||||||
|
println!("CurseForge API key verified and saved.");
|
||||||
|
Ok(true)
|
||||||
|
},
|
||||||
|
Ok(resp) => {
|
||||||
|
println!(
|
||||||
|
"Warning: CurseForge API key verification failed (HTTP {}).",
|
||||||
|
resp.status()
|
||||||
|
);
|
||||||
|
if crate::ui_utils::prompt_yes_no(
|
||||||
|
"Save this key anyway?",
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
)? {
|
||||||
|
let mut creds_file = PakkerCredentialsFile::load()?;
|
||||||
|
set_keyring_secret("curseforge_api_key", &key)?;
|
||||||
|
creds_file.curseforge_api_key = Some(key);
|
||||||
|
creds_file.save()?;
|
||||||
|
Ok(true)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
println!("Warning: Could not verify CurseForge API key: {e}");
|
||||||
|
if crate::ui_utils::prompt_yes_no(
|
||||||
|
"Save this key anyway?",
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
)? {
|
||||||
|
let mut creds_file = PakkerCredentialsFile::load()?;
|
||||||
|
set_keyring_secret("curseforge_api_key", &key)?;
|
||||||
|
creds_file.curseforge_api_key = Some(key);
|
||||||
|
creds_file.save()?;
|
||||||
|
Ok(true)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_all_platforms()
|
pub fn create_all_platforms()
|
||||||
-> HashMap<String, Box<dyn crate::platform::PlatformClient>> {
|
-> HashMap<String, Box<dyn crate::platform::PlatformClient>> {
|
||||||
let mut platforms = HashMap::new();
|
let mut platforms = HashMap::new();
|
||||||
|
|
@ -166,6 +249,11 @@ pub async fn execute(
|
||||||
|
|
||||||
let mut lockfile = LockFile::load_with_validation(lockfile_dir, false)?;
|
let mut lockfile = LockFile::load_with_validation(lockfile_dir, false)?;
|
||||||
|
|
||||||
|
// Prompt for missing CurseForge credentials when needed
|
||||||
|
if needs_curseforge(lockfile.target.as_ref()) && !skip_prompts {
|
||||||
|
let _ = ensure_curseforge_credentials().await;
|
||||||
|
}
|
||||||
|
|
||||||
// Load config if available
|
// Load config if available
|
||||||
let _config = Config::load(config_dir).ok();
|
let _config = Config::load(config_dir).ok();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
platform::create_platform,
|
platform::create_platform,
|
||||||
resolver::DependencyResolver,
|
resolver::DependencyResolver,
|
||||||
|
ui_utils::prompt_curseforge_api_key,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parse a common project argument (slug or ID with optional file ID)
|
/// Parse a common project argument (slug or ID with optional file ID)
|
||||||
|
|
@ -100,7 +101,16 @@ pub async fn execute(
|
||||||
log::info!("Fetching from CurseForge: {cf_input}");
|
log::info!("Fetching from CurseForge: {cf_input}");
|
||||||
let (input, file_id) = parse_common_arg(&cf_input);
|
let (input, file_id) = parse_common_arg(&cf_input);
|
||||||
|
|
||||||
let cf_api_key = std::env::var("CURSEFORGE_API_KEY").ok();
|
let credentials = ResolvedCredentials::load();
|
||||||
|
let mut cf_api_key = credentials.curseforge_api_key().map(String::from);
|
||||||
|
|
||||||
|
// Prompt for missing CurseForge credentials
|
||||||
|
if cf_api_key.is_none() && !yes {
|
||||||
|
if let Some(key) = prompt_curseforge_api_key(false)? {
|
||||||
|
cf_api_key = Some(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let platform = create_platform("curseforge", cf_api_key)?;
|
let platform = create_platform("curseforge", cf_api_key)?;
|
||||||
|
|
||||||
let mut project = platform
|
let mut project = platform
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue