feat(wasm): parse_lastpass_csv_json bridge
Returns { items: [Item], warnings: [ImportWarning] } as a JSON
string. The items already have fresh IDs + timestamps; the SW
caller encrypts and writes them through the existing
item_encrypt + manifest_encrypt bridges.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -432,6 +432,28 @@ pub fn unpack_backup_json(bytes: &[u8], passphrase: &str) -> Result<String, JsEr
|
||||
Ok(json.to_string())
|
||||
}
|
||||
|
||||
// ── LastPass CSV importer bridge ────────────────────────────────────────────
|
||||
|
||||
use relicario_core::import_lastpass::parse_lastpass_csv as core_parse_lastpass_csv;
|
||||
|
||||
/// Parse a LastPass CSV into `{ items: [Item], warnings: [ImportWarning] }`.
|
||||
///
|
||||
/// Items are returned as full `Item` JSON objects with freshly-minted IDs
|
||||
/// and timestamps already populated. The SW caller is responsible for
|
||||
/// encrypting + writing them; this bridge stays pure so the preview UI
|
||||
/// can render counts without committing anything.
|
||||
#[wasm_bindgen]
|
||||
pub fn parse_lastpass_csv_json(csv_bytes: &[u8]) -> Result<String, JsError> {
|
||||
let (items, warnings) = core_parse_lastpass_csv(csv_bytes)
|
||||
.map_err(|e| JsError::new(&e.to_string()))?;
|
||||
|
||||
let json = serde_json::json!({
|
||||
"items": items,
|
||||
"warnings": warnings,
|
||||
});
|
||||
Ok(json.to_string())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod session_tests {
|
||||
use super::*;
|
||||
@@ -474,4 +496,31 @@ mod session_tests {
|
||||
let bytes2 = manifest_encrypt(&handle, &serde_json::to_string(&empty).unwrap()).unwrap();
|
||||
assert_ne!(bytes, bytes2, "nonces must differ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_lastpass_csv_json_returns_items_and_warnings() {
|
||||
// Row 1 imports cleanly; row 2 has an empty `name` and is skipped
|
||||
// with a warning.
|
||||
let csv = "url,username,password,totp,extra,name,grouping,fav\n\
|
||||
https://x,alice,hunter2,,,GitHub,Work,1\n\
|
||||
https://y,bob,hunter2,,,,,";
|
||||
let json = super::parse_lastpass_csv_json(csv.as_bytes()).unwrap();
|
||||
let v: serde_json::Value = serde_json::from_str(&json).unwrap();
|
||||
assert_eq!(v["items"].as_array().unwrap().len(), 1);
|
||||
assert_eq!(v["warnings"].as_array().unwrap().len(), 1);
|
||||
assert!(v["warnings"][0]["message"].as_str().unwrap().contains("name"));
|
||||
// The item's title round-trips as a plain JSON string.
|
||||
assert_eq!(v["items"][0]["title"].as_str().unwrap(), "GitHub");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_lastpass_csv_json_propagates_header_errors() {
|
||||
// Test the underlying core function directly since native tests
|
||||
// can't call wasm_bindgen functions.
|
||||
use relicario_core::import_lastpass::parse_lastpass_csv;
|
||||
let bad = "name,user,pass\nA,u,p\n";
|
||||
let err = parse_lastpass_csv(bad.as_bytes());
|
||||
// Should fail with a header validation error.
|
||||
assert!(err.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user