keystore fix + looser vw timings.
This commit is contained in:
+1
-1
@@ -39,4 +39,4 @@ Supported; 3 bursts, 10 s inter-burst gap; preamble, sync, encrypted payload + C
|
|||||||
|
|
||||||
## Keystore
|
## Keystore
|
||||||
|
|
||||||
Requires KIA manufacturer key (keystore type 10, `kia_mf_key`). Loaded from embedded blob or keystore.ini.
|
Requires KIA manufacturer key (keystore type 10, `kia_mf_key`). Loaded from the embedded keystore (built from `REFERENCES/mf_keys.txt`).
|
||||||
|
|||||||
+8
-203
@@ -1,9 +1,11 @@
|
|||||||
//! Key management module for protocol encryption/decryption
|
//! Key management module for protocol encryption/decryption
|
||||||
//!
|
//!
|
||||||
|
//! All keys are loaded from the **embedded keystore only** (no keystore.ini or file-based keys).
|
||||||
|
//! The blob is built from the master list `REFERENCES/mf_keys.txt` by
|
||||||
|
//! `scripts/build_keystore_from_mf_keys.py` and embedded in `crate::keystore::embedded`.
|
||||||
|
//!
|
||||||
//! Aligned with ProtoPirate's keys.c (KIA_KEY1..4, get_kia_mf_key, etc.).
|
//! Aligned with ProtoPirate's keys.c (KIA_KEY1..4, get_kia_mf_key, etc.).
|
||||||
//! Keys are loaded from the embedded keystore blob in `crate::keystore` at startup
|
//! At startup `load_keystore_from_embedded()` parses `keystore::embedded::KEYSTORE_BLOB` and populates:
|
||||||
//! via `load_keystore_from_embedded()`, which parses the blob from
|
|
||||||
//! `keystore::embedded::KEYSTORE_BLOB` and populates:
|
|
||||||
//!
|
//!
|
||||||
//! - **KIA**: type 10 → kia_mf_key, 11 → kia_v6_a_key, 12 → kia_v6_b_key, 13 → kia_v5_key
|
//! - **KIA**: type 10 → kia_mf_key, 11 → kia_v6_a_key, 12 → kia_v6_b_key, 13 → kia_v5_key
|
||||||
//! - **Star Line**: type 20 → star_line_mf_key
|
//! - **Star Line**: type 20 → star_line_mf_key
|
||||||
@@ -13,10 +15,8 @@
|
|||||||
//! KIA V5 uses `get_kia_v5_key()`, KIA V6 uses `get_kia_v6_keystore_a()` / `get_kia_v6_keystore_b()`.
|
//! KIA V5 uses `get_kia_v5_key()`, KIA V6 uses `get_kia_v6_keystore_a()` / `get_kia_v6_keystore_b()`.
|
||||||
|
|
||||||
use super::aut64::{self, Aut64Key, AUT64_KEY_STRUCT_PACKED_SIZE};
|
use super::aut64::{self, Aut64Key, AUT64_KEY_STRUCT_PACKED_SIZE};
|
||||||
use configparser::ini::Ini;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::sync::{OnceLock, RwLock};
|
use std::sync::{OnceLock, RwLock};
|
||||||
use tracing::{info, warn, error};
|
use tracing::{error, info};
|
||||||
|
|
||||||
/// Key type identifiers; must match type IDs in `keystore::embedded::KEYSTORE_BLOB`.
|
/// Key type identifiers; must match type IDs in `keystore::embedded::KEYSTORE_BLOB`.
|
||||||
const KIA_KEY1: u32 = 10; // kia_mf_key (KIA V3/V4)
|
const KIA_KEY1: u32 = 10; // kia_mf_key (KIA V3/V4)
|
||||||
@@ -81,7 +81,8 @@ impl KeyStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load VAG AUT64 keys from raw binary data (16 bytes per key; up to MAX_VAG_KEYS)
|
/// Load VAG AUT64 keys from raw binary data (16 bytes per key; up to MAX_VAG_KEYS).
|
||||||
|
/// Used only by the embedded keystore parser.
|
||||||
pub fn load_vag_keys_from_data(&mut self, data: &[u8]) {
|
pub fn load_vag_keys_from_data(&mut self, data: &[u8]) {
|
||||||
if self.vag_keys_loaded {
|
if self.vag_keys_loaded {
|
||||||
return;
|
return;
|
||||||
@@ -103,28 +104,6 @@ impl KeyStore {
|
|||||||
info!("Loaded {} VAG keys", self.vag_keys.len());
|
info!("Loaded {} VAG keys", self.vag_keys.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load VAG AUT64 keys from a file path
|
|
||||||
pub fn load_vag_keys_from_file(&mut self, path: &str) {
|
|
||||||
if self.vag_keys_loaded {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let file_path = Path::new(path);
|
|
||||||
if !file_path.exists() {
|
|
||||||
warn!("VAG key file not found: {}", path);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
match std::fs::read(file_path) {
|
|
||||||
Ok(data) => {
|
|
||||||
self.load_vag_keys_from_data(&data);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
error!("Failed to read VAG key file {}: {}", path, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a VAG AUT64 key by its internal index field
|
/// Get a VAG AUT64 key by its internal index field
|
||||||
pub fn get_vag_key(&self, index: u8) -> Option<&Aut64Key> {
|
pub fn get_vag_key(&self, index: u8) -> Option<&Aut64Key> {
|
||||||
self.vag_keys.iter().find(|k| k.index == index)
|
self.vag_keys.iter().find(|k| k.index == index)
|
||||||
@@ -183,12 +162,6 @@ pub fn load_keys(kia_entries: &[(u32, u64)]) {
|
|||||||
store.load_kia_keys(kia_entries);
|
store.load_kia_keys(kia_entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize VAG keys from file
|
|
||||||
pub fn load_vag_keys(path: &str) {
|
|
||||||
let mut store = get_keystore_mut();
|
|
||||||
store.load_vag_keys_from_file(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Load the global keystore from the embedded blob (src/keystore/embedded.rs).
|
/// Load the global keystore from the embedded blob (src/keystore/embedded.rs).
|
||||||
/// Populates KIA (V3/V4, V5, V6A, V6B), Star Line, and VAG AUT64 keys from the blob.
|
/// Populates KIA (V3/V4, V5, V6A, V6B), Star Line, and VAG AUT64 keys from the blob.
|
||||||
/// VAG raw bytes are 64 bytes = 4 × 16-byte packed keys; each key's `index` is byte 0 (used by VAG lookup).
|
/// VAG raw bytes are 64 bytes = 4 × 16-byte packed keys; each key's `index` is byte 0 (used by VAG lookup).
|
||||||
@@ -209,171 +182,3 @@ pub fn load_keystore_from_embedded() {
|
|||||||
store.vag_keys.len()
|
store.vag_keys.len()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// Keystore file loading from ~/.config/KAT/keystore/
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
/// Parse a hex string (with or without "0x" prefix) into a u64.
|
|
||||||
fn parse_hex_u64(s: &str) -> Option<u64> {
|
|
||||||
let s = s.trim();
|
|
||||||
let s = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")).unwrap_or(s);
|
|
||||||
u64::from_str_radix(s, 16).ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Default keystore.ini template content.
|
|
||||||
/// Written to disk on first run so users know which keys to configure.
|
|
||||||
const DEFAULT_KEYSTORE_INI: &str = r#"; KAT Keystore — Protocol Encryption Keys
|
|
||||||
;
|
|
||||||
; Place your protocol keys here. Key values should be in hexadecimal
|
|
||||||
; with a 0x prefix (e.g. 0x0123456789ABCDEF).
|
|
||||||
;
|
|
||||||
; Keys left at 0x0000000000000000 or omitted are treated as "not loaded"
|
|
||||||
; and the corresponding protocol will decode without decryption
|
|
||||||
; (serial/button still visible, but counter may not validate).
|
|
||||||
;
|
|
||||||
; This file corresponds to protopirate's keystore/encrypted and keystore/vag
|
|
||||||
; assets. Since KAT runs on a PC (not a Flipper), keys must be provided
|
|
||||||
; in plaintext here rather than in the Flipper's encrypted keystore format.
|
|
||||||
|
|
||||||
[kia]
|
|
||||||
; KIA V3/V4: KeeLoq manufacturer key (used for hop-code decryption)
|
|
||||||
mf_key = 0x0000000000000000
|
|
||||||
|
|
||||||
; KIA V5: Custom mixer cipher key
|
|
||||||
v5_key = 0x0000000000000000
|
|
||||||
|
|
||||||
; KIA V6: AES-128 key components (XOR-masked before use)
|
|
||||||
v6_a_key = 0x0000000000000000
|
|
||||||
v6_b_key = 0x0000000000000000
|
|
||||||
|
|
||||||
[star_line]
|
|
||||||
; Star Line: KeeLoq manufacturer key (used for hop-code decryption)
|
|
||||||
mf_key = 0x0000000000000000
|
|
||||||
|
|
||||||
[vag]
|
|
||||||
; VAG: Path to AUT64 binary key file (raw packed keys, 16 bytes each).
|
|
||||||
; Can be absolute or relative to the keystore directory.
|
|
||||||
; Leave empty or commented out if you don't have VAG keys.
|
|
||||||
; keys_file = vag.bin
|
|
||||||
"#;
|
|
||||||
|
|
||||||
/// Write the default keystore.ini template if it doesn't exist yet.
|
|
||||||
pub fn create_default_keystore(keystore_dir: &Path) {
|
|
||||||
let ini_path = keystore_dir.join("keystore.ini");
|
|
||||||
if ini_path.exists() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
match std::fs::write(&ini_path, DEFAULT_KEYSTORE_INI) {
|
|
||||||
Ok(_) => info!("Created default keystore template at {:?}", ini_path),
|
|
||||||
Err(e) => warn!("Could not create default keystore.ini: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Load all keys from the keystore directory.
|
|
||||||
///
|
|
||||||
/// Reads `keystore.ini` from the given directory and populates the global
|
|
||||||
/// [`KeyStore`] with:
|
|
||||||
///
|
|
||||||
/// - KIA V3/V4 manufacturer key (`[kia] mf_key`)
|
|
||||||
/// - KIA V5 mixer key (`[kia] v5_key`)
|
|
||||||
/// - KIA V6 AES keys (`[kia] v6_a_key`, `[kia] v6_b_key`)
|
|
||||||
/// - Star Line manufacturer key (`[star_line] mf_key`)
|
|
||||||
/// - VAG AUT64 keys from binary file (`[vag] keys_file`)
|
|
||||||
///
|
|
||||||
/// Keys that are missing, zeroed, or unparseable are silently skipped.
|
|
||||||
pub fn load_keystore_from_dir(keystore_dir: &Path) {
|
|
||||||
let ini_path = keystore_dir.join("keystore.ini");
|
|
||||||
|
|
||||||
if !ini_path.exists() {
|
|
||||||
info!("No keystore.ini found at {:?} — keys not loaded", ini_path);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut ini = Ini::new();
|
|
||||||
if let Err(e) = ini.load(ini_path.to_string_lossy().as_ref()) {
|
|
||||||
error!("Failed to parse keystore.ini: {}", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut store = get_keystore_mut();
|
|
||||||
let mut loaded_count = 0u32;
|
|
||||||
|
|
||||||
// ── KIA keys ──────────────────────────────────────────────────────────
|
|
||||||
if let Some(val) = ini.get("kia", "mf_key").and_then(|s| parse_hex_u64(&s)) {
|
|
||||||
if val != 0 {
|
|
||||||
store.kia_mf_key = val;
|
|
||||||
loaded_count += 1;
|
|
||||||
info!("Loaded KIA V3/V4 manufacturer key");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(val) = ini.get("kia", "v5_key").and_then(|s| parse_hex_u64(&s)) {
|
|
||||||
if val != 0 {
|
|
||||||
store.kia_v5_key = val;
|
|
||||||
loaded_count += 1;
|
|
||||||
info!("Loaded KIA V5 mixer key");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(val) = ini.get("kia", "v6_a_key").and_then(|s| parse_hex_u64(&s)) {
|
|
||||||
if val != 0 {
|
|
||||||
store.kia_v6_a_key = val;
|
|
||||||
loaded_count += 1;
|
|
||||||
info!("Loaded KIA V6 AES key A");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(val) = ini.get("kia", "v6_b_key").and_then(|s| parse_hex_u64(&s)) {
|
|
||||||
if val != 0 {
|
|
||||||
store.kia_v6_b_key = val;
|
|
||||||
loaded_count += 1;
|
|
||||||
info!("Loaded KIA V6 AES key B");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Star Line keys ────────────────────────────────────────────────────
|
|
||||||
if let Some(val) = ini.get("star_line", "mf_key").and_then(|s| parse_hex_u64(&s)) {
|
|
||||||
if val != 0 {
|
|
||||||
store.star_line_mf_key = val;
|
|
||||||
loaded_count += 1;
|
|
||||||
info!("Loaded Star Line manufacturer key");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── VAG AUT64 keys (binary file) ──────────────────────────────────────
|
|
||||||
if let Some(vag_file) = ini.get("vag", "keys_file") {
|
|
||||||
let vag_file = vag_file.trim().to_string();
|
|
||||||
if !vag_file.is_empty() {
|
|
||||||
let vag_path = if Path::new(&vag_file).is_absolute() {
|
|
||||||
std::path::PathBuf::from(&vag_file)
|
|
||||||
} else {
|
|
||||||
keystore_dir.join(&vag_file)
|
|
||||||
};
|
|
||||||
|
|
||||||
if vag_path.exists() {
|
|
||||||
match std::fs::read(&vag_path) {
|
|
||||||
Ok(data) => {
|
|
||||||
store.load_vag_keys_from_data(&data);
|
|
||||||
if store.vag_keys_loaded {
|
|
||||||
loaded_count += store.vag_keys.len() as u32;
|
|
||||||
info!("Loaded {} VAG AUT64 keys from {:?}", store.vag_keys.len(), vag_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
error!("Failed to read VAG key file {:?}: {}", vag_path, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
warn!("VAG key file not found: {:?}", vag_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if loaded_count > 0 {
|
|
||||||
info!("Keystore loaded: {} key(s) from {:?}", loaded_count, keystore_dir);
|
|
||||||
} else {
|
|
||||||
info!("Keystore loaded but no non-zero keys found. Edit keystore.ini to add your keys.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+14
-15
@@ -5,10 +5,9 @@
|
|||||||
//! parse (vag_parse_data, vag_aut64_decrypt, vag_tea_decrypt), dispatch (0x2A/0x1C/0x46 and
|
//! parse (vag_parse_data, vag_aut64_decrypt, vag_tea_decrypt), dispatch (0x2A/0x1C/0x46 and
|
||||||
//! 0x2B/0x1D/0x47), and encoder (vag_encoder_build_type1/2/3_4) match the reference.
|
//! 0x2B/0x1D/0x47), and encoder (vag_encoder_build_type1/2/3_4) match the reference.
|
||||||
//!
|
//!
|
||||||
//! **Timing**: Reference uses VAG_TOL_300 (79) and VAG_TOL_500 (120). Reset/Preamble1 use 300±79/80;
|
//! **Timing**: Slightly looser than reference for real-world decode rate. Reference uses 79/80/120;
|
||||||
//! Preamble1→Data1 gap 600µs ±79; Data1 short 300±79/80, long 600±79/80; end-of-data gap 6000µs
|
//! we use 90 for reset/preamble/sync and 130 for Data2. Reset/Preamble1 300±90; gap 600±90;
|
||||||
//! (accept diff < 4000). Preamble2 count 500±80; Sync2A 500/1000µs ±79; Sync2B 750µs ±79;
|
//! Data1 short 300±90, long 600±90; Preamble2 500±90; Sync2 500/1000/750±90; Data2 500±130, 1000±130.
|
||||||
//! Sync2C 750µs ±79; Data2 short 500±120 (380–620µs), long 1000±120 (880–1120µs).
|
|
||||||
//!
|
//!
|
||||||
//! **Protocol**: Manchester, 80 bits (key1 64 + key2 16). Type 1/2: 300/600µs, prefix 0xAF3F/0xAF1C.
|
//! **Protocol**: Manchester, 80 bits (key1 64 + key2 16). Type 1/2: 300/600µs, prefix 0xAF3F/0xAF1C.
|
||||||
//! Type 3/4: 500µs, 45 preamble pairs, sync 1000+500 then 3×750µs; key1/key2 not inverted.
|
//! Type 3/4: 500µs, 45 preamble pairs, sync 1000+500 then 3×750µs; key1/key2 not inverted.
|
||||||
@@ -23,21 +22,21 @@ use crate::radio::demodulator::LevelDuration;
|
|||||||
const TE_SHORT: u32 = 500;
|
const TE_SHORT: u32 = 500;
|
||||||
const TE_LONG: u32 = 1000;
|
const TE_LONG: u32 = 1000;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
const TE_DELTA: u32 = 80; // ref vag.c (Type 3/4); exposed via timing()
|
const TE_DELTA: u32 = 100; // Type 3/4 tolerance; exposed via timing()
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
const MIN_COUNT_BIT: usize = 80;
|
const MIN_COUNT_BIT: usize = 80;
|
||||||
|
|
||||||
// Type 1/2 timing
|
// Type 1/2 timing
|
||||||
const TE_SHORT_12: u32 = 300;
|
const TE_SHORT_12: u32 = 300;
|
||||||
const TE_LONG_12: u32 = 600;
|
const TE_LONG_12: u32 = 600;
|
||||||
const TE_DELTA_12: u32 = 80; // Preamble1/Data1 (ref vag.c 79/80)
|
const TE_DELTA_12: u32 = 100; // Preamble1/Data1 (looser for real-world captures)
|
||||||
|
|
||||||
// Reference-aligned deltas (vag.c VAG_NEAR / VAG_TOL_300 79, VAG_TOL_500 120)
|
// Looser than reference for better decode rate on real hardware
|
||||||
const REF_RESET_DELTA: u32 = 79; // Reset: 300±79, 500±79 for Preamble2
|
const REF_RESET_DELTA: u32 = 100; // Reset: 300±100, 500±100 for Preamble2
|
||||||
const REF_PREAMBLE_SYNC: u32 = 80; // Preamble2 counting: 500±80
|
const REF_PREAMBLE_SYNC: u32 = 100; // Preamble2 counting: 500±100
|
||||||
const REF_SYNC2_AB_DELTA: u32 = 79; // Sync2A/Sync2B: 500/1000/750±79 (ref VAG_NEAR(..., 79))
|
const REF_SYNC2_AB_DELTA: u32 = 100; // Sync2A/Sync2B: 500/1000/750±100
|
||||||
const REF_SYNC2C_DELTA: u32 = 79; // Sync2C: 750±79
|
const REF_SYNC2C_DELTA: u32 = 100; // Sync2C: 750±100
|
||||||
const REF_GAP1_DELTA: u32 = 79; // Preamble1→Data1 gap 600µs ±79 (ref check_gap1)
|
const REF_GAP1_DELTA: u32 = 100; // Preamble1→Data1 gap 600µs ±100
|
||||||
|
|
||||||
// TEA constants
|
// TEA constants
|
||||||
const TEA_DELTA: u32 = 0x9E3779B9;
|
const TEA_DELTA: u32 = 0x9E3779B9;
|
||||||
@@ -1143,10 +1142,10 @@ impl ProtocolDecoder for VagDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DecoderStep::Data2 => {
|
DecoderStep::Data2 => {
|
||||||
// Matches vag.c: short 380-620µs, long 880-1120µs
|
// Data2: short 500±140µs, long 1000±140µs
|
||||||
let event = if duration >= 380 && duration <= 620 {
|
let event = if duration >= 360 && duration <= 640 {
|
||||||
Some(if level { ManchesterEvent::ShortLow } else { ManchesterEvent::ShortHigh })
|
Some(if level { ManchesterEvent::ShortLow } else { ManchesterEvent::ShortHigh })
|
||||||
} else if duration >= 880 && duration <= 1120 {
|
} else if duration >= 860 && duration <= 1140 {
|
||||||
Some(if level { ManchesterEvent::LongLow } else { ManchesterEvent::LongHigh })
|
Some(if level { ManchesterEvent::LongLow } else { ManchesterEvent::LongHigh })
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|||||||
+1
-19
@@ -7,9 +7,6 @@
|
|||||||
//! config.ini — User configuration
|
//! config.ini — User configuration
|
||||||
//! exports/ — Exported .fob / .sub files (save location)
|
//! exports/ — Exported .fob / .sub files (save location)
|
||||||
//! import/ — Scanned at startup for .fob / .sub to import
|
//! import/ — Scanned at startup for .fob / .sub to import
|
||||||
//! keystore/ — Protocol encryption keys
|
|
||||||
//! keystore.ini — Key definitions (hex values)
|
|
||||||
//! vag.bin — VAG AUT64 binary key file (optional)
|
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! Captures are **in-memory only** and are discarded when KAT exits.
|
//! Captures are **in-memory only** and are discarded when KAT exits.
|
||||||
@@ -345,20 +342,10 @@ impl Storage {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── 6. Ensure keystore directory exists ────────────────────────
|
// ── 6. Log resolved paths ───────────────────────────────────────
|
||||||
let keystore_dir = config_dir.join("keystore");
|
|
||||||
if !keystore_dir.exists() {
|
|
||||||
fs::create_dir_all(&keystore_dir).with_context(|| {
|
|
||||||
format!("Failed to create keystore dir: {:?}", keystore_dir)
|
|
||||||
})?;
|
|
||||||
tracing::info!("Created keystore directory: {:?}", keystore_dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── 7. Log resolved paths ───────────────────────────────────────
|
|
||||||
tracing::info!("Config dir: {:?}", config_dir);
|
tracing::info!("Config dir: {:?}", config_dir);
|
||||||
tracing::info!("Export dir: {:?}", config.export_directory);
|
tracing::info!("Export dir: {:?}", config.export_directory);
|
||||||
tracing::info!("Import dir: {:?}", config.import_directory);
|
tracing::info!("Import dir: {:?}", config.import_directory);
|
||||||
tracing::info!("Keystore dir: {:?}", keystore_dir);
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
config_dir,
|
config_dir,
|
||||||
@@ -393,9 +380,4 @@ impl Storage {
|
|||||||
&self.config.import_directory
|
&self.config.import_directory
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the keystore directory path (`~/.config/KAT/keystore`). Kept for optional file-based override.
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn keystore_dir(&self) -> PathBuf {
|
|
||||||
self.config_dir.join("keystore")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user