mirror of
https://gitlab.com/hagrid-keyserver/hagrid.git
synced 2023-02-13 20:55:02 -05:00
freshen up consistency check
This commit is contained in:
parent
a702a16edb
commit
848f03e95c
1 changed files with 109 additions and 147 deletions
|
@ -1,4 +1,5 @@
|
||||||
use std::convert::{TryInto, TryFrom};
|
use std::collections::HashMap;
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::fs::{create_dir_all, read_link, remove_file, rename};
|
use std::fs::{create_dir_all, read_link, remove_file, rename};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
@ -16,6 +17,8 @@ use Result;
|
||||||
|
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
|
|
||||||
|
use openpgp::TPK;
|
||||||
|
|
||||||
pub struct Filesystem {
|
pub struct Filesystem {
|
||||||
update_lock: FlockMutex,
|
update_lock: FlockMutex,
|
||||||
|
|
||||||
|
@ -185,20 +188,117 @@ impl Filesystem {
|
||||||
Email::from_str(&decoded).ok()
|
Email::from_str(&decoded).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the backing primary key fingerprint for any key path.
|
||||||
|
fn path_to_primary(&self, path: &Path) -> Option<Fingerprint> {
|
||||||
|
use std::fs;
|
||||||
|
let typ = fs::symlink_metadata(&path).ok()?.file_type();
|
||||||
|
if typ.is_symlink() {
|
||||||
|
let path = read_link(path).ok()?;
|
||||||
|
self.path_to_fingerprint(&path)
|
||||||
|
} else {
|
||||||
|
self.path_to_fingerprint(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks the database for consistency.
|
/// Checks the database for consistency.
|
||||||
///
|
///
|
||||||
/// Note that this operation may take a long time, and is
|
/// Note that this operation may take a long time, and is
|
||||||
/// generally only useful for testing.
|
/// generally only useful for testing.
|
||||||
pub fn check_consistency(&self) -> Result<()> {
|
pub fn check_consistency(&self) -> Result<()> {
|
||||||
use std::fs;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use failure::format_err;
|
use failure::format_err;
|
||||||
use walkdir::WalkDir;
|
|
||||||
|
|
||||||
// A cache of all TPKs, for quick lookups.
|
// A cache of all TPKs, for quick lookups.
|
||||||
let mut tpks = HashMap::new();
|
let mut tpks = HashMap::new();
|
||||||
|
|
||||||
for entry in WalkDir::new(&self.keys_dir_published) {
|
self.perform_checks(&self.keys_dir_published, &mut tpks,
|
||||||
|
|path, _, primary_fp| {
|
||||||
|
// The KeyID corresponding with this path.
|
||||||
|
let fp = self.path_to_fingerprint(&path)
|
||||||
|
.ok_or_else(|| format_err!("Malformed path: {:?}", path))?;
|
||||||
|
|
||||||
|
if fp != *primary_fp {
|
||||||
|
return Err(format_err!(
|
||||||
|
"{:?} points to the wrong TPK, expected {} \
|
||||||
|
but found {}",
|
||||||
|
path, fp, primary_fp));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
)?;
|
||||||
|
|
||||||
|
self.perform_checks(&self.links_dir_by_fingerprint, &mut tpks,
|
||||||
|
|path, tpk, _| {
|
||||||
|
// The KeyID corresponding with this path.
|
||||||
|
let id = self.path_to_keyid(&path)
|
||||||
|
.ok_or_else(|| format_err!("Malformed path: {:?}", path))?;
|
||||||
|
|
||||||
|
let found = tpk.keys_all()
|
||||||
|
.map(|(_, _, key)| KeyID::try_from(key.fingerprint()).unwrap())
|
||||||
|
.any(|key_fp| key_fp == id);
|
||||||
|
if ! found {
|
||||||
|
return Err(format_err!(
|
||||||
|
"{:?} points to the wrong TPK, the TPK does not \
|
||||||
|
contain the (sub)key {}", path, id));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
)?;
|
||||||
|
|
||||||
|
self.perform_checks(&self.links_dir_by_keyid, &mut tpks,
|
||||||
|
|path, tpk, _| {
|
||||||
|
// The KeyID corresponding with this path.
|
||||||
|
let id = self.path_to_keyid(&path)
|
||||||
|
.ok_or_else(|| format_err!("Malformed path: {:?}", path))?;
|
||||||
|
|
||||||
|
let found = tpk.keys_all()
|
||||||
|
.map(|(_, _, key)| KeyID::try_from(key.fingerprint()).unwrap())
|
||||||
|
.any(|key_fp| key_fp == id);
|
||||||
|
if ! found {
|
||||||
|
return Err(format_err!(
|
||||||
|
"{:?} points to the wrong TPK, the TPK does not \
|
||||||
|
contain the (sub)key {}", path, id));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
)?;
|
||||||
|
|
||||||
|
self.perform_checks(&self.links_dir_by_email, &mut tpks,
|
||||||
|
|path, tpk, _| {
|
||||||
|
// The Email corresponding with this path.
|
||||||
|
let email = self.path_to_email(&path)
|
||||||
|
.ok_or_else(|| format_err!("Malformed path: {:?}", path))?;
|
||||||
|
let mut found = false;
|
||||||
|
for uidb in tpk.userids() {
|
||||||
|
if Email::try_from(uidb.userid()).unwrap() == email
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ! found {
|
||||||
|
return Err(format_err!(
|
||||||
|
"{:?} points to the wrong TPK, the TPK does not \
|
||||||
|
contain the email {}", path, email));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn perform_checks(
|
||||||
|
&self,
|
||||||
|
checks_dir: &Path,
|
||||||
|
tpks: &mut HashMap<Fingerprint, TPK>,
|
||||||
|
check: impl Fn(&Path, &TPK, &Fingerprint) -> Result<()>,
|
||||||
|
) -> Result<()> {
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
use std::fs;
|
||||||
|
use failure::format_err;
|
||||||
|
|
||||||
|
for entry in WalkDir::new(checks_dir) {
|
||||||
let entry = entry?;
|
let entry = entry?;
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
let typ = fs::symlink_metadata(&path)?.file_type();
|
let typ = fs::symlink_metadata(&path)?.file_type();
|
||||||
|
@ -206,19 +306,12 @@ impl Filesystem {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Fingerprint corresponding with this path.
|
|
||||||
let fp = self.path_to_fingerprint(&path)
|
|
||||||
.ok_or_else(|| format_err!("Malformed path: {:?}", path))?;
|
|
||||||
|
|
||||||
// Compute the corresponding primary fingerprint just
|
// Compute the corresponding primary fingerprint just
|
||||||
// by looking at the paths.
|
// by looking at the paths.
|
||||||
let primary_fp = match () {
|
let primary_fp = self.path_to_primary(path)
|
||||||
_ if typ.is_file() =>
|
.ok_or_else(
|
||||||
fp.clone(),
|
|| format_err!("Malformed path: {:?}",
|
||||||
_ => return
|
path.read_link().unwrap()))?;
|
||||||
Err(format_err!("{:?} is not a file but a {:?}", path, typ)),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Load into cache.
|
// Load into cache.
|
||||||
if ! tpks.contains_key(&primary_fp) {
|
if ! tpks.contains_key(&primary_fp) {
|
||||||
tpks.insert(
|
tpks.insert(
|
||||||
|
@ -228,144 +321,13 @@ impl Filesystem {
|
||||||
|| format_err!("No TPK with fingerprint {:?}",
|
|| format_err!("No TPK with fingerprint {:?}",
|
||||||
primary_fp))?);
|
primary_fp))?);
|
||||||
}
|
}
|
||||||
let tpk = tpks.get(&primary_fp).unwrap();
|
|
||||||
|
|
||||||
let tpk_primary_fp =
|
|
||||||
tpk.primary().fingerprint().try_into().unwrap();
|
|
||||||
if fp != tpk_primary_fp {
|
|
||||||
return Err(format_err!(
|
|
||||||
"{:?} points to the wrong TPK, expected {} \
|
|
||||||
but found {}",
|
|
||||||
path, fp, tpk_primary_fp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check subkeys
|
|
||||||
for entry in WalkDir::new(&self.links_dir_by_fingerprint) {
|
|
||||||
let entry = entry?;
|
|
||||||
let path = entry.path();
|
|
||||||
let typ = fs::symlink_metadata(&path)?.file_type();
|
|
||||||
if typ.is_dir() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The KeyID corresponding with this path.
|
|
||||||
let fp = self.path_to_fingerprint(&path)
|
|
||||||
.ok_or_else(|| format_err!("Malformed path: {:?}", path))?;
|
|
||||||
|
|
||||||
// Compute the corresponding primary fingerprint just
|
|
||||||
// by looking at the paths.
|
|
||||||
let primary_fp = match () {
|
|
||||||
_ if typ.is_symlink() =>
|
|
||||||
self.path_to_fingerprint(&path.read_link()?)
|
|
||||||
.ok_or_else(
|
|
||||||
|| format_err!("Malformed path: {:?}",
|
|
||||||
path.read_link().unwrap()))?,
|
|
||||||
_ => return
|
|
||||||
Err(format_err!("{:?} is not a symlink but a {:?}",
|
|
||||||
path, typ)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let tpk = tpks.get(&primary_fp)
|
let tpk = tpks.get(&primary_fp)
|
||||||
.ok_or_else(
|
.ok_or_else(
|
||||||
|| format_err!("Broken symlink {:?}: No such Key {}",
|
|| format_err!("Broken symlink {:?}: No such Key {}",
|
||||||
path, primary_fp))?;
|
path, primary_fp))?;
|
||||||
|
|
||||||
let found = tpk.keys_all()
|
check(&path, &tpk, &primary_fp)?;
|
||||||
.map(|(_, _, key)| Fingerprint::try_from(key.fingerprint()).unwrap())
|
|
||||||
.any(|key_fp| key_fp == fp);
|
|
||||||
if ! found {
|
|
||||||
return Err(format_err!(
|
|
||||||
"{:?} points to the wrong TPK, the TPK does not \
|
|
||||||
contain the subkey {}", path, fp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check KeyIDs.
|
|
||||||
for entry in WalkDir::new(&self.links_dir_by_keyid) {
|
|
||||||
let entry = entry?;
|
|
||||||
let path = entry.path();
|
|
||||||
let typ = fs::symlink_metadata(&path)?.file_type();
|
|
||||||
if typ.is_dir() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The KeyID corresponding with this path.
|
|
||||||
let id = self.path_to_keyid(&path)
|
|
||||||
.ok_or_else(|| format_err!("Malformed path: {:?}", path))?;
|
|
||||||
|
|
||||||
// Compute the corresponding primary fingerprint just
|
|
||||||
// by looking at the paths.
|
|
||||||
let primary_fp = match () {
|
|
||||||
_ if typ.is_symlink() =>
|
|
||||||
self.path_to_fingerprint(&path.read_link()?)
|
|
||||||
.ok_or_else(
|
|
||||||
|| format_err!("Malformed path: {:?}",
|
|
||||||
path.read_link().unwrap()))?,
|
|
||||||
_ => return
|
|
||||||
Err(format_err!("{:?} is not a symlink but a {:?}",
|
|
||||||
path, typ)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let tpk = tpks.get(&primary_fp)
|
|
||||||
.ok_or_else(
|
|
||||||
|| format_err!("Broken symlink {:?}: No such Key {}",
|
|
||||||
path, primary_fp))?;
|
|
||||||
|
|
||||||
let found = tpk.keys_all()
|
|
||||||
.map(|(_, _, key)| KeyID::try_from(key.fingerprint()).unwrap())
|
|
||||||
.any(|key_fp| key_fp == id);
|
|
||||||
if ! found {
|
|
||||||
return Err(format_err!(
|
|
||||||
"{:?} points to the wrong TPK, the TPK does not \
|
|
||||||
contain the (sub)key {}", path, id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check Emails.
|
|
||||||
for entry in WalkDir::new(&self.links_dir_by_email) {
|
|
||||||
let entry = entry?;
|
|
||||||
let path = entry.path();
|
|
||||||
let typ = fs::symlink_metadata(&path)?.file_type();
|
|
||||||
if typ.is_dir() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Email corresponding with this path.
|
|
||||||
let email = self.path_to_email(&path)
|
|
||||||
.ok_or_else(|| format_err!("Malformed path: {:?}", path))?;
|
|
||||||
|
|
||||||
// Compute the corresponding primary fingerprint just
|
|
||||||
// by looking at the paths.
|
|
||||||
let primary_fp = match () {
|
|
||||||
_ if typ.is_symlink() =>
|
|
||||||
self.path_to_fingerprint(&path.read_link()?)
|
|
||||||
.ok_or_else(
|
|
||||||
|| format_err!("Malformed path: {:?}",
|
|
||||||
path.read_link().unwrap()))?,
|
|
||||||
_ => return
|
|
||||||
Err(format_err!("{:?} is not a symlink but a {:?}",
|
|
||||||
path, typ)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let tpk = tpks.get(&primary_fp)
|
|
||||||
.ok_or_else(
|
|
||||||
|| format_err!("Broken symlink {:?}: No such Key {}",
|
|
||||||
path, primary_fp))?;
|
|
||||||
|
|
||||||
let mut found = false;
|
|
||||||
for uidb in tpk.userids() {
|
|
||||||
if Email::try_from(uidb.userid()).unwrap() == email
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ! found {
|
|
||||||
return Err(format_err!(
|
|
||||||
"{:?} points to the wrong TPK, the TPK does not \
|
|
||||||
contain the email {}", path, email));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in a new issue