From 08caddff9be60ecf3aae2bcd990a25e1f80482aa Mon Sep 17 00:00:00 2001 From: Owain Davies <116417456+OTheDev@users.noreply.github.com> Date: Thu, 2 May 2024 13:46:30 +0700 Subject: [PATCH] Add `updated_at` timestamp for password updates (#14) --- src/manager.rs | 13 ++++++++++++- src/manager/tests.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/manager.rs b/src/manager.rs index 6f5965f..fd9f139 100644 --- a/src/manager.rs +++ b/src/manager.rs @@ -75,11 +75,22 @@ impl PwdManager { id TEXT PRIMARY KEY, ciphertext BLOB NOT NULL CHECK(length(ciphertext) > 0), nonce BLOB NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )", [], )?; + tx.execute( + "CREATE TRIGGER update_time + AFTER UPDATE ON passwords + FOR EACH ROW + BEGIN + UPDATE passwords SET updated_at = CURRENT_TIMESTAMP WHERE id = OLD.id; + END;", + [], + )?; + tx.execute( "INSERT INTO metadata (name, value) VALUES (?1, ?2)", params!["signature", Self::SIGNATURE], diff --git a/src/manager/tests.rs b/src/manager/tests.rs index 6d3b1c8..c987531 100644 --- a/src/manager/tests.rs +++ b/src/manager/tests.rs @@ -373,3 +373,49 @@ fn test_signature_not_found_no_metadata_table() { assert!(!PwdManager::found_signature(db_path)); } + +#[test] +fn test_created_at_and_updated_at() { + let (manager, _temp_file) = setup_db(); + + const QUERY: &str = " + SELECT + cast(strftime('%s', created_at) as integer), + cast(strftime('%s', updated_at) as integer) + FROM passwords + WHERE id = ? + "; + let get_times = |id: &str| { + manager + .conn + .query_row(QUERY, rusqlite::params![id], |row| { + Ok((row.get::<_, i64>(0)?, row.get::<_, i64>(1)?)) + }) + .unwrap() + }; + + let id = "test_id"; + let password = "test_password"; + manager.add_password(id, password).unwrap(); + + // Check timestamps on creation + let times_0 = get_times(id); + assert_eq!(times_0.0, times_0.1); + + std::thread::sleep(std::time::Duration::from_secs(2)); + + // Update the password + let new_password = "new_password"; + manager.update_password(id, new_password).unwrap(); + + // Check timestamps on update + let times_1 = get_times(id); + assert!( + times_1.1 > times_1.0, + "updated_at should not be earlier than created_at" + ); + assert!( + times_0.0 == times_1.0, + "created_at should not change after updating" + ); +}