Skip to content
Closed
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
11 changes: 0 additions & 11 deletions app/src-tauri/Cargo.lock

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

1 change: 0 additions & 1 deletion app/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ tauri-plugin-shell = "2"
tauri-plugin-fs = "2"
tauri-plugin-notification = "2"
tauri-plugin-updater = "2"
keyring = "3"
notify = "6"
dirs = "5"
serde = { version = "1", features = ["derive"] }
Expand Down
1 change: 0 additions & 1 deletion app/src-tauri/src/dataclaw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,6 @@ fn base_env() -> HashMap<String, String> {
"LC_CTYPE",
"USER",
"TMPDIR",
"HF_TOKEN",
"HF_HOME",
"HUGGINGFACE_HUB_CACHE",
] {
Expand Down
52 changes: 12 additions & 40 deletions app/src-tauri/src/hf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,8 @@ use std::{collections::HashMap, fs};
use serde_json::{json, Value};
use tauri::AppHandle;

const SERVICE: &str = "io.dataclaw.app";
const ACCOUNT: &str = "hf_token";
const WHOAMI_URL: &str = "https://huggingface.co/api/whoami-v2";

fn entry() -> Result<keyring::Entry, String> {
keyring::Entry::new(SERVICE, ACCOUNT).map_err(|e| e.to_string())
}

pub fn hf_token_path() -> std::path::PathBuf {
dirs::home_dir()
.expect("home directory is required")
Expand All @@ -19,7 +13,7 @@ pub fn hf_token_path() -> std::path::PathBuf {
.join("token")
}

fn write_mirror(token: &str) -> Result<(), String> {
fn write_token_file(token: &str) -> Result<(), String> {
let path = hf_token_path();
let parent = path
.parent()
Expand All @@ -35,7 +29,7 @@ fn write_mirror(token: &str) -> Result<(), String> {
Ok(())
}

fn read_mirror() -> Option<String> {
fn read_token_file() -> Option<String> {
let token = fs::read_to_string(hf_token_path()).ok()?;
let trimmed = token.trim();
if trimmed.is_empty() {
Expand All @@ -45,54 +39,32 @@ fn read_mirror() -> Option<String> {
}
}

fn delete_mirror() -> Result<(), String> {
fn delete_token_file() -> Result<(), String> {
match fs::remove_file(hf_token_path()) {
Ok(()) => Ok(()),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(()),
Err(e) => Err(e.to_string()),
}
}

fn try_save_keychain(token: &str) {
if let Ok(entry) = entry() {
let _ = entry.set_password(token);
}
}

fn try_load_keychain() -> Option<String> {
entry().ok()?.get_password().ok()
}

fn try_delete_keychain() {
if let Ok(entry) = entry() {
let _ = entry.delete_credential();
}
}

#[tauri::command]
pub fn hf_save_token(token: String) -> Result<(), String> {
let trimmed = token.trim();
if trimmed.is_empty() {
return Err("token is empty".into());
}
write_mirror(trimmed)?;
try_save_keychain(trimmed);
write_token_file(trimmed)?;
Ok(())
}

#[tauri::command]
pub fn hf_load_token() -> Result<Option<String>, String> {
if let Some(token) = read_mirror() {
return Ok(Some(token));
}
Ok(try_load_keychain())
Ok(read_token_file())
}

#[tauri::command]
pub fn hf_delete_token() -> Result<(), String> {
try_delete_keychain();
let _ = delete_mirror();
Ok(())
delete_token_file()
}

pub async fn run_with_token(app: &AppHandle, args: &[&str]) -> Result<Value, String> {
Expand Down Expand Up @@ -148,7 +120,7 @@ pub async fn hf_whoami(_app: AppHandle) -> Result<Value, String> {

#[cfg(test)]
mod tests {
use super::{delete_mirror, hf_token_path, write_mirror};
use super::{delete_token_file, hf_token_path, write_token_file};
use std::{
fs,
sync::Mutex,
Expand Down Expand Up @@ -178,11 +150,11 @@ mod tests {

#[cfg(unix)]
#[test]
fn write_mirror_writes_token_with_chmod_600() {
fn write_token_file_writes_token_with_chmod_600() {
use std::os::unix::fs::PermissionsExt;

with_temp_home(|| {
write_mirror("hf_test").unwrap();
write_token_file("hf_test").unwrap();
let path = hf_token_path();
assert_eq!(fs::read_to_string(&path).unwrap(), "hf_test");
let mode = fs::metadata(path).unwrap().permissions().mode() & 0o777;
Expand All @@ -191,12 +163,12 @@ mod tests {
}

#[test]
fn delete_mirror_removes_file() {
fn delete_token_file_removes_file() {
with_temp_home(|| {
write_mirror("hf_test").unwrap();
write_token_file("hf_test").unwrap();
let path = hf_token_path();
assert!(path.exists());
delete_mirror().unwrap();
delete_token_file().unwrap();
assert!(!path.exists());
});
}
Expand Down
6 changes: 3 additions & 3 deletions app/src/routes/Auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ export default function Auth() {
<div className="card">
<h2>Token</h2>
<p className="muted">
Paste a Hugging Face access token with <strong>write</strong> permission. It is stored in
macOS Keychain and mirrored to <code>~/.cache/huggingface/token</code> (mode 600) so the CLI
and scheduled runs find it. Get a token at{" "}
Paste a Hugging Face access token with <strong>write</strong> permission. It is stored at{" "}
<code>~/.cache/huggingface/token</code> (mode 600) so the CLI and scheduled runs find it.
Get a token at{" "}
<a href="https://huggingface.co/settings/tokens" target="_blank" rel="noreferrer">
huggingface.co/settings/tokens
</a>
Expand Down
2 changes: 1 addition & 1 deletion scripts/build-sidecar.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ mkdir -p app/src-tauri/binaries
cp dist/dataclaw "app/src-tauri/binaries/dataclaw-${TRIPLE}"
codesign --force --sign - "app/src-tauri/binaries/dataclaw-${TRIPLE}"

SIDECAR_PATH="app/src-tauri/binaries/dataclaw-${TRIPLE}" python - <<'PY'
SIDECAR_PATH="app/src-tauri/binaries/dataclaw-${TRIPLE}" "${PYTHON_BIN}" - <<'PY'
import os
import subprocess

Expand Down
Loading