Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"permissions": {
"allow": [
"Bash(doppler run:*)",
"WebSearch",
"Bash(cargo clean:*)",
"Bash(cargo tree:*)",
"WebFetch(domain:docs.rs)",
"WebFetch(domain:seanmonstar.com)",
"WebFetch(domain:github.com)",
"WebFetch(domain:crates.io)",
"WebFetch(domain:raw.githubusercontent.com)",
"Bash(dir:*)",
"Bash(cargo check:*)",
"Bash(git add:*)",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfix: use ephemeral port for dev server to avoid Hyper-V conflicts\n\nPort 7777 falls within Windows'' excluded port range \\(7747-7846\\) reserved\nby Hyper-V/WSL2/Docker, causing \"os error 10013\" on many Windows machines.\nNow lets the OS pick an available port automatically.\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(grep:*)",
"Bash(agent-browser *)"
]
},
"enabledPlugins": {
"rust-skills@rust-skills": true,
"github@claude-plugins-official": true
}
}
23 changes: 10 additions & 13 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
{
"permissions": {
"allow": [
"Bash(doppler run:*)",
"WebSearch",
"Bash(cargo clean:*)",
"Bash(cargo tree:*)",
"WebFetch(domain:docs.rs)",
"WebFetch(domain:seanmonstar.com)",
"WebFetch(domain:github.com)",
"WebFetch(domain:crates.io)",
"WebFetch(domain:raw.githubusercontent.com)",
"Bash(dir:*)",
"Bash(cargo check:*)",
"Bash(git add:*)",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfix: use ephemeral port for dev server to avoid Hyper-V conflicts\n\nPort 7777 falls within Windows'' excluded port range \\(7747-7846\\) reserved\nby Hyper-V/WSL2/Docker, causing \"os error 10013\" on many Windows machines.\nNow lets the OS pick an available port automatically.\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")"
"Bash(cargo build:*)",
"Bash(./target/debug/wvdsh auth:*)",
"Bash(WVDSH_TOKEN=test-token-12345678 ./target/debug/wvdsh auth status:*)",
"WebFetch(domain:docs.github.com)",
"Bash(gh ruleset list:*)",
"Bash(gh ruleset check:*)",
"Bash(gh api:*)",
"Bash(while read id)",
"Bash(do gh api -X DELETE \"repos/wvdsh/docs/rulesets/$id\")",
"Bash(done)"
]
}
}
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "wvdsh"
version = "0.1.46"
version = "0.1.47"
edition = "2021"
authors = ["Wavedash Team"]
description = "Cross-platform CLI tool for uploading game projects to wavedash.com"
Expand Down
46 changes: 41 additions & 5 deletions src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ struct Credentials {
api_key: String,
}

pub enum AuthSource {
Environment,
File,
None,
}

pub struct AuthInfo {
pub source: AuthSource,
pub api_key: Option<String>,
}

pub struct AuthManager;

