mirror of
https://gitlab.com/keys.openpgp.org/hagrid.git
synced 2025-10-06 00:23:08 +02:00
db: work on sqlite, make tests pass
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::fs::{create_dir_all, File, OpenOptions};
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::fs::create_dir_all;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use std::time::SystemTime;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use openpgp::policy::StandardPolicy;
|
||||
use types::{Email, Fingerprint, KeyID};
|
||||
use Result;
|
||||
use {Database, Query};
|
||||
@@ -17,11 +16,12 @@ use r2d2_sqlite::rusqlite::params;
|
||||
use r2d2_sqlite::rusqlite::OptionalExtension;
|
||||
use r2d2_sqlite::SqliteConnectionManager;
|
||||
|
||||
use crate::wkd;
|
||||
|
||||
pub const POLICY: StandardPolicy = StandardPolicy::new();
|
||||
|
||||
pub struct Sqlite {
|
||||
pool: r2d2::Pool<SqliteConnectionManager>,
|
||||
|
||||
keys_dir_log: PathBuf,
|
||||
dry_run: bool,
|
||||
}
|
||||
|
||||
impl Sqlite {
|
||||
@@ -75,74 +75,38 @@ impl Sqlite {
|
||||
let keys_dir_log = base_dir.join("log");
|
||||
create_dir_all(&keys_dir_log)?;
|
||||
|
||||
let dry_run = false;
|
||||
|
||||
let pool = Self::build_pool(manager)?;
|
||||
let conn = pool.get()?;
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS certs (
|
||||
fingerprint TEXT NOT NULL PRIMARY KEY,
|
||||
conn.pragma_update(None, "journal_mode", "wal")?;
|
||||
conn.pragma_update(None, "synchronous", "normal")?;
|
||||
conn.pragma_update(None, "user_version", "1")?;
|
||||
conn.execute_batch(
|
||||
"
|
||||
CREATE TABLE IF NOT EXISTS certs (
|
||||
primary_fingerprint TEXT NOT NULL PRIMARY KEY,
|
||||
full TEXT NOT NULL,
|
||||
published TEXT,
|
||||
published_not_armored BLOB
|
||||
)",
|
||||
[],
|
||||
)?;
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS cert_identifiers (
|
||||
published_not_armored BLOB,
|
||||
updated_at TIMESTAMP NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS cert_identifiers (
|
||||
fingerprint TEXT NOT NULL PRIMARY KEY,
|
||||
keyid TEXT NOT NULL,
|
||||
primary_fingerprint TEXT NOT NULL,
|
||||
fingerprint TEXT NOT NULL,
|
||||
keyid TEXT NOT NULL
|
||||
)",
|
||||
[],
|
||||
)?;
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS emails (
|
||||
created_at TIMESTAMP NOT NULL
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS emails (
|
||||
email TEXT NOT NULL PRIMARY KEY,
|
||||
primary_fingerprint TEXT NOT NULL
|
||||
)",
|
||||
[],
|
||||
domain TEXT NOT NULL,
|
||||
wkd_hash TEXT NOT NULL,
|
||||
primary_fingerprint TEXT NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL
|
||||
);
|
||||
",
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
pool,
|
||||
keys_dir_log,
|
||||
dry_run,
|
||||
})
|
||||
}
|
||||
|
||||
fn link_email_vks(&self, email: &Email, fpr: &Fingerprint) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn link_email_wkd(&self, email: &Email, fpr: &Fingerprint) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn unlink_email_vks(&self, email: &Email, fpr: &Fingerprint) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn unlink_email_wkd(&self, email: &Email, fpr: &Fingerprint) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn open_logfile(&self, file_name: &str) -> Result<File> {
|
||||
let file_path = self.keys_dir_log.join(file_name);
|
||||
Ok(OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(file_path)?)
|
||||
}
|
||||
|
||||
fn perform_checks(
|
||||
&self,
|
||||
checks_dir: &Path,
|
||||
tpks: &mut HashMap<Fingerprint, Cert>,
|
||||
check: impl Fn(&Path, &Cert, &Fingerprint) -> Result<()>,
|
||||
) -> Result<()> {
|
||||
// XXX: stub
|
||||
Ok(())
|
||||
Ok(Self { pool })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,6 +115,7 @@ impl Database for Sqlite {
|
||||
type TempCert = Vec<u8>;
|
||||
|
||||
fn lock(&self) -> Result<Self::MutexGuard> {
|
||||
// no need to lock the db. we *should* introduce transactions, though!
|
||||
Ok("locked :)".to_owned())
|
||||
}
|
||||
|
||||
@@ -158,43 +123,43 @@ impl Database for Sqlite {
|
||||
Ok(content.to_vec())
|
||||
}
|
||||
|
||||
fn write_log_append(&self, filename: &str, fpr_primary: &Fingerprint) -> Result<()> {
|
||||
let timestamp = SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
let fingerprint_line = format!("{:010} {}\n", timestamp, fpr_primary.to_string());
|
||||
|
||||
self.open_logfile(filename)?
|
||||
.write_all(fingerprint_line.as_bytes())?;
|
||||
|
||||
fn write_log_append(&self, _filename: &str, _fpr_primary: &Fingerprint) -> Result<()> {
|
||||
// this is done implicitly via created_at in sqlite, no need to do anything here
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn move_tmp_to_full(&self, file: Self::TempCert, fpr: &Fingerprint) -> Result<()> {
|
||||
let conn = self.pool.get()?;
|
||||
let now = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
.as_millis() as u64;
|
||||
let file = String::from_utf8(file)?;
|
||||
conn.execute(
|
||||
"
|
||||
INSERT INTO certs (fingerprint, full)
|
||||
VALUES (?1, ?2)
|
||||
ON CONFLICT(fingerprint) DO UPDATE SET full=excluded.full;
|
||||
INSERT INTO certs (primary_fingerprint, full, created_at, updated_at)
|
||||
VALUES (?1, ?2, ?3, ?3)
|
||||
ON CONFLICT(primary_fingerprint) DO UPDATE SET full=excluded.full, updated_at = excluded.updated_at
|
||||
",
|
||||
params![fpr.to_string(), file],
|
||||
params![fpr.to_string(), file, now],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn move_tmp_to_published(&self, file: Self::TempCert, fpr: &Fingerprint) -> Result<()> {
|
||||
let conn = self.pool.get()?;
|
||||
let now = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
.as_millis() as u64;
|
||||
let file = String::from_utf8(file)?;
|
||||
conn.execute(
|
||||
"
|
||||
UPDATE certs
|
||||
SET published = ?2
|
||||
WHERE fingerprint = ?1
|
||||
SET published = ?2, updated_at = ?3
|
||||
WHERE primary_fingerprint = ?1
|
||||
",
|
||||
params![fpr.to_string(), file],
|
||||
params![fpr.to_string(), file, now],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -205,27 +170,32 @@ impl Database for Sqlite {
|
||||
fpr: &Fingerprint,
|
||||
) -> Result<()> {
|
||||
let conn = self.pool.get()?;
|
||||
let now = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
.as_millis() as u64;
|
||||
conn.execute(
|
||||
"
|
||||
UPDATE certs
|
||||
SET published_not_armored = ?2
|
||||
WHERE fingerprint = ?1
|
||||
SET published_not_armored = ?2, updated_at = ?3
|
||||
WHERE primary_fingerprint = ?1
|
||||
",
|
||||
params![fpr.to_string(), file],
|
||||
params![fpr.to_string(), file, now],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_to_quarantine(&self, fpr: &Fingerprint, content: &[u8]) -> Result<()> {
|
||||
fn write_to_quarantine(&self, _fpr: &Fingerprint, _content: &[u8]) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_link_fpr(
|
||||
&self,
|
||||
fpr: &Fingerprint,
|
||||
fpr_target: &Fingerprint,
|
||||
_fpr_target: &Fingerprint,
|
||||
) -> Result<Option<Fingerprint>> {
|
||||
Ok(None)
|
||||
// a desync here cannot happen structurally, so always return true here
|
||||
Ok(Some(fpr.clone()))
|
||||
}
|
||||
|
||||
fn lookup_primary_fingerprint(&self, term: &Query) -> Option<Fingerprint> {
|
||||
@@ -269,14 +239,18 @@ impl Database for Sqlite {
|
||||
|
||||
fn link_email(&self, email: &Email, fpr: &Fingerprint) -> Result<()> {
|
||||
let conn = self.pool.get()?;
|
||||
let now = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
.as_millis() as u64;
|
||||
let (domain, wkd_hash) = wkd::encode_wkd(email.as_str()).expect("email must be vaild");
|
||||
conn.execute(
|
||||
"
|
||||
INSERT INTO emails (email, primary_fingerprint)
|
||||
VALUES (?1, ?2)
|
||||
ON CONFLICT(email) DO UPDATE
|
||||
SET email=excluded.email, primary_fingerprint=excluded.primary_fingerprint
|
||||
INSERT INTO emails (email, wkd_hash, domain, primary_fingerprint, created_at)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5)
|
||||
ON CONFLICT(email) DO UPDATE SET primary_fingerprint = excluded.primary_fingerprint
|
||||
",
|
||||
params![email.to_string(), fpr.to_string(),],
|
||||
params![email.to_string(), domain, wkd_hash, fpr.to_string(), now],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -290,23 +264,28 @@ impl Database for Sqlite {
|
||||
AND primary_fingerprint = ?2
|
||||
",
|
||||
params![email.to_string(), fpr.to_string(),],
|
||||
)?;
|
||||
)
|
||||
.unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn link_fpr(&self, from: &Fingerprint, primary_fpr: &Fingerprint) -> Result<()> {
|
||||
let conn = self.pool.get()?;
|
||||
let now = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
.as_millis() as u64;
|
||||
conn.execute(
|
||||
"
|
||||
INSERT INTO cert_identifiers (primary_fingerprint, fingerprint, keyid)
|
||||
VALUES (?1, ?2, ?3)
|
||||
ON CONFLICT(primary_fingerprint) DO UPDATE
|
||||
SET fingerprint=excluded.fingerprint, keyid=excluded.keyid;
|
||||
INSERT INTO cert_identifiers (fingerprint, keyid, primary_fingerprint, created_at)
|
||||
VALUES (?1, ?2, ?3, ?4)
|
||||
ON CONFLICT(fingerprint) DO UPDATE SET primary_fingerprint = excluded.primary_fingerprint;
|
||||
",
|
||||
params![
|
||||
primary_fpr.to_string(),
|
||||
from.to_string(),
|
||||
KeyID::try_from(from)?.to_string()
|
||||
KeyID::try_from(from)?.to_string(),
|
||||
primary_fpr.to_string(),
|
||||
now,
|
||||
],
|
||||
)?;
|
||||
Ok(())
|
||||
@@ -330,7 +309,6 @@ impl Database for Sqlite {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// XXX: slow
|
||||
// Lookup straight from certs table, no link resolution
|
||||
fn by_fpr_full(&self, fpr: &Fingerprint) -> Option<String> {
|
||||
let conn = self.pool.get().unwrap();
|
||||
@@ -339,7 +317,7 @@ impl Database for Sqlite {
|
||||
"
|
||||
SELECT full
|
||||
FROM certs
|
||||
WHERE fingerprint = ?1
|
||||
WHERE primary_fingerprint = ?1
|
||||
",
|
||||
[fpr.to_string()],
|
||||
|row| row.get(0),
|
||||
@@ -353,22 +331,21 @@ impl Database for Sqlite {
|
||||
// Lookup the published cert straight from certs table, no link resolution
|
||||
fn by_primary_fpr(&self, fpr: &Fingerprint) -> Option<String> {
|
||||
let conn = self.pool.get().unwrap();
|
||||
let armored_cert: Option<String> = conn
|
||||
let armored_cert: Option<Option<String>> = conn
|
||||
.query_row(
|
||||
"
|
||||
SELECT published
|
||||
FROM certs
|
||||
WHERE fingerprint = ?1
|
||||
WHERE primary_fingerprint = ?1
|
||||
",
|
||||
[fpr.to_string()],
|
||||
|row| row.get(0),
|
||||
)
|
||||
.optional()
|
||||
.unwrap();
|
||||
armored_cert
|
||||
armored_cert.flatten()
|
||||
}
|
||||
|
||||
// XXX: slow
|
||||
fn by_fpr(&self, fpr: &Fingerprint) -> Option<String> {
|
||||
let conn = self.pool.get().unwrap();
|
||||
let primary_fingerprint: Option<String> = conn
|
||||
@@ -390,7 +367,6 @@ impl Database for Sqlite {
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: slow
|
||||
fn by_email(&self, email: &Email) -> Option<String> {
|
||||
let conn = self.pool.get().unwrap();
|
||||
let primary_fingerprint: Option<String> = conn
|
||||
@@ -412,7 +388,6 @@ impl Database for Sqlite {
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: slow
|
||||
fn by_email_wkd(&self, email: &Email) -> Option<Vec<u8>> {
|
||||
let conn = self.pool.get().unwrap();
|
||||
let primary_fingerprint: Option<String> = conn
|
||||
@@ -432,7 +407,7 @@ impl Database for Sqlite {
|
||||
"
|
||||
SELECT published_not_armored
|
||||
FROM certs
|
||||
WHERE fingerprint = ?1
|
||||
WHERE primary_fingerprint = ?1
|
||||
",
|
||||
[primary_fingerprint],
|
||||
|row| row.get(0),
|
||||
@@ -442,7 +417,6 @@ impl Database for Sqlite {
|
||||
binary_cert
|
||||
}
|
||||
|
||||
// XXX: slow
|
||||
fn by_kid(&self, kid: &KeyID) -> Option<String> {
|
||||
let conn = self.pool.get().unwrap();
|
||||
let primary_fingerprint: Option<String> = conn
|
||||
@@ -464,13 +438,114 @@ impl Database for Sqlite {
|
||||
}
|
||||
}
|
||||
|
||||
fn by_domain_and_hash_wkd(&self, domain: &str, wkd_hash: &str) -> Option<Vec<u8>> {
|
||||
let conn = self.pool.get().unwrap();
|
||||
let primary_fingerprint: Option<String> = conn
|
||||
.query_row(
|
||||
"
|
||||
SELECT primary_fingerprint
|
||||
FROM emails
|
||||
WHERE domain = ?1, wkd_hash = ?2
|
||||
",
|
||||
[domain, wkd_hash],
|
||||
|row| row.get(0),
|
||||
)
|
||||
.optional()
|
||||
.unwrap();
|
||||
let binary_cert: Option<Vec<u8>> = conn
|
||||
.query_row(
|
||||
"
|
||||
SELECT published_not_armored
|
||||
FROM certs
|
||||
WHERE primary_fingerprint = ?1
|
||||
",
|
||||
[primary_fingerprint],
|
||||
|row| row.get(0),
|
||||
)
|
||||
.optional()
|
||||
.unwrap();
|
||||
binary_cert
|
||||
}
|
||||
|
||||
/// Checks the database for consistency.
|
||||
///
|
||||
/// Note that this operation may take a long time, and is
|
||||
/// generally only useful for testing.
|
||||
fn check_consistency(&self) -> Result<()> {
|
||||
let conn = self.pool.get().unwrap();
|
||||
let mut stmt = conn.prepare("SELECT primary_fingerprint, published FROM certs")?;
|
||||
let mut rows = stmt.query([])?;
|
||||
while let Some(row) = rows.next()? {
|
||||
let primary_fpr: Fingerprint = row.get(0)?;
|
||||
let published: String = row.get(1)?;
|
||||
let cert = Cert::from_str(&published).unwrap();
|
||||
|
||||
let mut cert_emails: Vec<Email> = cert
|
||||
.userids()
|
||||
.map(|uid| uid.userid().email2().unwrap())
|
||||
.flatten()
|
||||
.map(|email| Email::from_str(&email))
|
||||
.flatten()
|
||||
.collect();
|
||||
let mut db_emails: Vec<Email> = conn
|
||||
.prepare("SELECT email FROM emails WHERE primary_fingerprint = ?1")?
|
||||
.query_map([primary_fpr.to_string()], |row| row.get::<_, String>(0))
|
||||
.unwrap()
|
||||
.map(|email| Email::from_str(&email.unwrap()))
|
||||
.flatten()
|
||||
.collect();
|
||||
cert_emails.sort();
|
||||
cert_emails.dedup();
|
||||
db_emails.sort();
|
||||
if cert_emails != db_emails {
|
||||
return Err(format_err!(
|
||||
"{:?} does not have correct emails indexed, cert ${:?} db {:?}",
|
||||
primary_fpr,
|
||||
cert_emails,
|
||||
db_emails,
|
||||
));
|
||||
}
|
||||
|
||||
let policy = &POLICY;
|
||||
let mut cert_fprs: Vec<Fingerprint> = cert
|
||||
.keys()
|
||||
.with_policy(policy, None)
|
||||
.for_certification()
|
||||
.for_signing()
|
||||
.map(|amalgamation| amalgamation.key().fingerprint())
|
||||
.map(Fingerprint::try_from)
|
||||
.flatten()
|
||||
.collect();
|
||||
let mut db_fprs: Vec<Fingerprint> = conn
|
||||
.prepare("SELECT fingerprint FROM cert_identifiers WHERE primary_fingerprint = ?1")?
|
||||
.query_map([primary_fpr.to_string()], |row| {
|
||||
row.get::<_, Fingerprint>(0)
|
||||
})
|
||||
.unwrap()
|
||||
.flatten()
|
||||
.collect();
|
||||
cert_fprs.sort();
|
||||
db_fprs.sort();
|
||||
if cert_fprs != db_fprs {
|
||||
return Err(format_err!(
|
||||
"{:?} does not have correct fingerprints indexed, cert ${:?} db {:?}",
|
||||
primary_fpr,
|
||||
cert_fprs,
|
||||
db_fprs,
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_last_log_entry(&self) -> Result<Fingerprint> {
|
||||
let conn = self.pool.get().unwrap();
|
||||
Ok(conn.query_row(
|
||||
"SELECT primary_fingerprint FROM certs ORDER BY updated_at DESC LIMIT 1",
|
||||
[],
|
||||
|row| row.get::<_, Fingerprint>(0),
|
||||
)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -480,18 +555,19 @@ mod tests {
|
||||
use tempfile::TempDir;
|
||||
use test;
|
||||
|
||||
fn open_db() -> (TempDir, Sqlite, PathBuf) {
|
||||
const DATA_1: &str = "data, content doesn't matter";
|
||||
const DATA_2: &str = "other data, content doesn't matter";
|
||||
const FINGERPRINT_1: &str = "D4AB192964F76A7F8F8A9B357BD18320DEADFA11";
|
||||
|
||||
fn open_db() -> (TempDir, Sqlite) {
|
||||
let tmpdir = TempDir::new().unwrap();
|
||||
|
||||
let db = Sqlite::new_file(tmpdir.path()).unwrap();
|
||||
let log_path = db.keys_dir_log.join(db.get_current_log_filename());
|
||||
|
||||
(tmpdir, db, log_path)
|
||||
(tmpdir, db)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new() {
|
||||
let (_tmp_dir, db, _log_path) = open_db();
|
||||
let (_tmp_dir, db) = open_db();
|
||||
let k1 = CertBuilder::new()
|
||||
.add_userid("a@invalid.example.org")
|
||||
.generate()
|
||||
@@ -537,114 +613,151 @@ mod tests {
|
||||
assert!(!db.merge(k3).unwrap().into_tpk_status().email_status.len() > 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn xx_by_fpr_full() -> Result<()> {
|
||||
let (_tmp_dir, db) = open_db();
|
||||
let fpr1 = Fingerprint::from_str(FINGERPRINT_1)?;
|
||||
|
||||
db.move_tmp_to_full(db.write_to_temp(DATA_1.as_bytes())?, &fpr1)?;
|
||||
db.link_fpr(&fpr1, &fpr1)?;
|
||||
|
||||
assert_eq!(db.by_fpr_full(&fpr1).expect("must find key"), DATA_1);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn xx_by_kid() -> Result<()> {
|
||||
let (_tmp_dir, db) = open_db();
|
||||
let fpr1 = Fingerprint::from_str(FINGERPRINT_1)?;
|
||||
|
||||
db.move_tmp_to_full(db.write_to_temp(DATA_1.as_bytes())?, &fpr1)?;
|
||||
db.move_tmp_to_published(db.write_to_temp(DATA_2.as_bytes())?, &fpr1)?;
|
||||
db.link_fpr(&fpr1, &fpr1)?;
|
||||
|
||||
assert_eq!(db.by_kid(&fpr1.into()).expect("must find key"), DATA_2);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn xx_by_primary_fpr() -> Result<()> {
|
||||
let (_tmp_dir, db) = open_db();
|
||||
let fpr1 = Fingerprint::from_str(FINGERPRINT_1)?;
|
||||
|
||||
db.move_tmp_to_full(db.write_to_temp(DATA_1.as_bytes())?, &fpr1)?;
|
||||
db.move_tmp_to_published(db.write_to_temp(DATA_2.as_bytes())?, &fpr1)?;
|
||||
|
||||
assert_eq!(db.by_primary_fpr(&fpr1).expect("must find key"), DATA_2);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uid_verification() {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::test_uid_verification(&mut db);
|
||||
db.check_consistency().expect("inconsistent database");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uid_deletion() {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::test_uid_deletion(&mut db);
|
||||
db.check_consistency().expect("inconsistent database");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subkey_lookup() {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::test_subkey_lookup(&mut db);
|
||||
db.check_consistency().expect("inconsistent database");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kid_lookup() {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::test_kid_lookup(&mut db);
|
||||
db.check_consistency().expect("inconsistent database");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn upload_revoked_tpk() {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::test_upload_revoked_tpk(&mut db);
|
||||
db.check_consistency().expect("inconsistent database");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uid_revocation() {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::test_uid_revocation(&mut db);
|
||||
db.check_consistency().expect("inconsistent database");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regenerate() {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::test_regenerate(&mut db);
|
||||
db.check_consistency().expect("inconsistent database");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn key_reupload() {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::test_reupload(&mut db);
|
||||
db.check_consistency().expect("inconsistent database");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uid_replacement() {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::test_uid_replacement(&mut db);
|
||||
db.check_consistency().expect("inconsistent database");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uid_unlinking() {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::test_unlink_uid(&mut db);
|
||||
db.check_consistency().expect("inconsistent database");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_email_1() {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::test_same_email_1(&mut db);
|
||||
db.check_consistency().expect("inconsistent database");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_email_2() {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::test_same_email_2(&mut db);
|
||||
db.check_consistency().expect("inconsistent database");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_email_3() {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::test_same_email_3(&mut db);
|
||||
db.check_consistency().expect("inconsistent database");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_email_4() {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::test_same_email_4(&mut db);
|
||||
db.check_consistency().expect("inconsistent database");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_selfsig() {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::test_no_selfsig(&mut db);
|
||||
db.check_consistency().expect("inconsistent database");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_uids() {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::test_bad_uids(&mut db);
|
||||
db.check_consistency().expect("inconsistent database");
|
||||
}
|
||||
@@ -664,7 +777,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn attested_key_signatures() -> Result<()> {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::attested_key_signatures(&mut db)?;
|
||||
db.check_consistency()?;
|
||||
Ok(())
|
||||
@@ -672,7 +785,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn nonexportable_sigs() -> Result<()> {
|
||||
let (_tmp_dir, mut db, log_path) = open_db();
|
||||
let (_tmp_dir, mut db) = open_db();
|
||||
test::nonexportable_sigs(&mut db)?;
|
||||
db.check_consistency()?;
|
||||
Ok(())
|
||||
|
@@ -314,17 +314,17 @@ pub fn test_regenerate(db: &mut impl Database) {
|
||||
db.unlink_email(&email1, &fpr).unwrap();
|
||||
assert!(db.check_consistency().is_err());
|
||||
db.regenerate_links(&fpr).unwrap();
|
||||
assert!(db.check_consistency().is_ok());
|
||||
db.check_consistency().expect("consistency must return Ok");
|
||||
|
||||
db.unlink_fpr(&fpr, &fpr).unwrap();
|
||||
assert!(db.check_consistency().is_err());
|
||||
db.regenerate_links(&fpr).unwrap();
|
||||
assert!(db.check_consistency().is_ok());
|
||||
db.check_consistency().expect("consistency must return Ok");
|
||||
|
||||
db.unlink_fpr(&fpr_sign, &fpr).unwrap();
|
||||
assert!(db.check_consistency().is_err());
|
||||
db.regenerate_links(&fpr).unwrap();
|
||||
assert!(db.check_consistency().is_ok());
|
||||
db.check_consistency().expect("consistency must return Ok");
|
||||
}
|
||||
|
||||
pub fn test_reupload(db: &mut impl Database) {
|
||||
|
@@ -5,6 +5,10 @@ use std::str::FromStr;
|
||||
|
||||
use anyhow::Error;
|
||||
use openpgp::packet::UserID;
|
||||
use r2d2_sqlite::rusqlite::types::FromSql;
|
||||
use r2d2_sqlite::rusqlite::types::FromSqlError;
|
||||
use r2d2_sqlite::rusqlite::types::FromSqlResult;
|
||||
use r2d2_sqlite::rusqlite::types::ValueRef;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use Result;
|
||||
|
||||
@@ -77,9 +81,17 @@ impl FromStr for Email {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Fingerprint([u8; 20]);
|
||||
|
||||
impl FromSql for Fingerprint {
|
||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||
value
|
||||
.as_str()
|
||||
.and_then(|s| Self::from_str(s).map_err(|_| FromSqlError::InvalidType))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<sequoia_openpgp::Fingerprint> for Fingerprint {
|
||||
type Error = Error;
|
||||
|
||||
|
@@ -319,7 +319,7 @@ pub fn key_to_response_plain(
|
||||
return MyResponse::not_found_plain(describe_query_error(&i18n, &query));
|
||||
};
|
||||
|
||||
match db.by_fpr(&fp) {
|
||||
match db.by_primary_fpr(&fp) {
|
||||
Some(armored) => MyResponse::key(armored, &fp),
|
||||
None => MyResponse::not_found_plain(describe_query_error(&i18n, &query)),
|
||||
}
|
||||
|
Reference in New Issue
Block a user