diff --git a/Cargo.toml b/Cargo.toml
index 61f4322..93c95a5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,11 +14,12 @@ rand = "0.5"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
-base64 = "0.9"
time = "0.1"
tempfile = "3.0"
parking_lot = "0.6"
structopt = "0.2"
+url = "1.6"
+hex = "0.3"
[dependencies.rocket_contrib]
version = "0"
diff --git a/dist/templates/index.html.hbs b/dist/templates/index.html.hbs
index a2c1715..a8da66b 100644
--- a/dist/templates/index.html.hbs
+++ b/dist/templates/index.html.hbs
@@ -3,8 +3,9 @@
The verifying PGP key server. Powered by p≡pnology!
Search for keys
-
diff --git a/src/database/fs.rs b/src/database/fs.rs
index 4fa41d4..e083f28 100644
--- a/src/database/fs.rs
+++ b/src/database/fs.rs
@@ -6,11 +6,11 @@ use std::os::unix::fs::symlink;
use tempfile;
use serde_json;
-use openpgp::packet::UserID;
-use base64;
+use url;
-use database::{Verify, Delete, Fingerprint, Database};
+use database::{Verify, Delete, Database};
use Result;
+use types::{Email, Fingerprint};
pub struct Filesystem {
base: PathBuf,
@@ -48,7 +48,7 @@ impl Filesystem {
create_dir_all(base.join("deletion_tokens"))?;
create_dir_all(base.join("scratch_pad"))?;
create_dir_all(base.join("public").join("by-fpr"))?;
- create_dir_all(base.join("public").join("by-uid"))?;
+ create_dir_all(base.join("public").join("by-email"))?;
info!("Opened base dir '{}'", base.display());
Ok(Filesystem{
@@ -127,10 +127,10 @@ impl Database for Filesystem {
}
}
- fn link_userid(&self, uid: &UserID, fpr: &Fingerprint) {
- let uid = base64::encode_config(uid.userid(), base64::URL_SAFE);
+ fn link_email(&self, email: &Email, fpr: &Fingerprint) {
+ let email = url::form_urlencoded::byte_serialize(email.to_string().as_bytes()).collect::();
let target = self.base.join("public").join("by-fpr").join(fpr.to_string());
- let link = self.base.join("public").join("by-uid").join(uid);
+ let link = self.base.join("public").join("by-email").join(email);
if link.exists() {
let _ = remove_file(link.clone());
@@ -139,9 +139,9 @@ impl Database for Filesystem {
let _ = symlink(target, link);
}
- fn unlink_userid(&self, uid: &UserID, fpr: &Fingerprint) {
- let uid = base64::encode_config(uid.userid(), base64::URL_SAFE);
- let link = self.base.join("public").join("by-uid").join(uid);
+ fn unlink_email(&self, email: &Email, fpr: &Fingerprint) {
+ let email = url::form_urlencoded::byte_serialize(email.to_string().as_bytes()).collect::();
+ let link = self.base.join("public").join("by-email").join(email);
match read_link(link.clone()) {
Ok(target) => {
@@ -187,10 +187,11 @@ impl Database for Filesystem {
}
// XXX: slow
- fn by_uid(&self, uid: &str) -> Option> {
+ fn by_email(&self, email: &Email) -> Option> {
use std::fs;
- let path = self.base.join("public").join("by-uid").join(uid);
+ let email = url::form_urlencoded::byte_serialize(email.to_string().as_bytes()).collect::();
+ let path = self.base.join("public").join("by-email").join(email);
fs::canonicalize(path).ok()
.and_then(|p| {
diff --git a/src/database/memory.rs b/src/database/memory.rs
index d6ba79a..a1600ec 100644
--- a/src/database/memory.rs
+++ b/src/database/memory.rs
@@ -1,15 +1,13 @@
use std::collections::HashMap;
use parking_lot::Mutex;
-use openpgp::packet::UserID;
-use base64;
-
-use database::{Verify, Delete, Fingerprint, Database};
+use database::{Verify, Delete, Database};
+use types::{Email, Fingerprint};
use Result;
pub struct Memory {
fpr: Mutex>>,
- userid: Mutex>,
+ email: Mutex>,
verify_token: Mutex>,
delete_token: Mutex>,
}
@@ -18,7 +16,7 @@ impl Default for Memory {
fn default() -> Self {
Memory{
fpr: Mutex::new(HashMap::default()),
- userid: Mutex::new(HashMap::default()),
+ email: Mutex::new(HashMap::default()),
verify_token: Mutex::new(HashMap::default()),
delete_token: Mutex::new(HashMap::default()),
}
@@ -56,14 +54,12 @@ impl Database for Memory {
}
}
- fn link_userid(&self, uid: &UserID, fpr: &Fingerprint) {
- let uid = base64::encode_config(uid.userid(), base64::URL_SAFE);
- self.userid.lock().insert(uid.to_string(), fpr.clone());
+ fn link_email(&self, email: &Email, fpr: &Fingerprint) {
+ self.email.lock().insert(email.clone(), fpr.clone());
}
- fn unlink_userid(&self, uid: &UserID, _: &Fingerprint) {
- let uid = base64::encode_config(uid.userid(), base64::URL_SAFE);
- self.userid.lock().remove(&uid.to_string());
+ fn unlink_email(&self, email: &Email, _: &Fingerprint) {
+ self.email.lock().remove(email);
}
// (verified uid, fpr)
@@ -80,11 +76,11 @@ impl Database for Memory {
self.fpr.lock().get(fpr).map(|x| x.clone())
}
- fn by_uid(&self, uid: &str) -> Option> {
- let userid = self.userid.lock();
+ fn by_email(&self, email: &Email) -> Option> {
+ let by_email = self.email.lock();
let fprs = self.fpr.lock();
- userid.get(uid).and_then(|fpr| fprs.get(fpr).map(|x| x.clone()))
+ by_email.get(email).and_then(|fpr| fprs.get(fpr).map(|x| x.clone()))
}
}
diff --git a/src/database/mod.rs b/src/database/mod.rs
index d5b3a90..1625caa 100644
--- a/src/database/mod.rs
+++ b/src/database/mod.rs
@@ -1,14 +1,10 @@
-use std::result;
use std::io::Cursor;
-use std::str::FromStr;
use std::convert::TryFrom;
-use std::fmt;
-use serde::{Serializer, Deserializer, de};
use time;
-use openpgp::{self, packet::Signature, TPK, packet::UserID, Packet, PacketPile, constants::SignatureType};
-use base64;
-use {Error, Result};
+use openpgp::{packet::Signature, TPK, packet::UserID, Packet, PacketPile, constants::SignatureType};
+use Result;
+use types::{Fingerprint, Email};
mod fs;
pub use self::fs::Filesystem;
@@ -16,53 +12,16 @@ mod memory;
pub use self::memory::Memory;
mod poly;
pub use self::poly::Polymorphic;
+
+#[cfg(test)]
mod test;
-
-#[derive(Serialize,Deserialize,Clone,Debug,Hash,PartialEq,Eq)]
-pub struct Fingerprint([u8; 20]);
-
-impl TryFrom for Fingerprint {
- type Error = Error;
-
- fn try_from(fpr: openpgp::Fingerprint) -> Result {
- match fpr {
- openpgp::Fingerprint::V4(a) => Ok(Fingerprint(a)),
- openpgp::Fingerprint::Invalid(_) => Err("invalid fingerprint".into()),
- }
- }
-}
-
-impl ToString for Fingerprint {
- fn to_string(&self) -> String {
- base64::encode_config(&self.0[..], base64::URL_SAFE)
- }
-}
-
-impl FromStr for Fingerprint {
- type Err = Error;
-
- fn from_str(s: &str) -> Result {
- let vec = base64::decode_config(s, base64::URL_SAFE)
- .map_err(|e| format!("'{}' is not a valid fingerprint: {}", s, e))?;
- if vec.len() == 20 {
- let mut arr = [0u8; 20];
-
- arr.copy_from_slice(&vec[..]);
- Ok(Fingerprint(arr))
- } else {
- Err(format!("'{}' is not a valid fingerprint", s).into())
- }
- }
-}
-
#[derive(Serialize,Deserialize,Clone,Debug)]
pub struct Verify {
created: i64,
packets: Box<[u8]>,
fpr: Fingerprint,
- #[serde(deserialize_with = "Verify::deserialize_userid", serialize_with = "Verify::serialize_userid")]
- uid: UserID,
+ email: Email,
}
impl Verify {
@@ -70,7 +29,6 @@ impl Verify {
use openpgp::serialize::Serialize;
let mut cur = Cursor::new(Vec::default());
-
let res: Result<()> = uid.serialize(&mut cur)
.map_err(|e| format!("openpgp: {}", e).into());
res?;
@@ -85,50 +43,9 @@ impl Verify {
created: time::now().to_timespec().sec,
packets: cur.into_inner().into(),
fpr: fpr,
- uid: uid.clone(),
+ email: Email::try_from(uid.clone())?,
})
}
- fn deserialize_userid<'de, D>(de: D) -> result::Result where D: Deserializer<'de> {
- de.deserialize_bytes(UserIDVisitor)
- }
-
- fn serialize_userid(uid: &UserID, ser: S) -> result::Result where S: Serializer {
- ser.serialize_bytes(uid.userid())
- }
-}
-
-struct UserIDVisitor;
-
-impl<'de> de::Visitor<'de> for UserIDVisitor {
- type Value = UserID;
-
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- write!(formatter, "a OpenPGP User ID")
- }
-
- fn visit_bytes(self, s: &[u8]) -> result::Result
- where
- E: de::Error,
- {
- let mut uid = UserID::new();
- uid.set_userid_from_bytes(s);
- Ok(uid)
- }
-
- fn visit_seq(self, mut seq: A) -> result::Result
- where
- A: de::SeqAccess<'de>
- {
- let mut buf = Vec::default();
-
- while let Some(x) = seq.next_element()? {
- buf.push(x);
- }
-
- let mut uid = UserID::new();
- uid.set_userid_from_bytes(&buf);
- Ok(uid)
- }
}
#[derive(Serialize,Deserialize,Clone,Debug)]
@@ -155,8 +72,8 @@ pub trait Database: Sync + Send {
fn compare_and_swap(&self, fpr: &Fingerprint, present: Option<&[u8]>, new: Option<&[u8]>) -> Result;
- fn link_userid(&self, uid: &UserID, fpr: &Fingerprint);
- fn unlink_userid(&self, uid: &UserID, fpr: &Fingerprint);
+ fn link_email(&self, email: &Email, fpr: &Fingerprint);
+ fn unlink_email(&self, email: &Email, fpr: &Fingerprint);
// (verified uid, fpr)
fn pop_verify_token(&self, token: &str) -> Option;
@@ -164,7 +81,7 @@ pub trait Database: Sync + Send {
fn pop_delete_token(&self, token: &str) -> Option;
fn by_fpr(&self, fpr: &Fingerprint) -> Option>;
- fn by_uid(&self, uid: &str) -> Option>;
+ fn by_email(&self, email: &Email) -> Option>;
// fn by_kid<'a>(&self, fpr: &str) -> Option<&[u8]>;
fn strip_userids(tpk: TPK) -> Result {
@@ -187,18 +104,22 @@ pub trait Database: Sync + Send {
tpk.serialize(&mut cur).map(|_| cur.into_inner()).map_err(|e| format!("{}", e).into())
}
- fn merge_or_publish(&self, mut tpk: TPK) -> Result> {
+ fn merge_or_publish(&self, mut tpk: TPK) -> Result> {
let fpr = Fingerprint::try_from(tpk.primary().fingerprint())?;
let mut ret = Vec::default();
// update verify tokens
for uid in tpk.userids() {
- let enc = base64::encode_config(&format!("{}", uid.userid()), base64::URL_SAFE);
- if self.by_uid(&enc).is_none() {
- let payload = Verify::new(uid.userid(), &uid.selfsigs().collect::>(), fpr.clone())?;
+ let email = Email::try_from(uid.userid().clone())?;
+
+ if self.by_email(&email).is_none() {
+ let payload = Verify::new(
+ uid.userid(),
+ &uid.selfsigs().collect::>(),
+ fpr.clone())?;
// XXX: send mail
- ret.push((uid.userid().clone(),self.new_verify_token(payload)?));
+ ret.push((email, self.new_verify_token(payload)?));
}
}
@@ -238,9 +159,9 @@ pub trait Database: Sync + Send {
// cas(tpk, merged)
// }
// }
- fn verify_token(&self, token: &str) -> Result