| 125 |
125 |
|
|
| 126 |
126 |
|
// ── API key persistence ──
|
| 127 |
127 |
|
|
| 128 |
|
- |
/// Embedded SyncKit API key, set at build time via SYNCKIT_API_KEY env var.
|
| 129 |
|
- |
const EMBEDDED_API_KEY: Option<&str> = option_env!("SYNCKIT_API_KEY");
|
|
128 |
+ |
/// Bundled synckit.toml, embedded at compile time from the project root.
|
|
129 |
+ |
const SYNCKIT_TOML: &str = include_str!("../../../synckit.toml");
|
|
130 |
+ |
|
|
131 |
+ |
/// Extract the api_key value from the bundled synckit.toml.
|
|
132 |
+ |
fn parse_synckit_toml_key() -> Option<&'static str> {
|
|
133 |
+ |
for line in SYNCKIT_TOML.lines() {
|
|
134 |
+ |
let line = line.trim();
|
|
135 |
+ |
if let Some(rest) = line.strip_prefix("api_key") {
|
|
136 |
+ |
let rest = rest.trim_start();
|
|
137 |
+ |
if let Some(rest) = rest.strip_prefix('=') {
|
|
138 |
+ |
let rest = rest.trim();
|
|
139 |
+ |
let rest = rest.trim_matches('"');
|
|
140 |
+ |
if !rest.is_empty() {
|
|
141 |
+ |
return Some(rest);
|
|
142 |
+ |
}
|
|
143 |
+ |
}
|
|
144 |
+ |
}
|
|
145 |
+ |
}
|
|
146 |
+ |
None
|
|
147 |
+ |
}
|
| 130 |
148 |
|
|
| 131 |
|
- |
/// Load a saved API key from the data directory, falling back to env vars and embedded key.
|
|
149 |
+ |
/// Load a saved API key from the data directory, falling back to env vars and bundled toml.
|
| 132 |
150 |
|
fn load_api_key(data_dir: &Path) -> Option<String> {
|
| 133 |
151 |
|
// Saved key file takes priority
|
| 134 |
152 |
|
let key_path = data_dir.join("sync_api_key");
|
| 146 |
164 |
|
) {
|
| 147 |
165 |
|
return Some(key);
|
| 148 |
166 |
|
}
|
| 149 |
|
- |
// Fall back to embedded key (set at build time)
|
| 150 |
|
- |
EMBEDDED_API_KEY.map(String::from)
|
|
167 |
+ |
// Fall back to bundled synckit.toml
|
|
168 |
+ |
parse_synckit_toml_key().map(String::from)
|
| 151 |
169 |
|
}
|
| 152 |
170 |
|
|
| 153 |
171 |
|
/// Save an API key to the data directory for future launches.
|
| 656 |
674 |
|
}
|
| 657 |
675 |
|
|
| 658 |
676 |
|
#[test]
|
| 659 |
|
- |
fn load_api_key_empty_file_returns_none() {
|
|
677 |
+ |
fn load_api_key_empty_file_falls_back_to_bundled() {
|
| 660 |
678 |
|
let dir = tempfile::tempdir().unwrap();
|
| 661 |
679 |
|
std::fs::write(dir.path().join("sync_api_key"), "").unwrap();
|
| 662 |
|
- |
// Without env vars, empty file → None
|
|
680 |
+ |
// Empty file → falls through to bundled synckit.toml key
|
| 663 |
681 |
|
if std::env::var("AF_SYNC_API_KEY").is_err() {
|
| 664 |
|
- |
assert_eq!(load_api_key(dir.path()), None);
|
|
682 |
+ |
let key = load_api_key(dir.path());
|
|
683 |
+ |
assert_eq!(key, parse_synckit_toml_key().map(String::from));
|
| 665 |
684 |
|
}
|
| 666 |
685 |
|
}
|
| 667 |
686 |
|
|
| 668 |
687 |
|
#[test]
|
| 669 |
|
- |
fn load_api_key_whitespace_only_returns_none() {
|
|
688 |
+ |
fn load_api_key_whitespace_only_falls_back_to_bundled() {
|
| 670 |
689 |
|
let dir = tempfile::tempdir().unwrap();
|
| 671 |
690 |
|
std::fs::write(dir.path().join("sync_api_key"), " \n ").unwrap();
|
| 672 |
691 |
|
if std::env::var("AF_SYNC_API_KEY").is_err() {
|
| 673 |
|
- |
assert_eq!(load_api_key(dir.path()), None);
|
|
692 |
+ |
let key = load_api_key(dir.path());
|
|
693 |
+ |
assert_eq!(key, parse_synckit_toml_key().map(String::from));
|
| 674 |
694 |
|
}
|
| 675 |
695 |
|
}
|
| 676 |
696 |
|
|
| 677 |
697 |
|
#[test]
|
| 678 |
|
- |
fn load_api_key_no_file_returns_none() {
|
|
698 |
+ |
fn load_api_key_no_file_falls_back_to_bundled() {
|
| 679 |
699 |
|
let dir = tempfile::tempdir().unwrap();
|
| 680 |
700 |
|
if std::env::var("AF_SYNC_API_KEY").is_err() {
|
| 681 |
|
- |
assert_eq!(load_api_key(dir.path()), None);
|
|
701 |
+ |
let key = load_api_key(dir.path());
|
|
702 |
+ |
assert_eq!(key, parse_synckit_toml_key().map(String::from));
|
| 682 |
703 |
|
}
|
| 683 |
704 |
|
}
|
| 684 |
705 |
|
|