chiark / gitweb /
server: get token, wip hmac work
[hippotat.git] / src / utils.rs
index 2271fd47cb2b0a97c7136bacd58d4ddbd63d1b8f..e8508b5a6909030fcca62c32884d0b4365029445 100644 (file)
@@ -16,28 +16,57 @@ impl<T,E> Result<T,E> where AE: From<E> {
   }
 }
 
-#[throws(AE)]
-pub async fn read_limited_body<S,E>(limit: usize, mut stream: S) -> Box<[u8]>
-where S: futures::Stream<Item=Result<hyper::body::Bytes,E>> + Unpin,
+#[derive(Error,Debug)]
+pub enum ReadLimitedError {
+  #[error("maximum size {limit} exceeded")]
+  Truncated { sofar: Box<[u8]>, limit: usize },
+
+  #[error("HTTP error {0}")]
+  Hyper(#[from] hyper::Error),
+}
+
+impl ReadLimitedError {
+  pub fn discard_data(&mut self) { match self {
+    ReadLimitedError::Truncated { sofar,.. } => { mem::take(sofar); },
+    _ => { },
+  } }
+}
+#[ext(pub)]
+impl<T> Result<T,ReadLimitedError> {
+  fn discard_data(self) -> Self {
+    self.map_err(|mut e| { e.discard_data(); e })
+  }
+}
+
+#[throws(ReadLimitedError)]
+pub async fn read_limited_bytes<S>(limit: usize, stream: &mut S) -> Box<[u8]>
+where S: futures::Stream<Item=Result<hyper::body::Bytes,hyper::Error>>
+         + Debug + Unpin,
       // we also require that the Stream is cancellation-safe
-      E: std::error::Error + Sync + Send + 'static,
 {
   let mut accum = vec![];
   while let Some(item) = stream.next().await {
-    let b = item.context("HTTP error fetching response body")?;
-    if accum.len() + b.len() > limit {
-      throw!(anyhow!("maximum response body size {} exceeded", limit));
-    }
+    let b = item?;
     accum.extend(b);
+    if accum.len() > limit {
+      throw!(ReadLimitedError::Truncated { limit, sofar: accum.into() })
+    }
   }
   accum.into()
 }
 
+pub fn time_t_now() -> u64 {
+  SystemTime::now()
+    .duration_since(UNIX_EPOCH)
+    .unwrap_or_else(|_| Duration::default()) // clock is being weird
+    .as_secs()
+}
+
 use sha2::Digest as _;
 
-type HmacH = sha2::Sha256;
-const HMAC_B: usize = 64;
-const HMAC_L: usize = 32;
+pub type HmacH = sha2::Sha256;
+pub const HMAC_B: usize = 64;
+pub const HMAC_L: usize = 32;
 
 pub fn token_hmac(key: &[u8], message: &[u8]) -> [u8; HMAC_L] {
   let key = {