impl AuthManager {
Expand Down Expand Up @@ -46,24 +57,49 @@ impl AuthManager {
Ok(())
}

pub fn get_api_key(&self) -> Option<String> {
fn read_file_credentials(&self) -> Option<String> {
let path = config::credentials_path().ok()?;
let json = fs::read_to_string(&path).ok()?;
let credentials: Credentials = serde_json::from_str(&json).ok()?;
Some(credentials.api_key)
}

pub fn get_auth_info(&self) -> AuthInfo {
// Check environment first
if let Ok(api_key) = std::env::var("WVDSH_TOKEN") {
if !api_key.is_empty() {
return AuthInfo {
source: AuthSource::Environment,
api_key: Some(api_key),
};
}
}

// Check file
if let Some(api_key) = self.read_file_credentials() {
return AuthInfo {
source: AuthSource::File,
api_key: Some(api_key),
};
}

AuthInfo {
source: AuthSource::None,
api_key: None,
}
}

pub fn get_api_key(&self) -> Option<String> {
self.get_auth_info().api_key
}

pub fn clear_credentials(&self) -> Result<()> {
let path = config::credentials_path()?;
if path.exists() {
fs::remove_file(&path)?;
}
Ok(())
}

pub fn is_authenticated(&self) -> bool {
self.get_api_key().is_some()
}
}

fn find_available_port() -> Result<u16> {
Expand Down
19 changes: 7 additions & 12 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
use anyhow::Result;
use directories::ProjectDirs;
use directories::BaseDirs;
use serde::Deserialize;
use std::path::PathBuf;

// Standard project directories configuration
pub const PROJECT_QUALIFIER: &str = "gg";
pub const PROJECT_ORGANIZATION: &str = "wavedash";
pub const PROJECT_APPLICATION: &str = "cli";

/// Get the project directories for this application
pub fn project_dirs() -> Result<ProjectDirs> {
ProjectDirs::from(PROJECT_QUALIFIER, PROJECT_ORGANIZATION, PROJECT_APPLICATION)
.ok_or_else(|| anyhow::anyhow!("Could not determine project directories"))
/// Get the wvdsh config directory (~/.wvdsh)
pub fn wvdsh_dir() -> Result<PathBuf> {
let base_dirs = BaseDirs::new()
.ok_or_else(|| anyhow::anyhow!("Could not determine home directory"))?;
Ok(base_dirs.home_dir().join(".wvdsh"))
}

#[derive(Deserialize)]
Expand Down Expand Up @@ -52,8 +48,7 @@ pub fn get(key: &str) -> Result<String> {

/// Get the path to the credentials file
pub fn credentials_path() -> Result<PathBuf> {
let dirs = project_dirs()?;
Ok(dirs.config_dir().join("credentials.json"))
Ok(wvdsh_dir()?.join("credentials.json"))
}

/// Create an HTTP client configured with Cloudflare Access headers if needed
Expand Down
3 changes: 1 addition & 2 deletions src/dev/cert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ const DEV_CERT_COMMON_NAME: &str = "wvdsh dev server";
const LINUX_CERT_INSTALL_PATH: &str = "/usr/local/share/ca-certificates/wvdsh-dev.crt";

pub async fn load_or_create_certificates() -> Result<(RustlsConfig, PathBuf, PathBuf)> {
let project_dirs = config::project_dirs()?;
let cert_dir = project_dirs.config_dir().join(DEV_CERT_SUBDIR);
let cert_dir = config::wvdsh_dir()?.join(DEV_CERT_SUBDIR);
fs::create_dir_all(&cert_dir)?;

let cert_path = cert_dir.join(DEV_CERT_NAME);
Expand Down
37 changes: 25 additions & 12 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,20 @@ mod file_staging;
mod updater;

use anyhow::Result;
use auth::{login_with_browser, AuthManager};
use auth::{login_with_browser, AuthManager, AuthSource};
use builds::handle_build_push;
use clap::{Parser, Subcommand};
use dev::handle_dev;
use std::path::PathBuf;

fn mask_token(token: &str) -> String {
if token.len() > 10 {
format!("{}...{}", &token[..6], &token[token.len() - 3..])
} else {
"***".to_string()
}
}

#[derive(Parser)]
#[command(name = "wvdsh")]
#[command(about = "Cross-platform CLI tool for uploading game projects to wavedash.com")]
Expand Down Expand Up @@ -111,18 +119,23 @@ async fn main() -> Result<()> {
println!("✓ Successfully logged out");
}
AuthCommands::Status => {
if auth_manager.is_authenticated() {
println!("✓ Authenticated");
if let Some(api_key) = auth_manager.get_api_key() {
let preview = if api_key.len() > 10 {
format!("{}...{}", &api_key[..6], &api_key[api_key.len() - 3..])
} else {
"***".to_string()
};
println!("API Key: {}", preview);
let auth_info = auth_manager.get_auth_info();
match auth_info.source {
AuthSource::Environment => {
println!("✓ Authenticated (via WVDSH_TOKEN environment variable)");
if let Some(api_key) = auth_info.api_key {
println!("Token: {}", mask_token(&api_key));
}
}
AuthSource::File => {
println!("✓ Authenticated (via stored credentials)");
if let Some(api_key) = auth_info.api_key {
println!("API Key: {}", mask_token(&api_key));
}
}
AuthSource::None => {
println!("Not authenticated. Run 'wvdsh auth login' or set WVDSH_TOKEN environment variable.");
}
} else {
println!("Not authenticated. Run 'wvdsh auth login' to get started.");
}
}
}
Expand Down
5 changes: 2 additions & 3 deletions src/updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ struct UpdateCache {

impl UpdateCache {
fn cache_path() -> Result<PathBuf> {
let project_dirs = config::project_dirs()?;
let cache_dir = project_dirs.config_dir();
fs::create_dir_all(cache_dir)?;
let cache_dir = config::wvdsh_dir()?;
fs::create_dir_all(&cache_dir)?;
Ok(cache_dir.join("update-cache.json"))
}

Expand Down