about summary refs log tree commit diff
path: root/kittybox-rs/indieauth/src/pkce.rs
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2022-07-10 19:35:10 +0300
committerVika <vika@fireburn.ru>2022-07-10 19:35:10 +0300
commit9ca0e358dc95e7358815886b061288f04a7d29af (patch)
treebc19ac6071d75f1ae58069e577fc02692aa87c8b /kittybox-rs/indieauth/src/pkce.rs
parent0ee2072d40dc0b88a7f475a25dfc790d49546a5f (diff)
kittybox-indieauth: init
This crate is the base framework-agnostic implementation of all data
structures and methods required for IndieAuth protocol. Anything that
can deserialize HTTP request payloads with serde can utilize this
crate.

This is a good candidate to independently release on crates.io when
the interface becomes stable enough.
Diffstat (limited to 'kittybox-rs/indieauth/src/pkce.rs')
-rw-r--r--kittybox-rs/indieauth/src/pkce.rs73
1 files changed, 73 insertions, 0 deletions
diff --git a/kittybox-rs/indieauth/src/pkce.rs b/kittybox-rs/indieauth/src/pkce.rs
new file mode 100644
index 0000000..a0bc291
--- /dev/null
+++ b/kittybox-rs/indieauth/src/pkce.rs
@@ -0,0 +1,73 @@
+use serde::{Serialize, Deserialize};
+use rand::{Rng, distributions::Alphanumeric};
+use sha2::{Sha256, Digest};
+use data_encoding::BASE64URL;
+
+#[derive(PartialEq, Eq, Copy, Clone, Debug, Serialize, Deserialize)]
+pub enum PKCEMethod {
+    S256,
+    Plain
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct PKCEVerifier(String);
+
+impl AsRef<str> for PKCEVerifier {
+    fn as_ref(&self) -> &str {
+        self.0.as_str()
+    }
+}
+impl ToString for PKCEVerifier {
+    fn to_string(&self) -> String {
+        self.0.clone()
+    }
+}
+
+impl PKCEVerifier {
+    fn new() -> Self {
+        let bytes = rand::thread_rng()
+            .sample_iter(&Alphanumeric)
+            .take(128)
+            .collect::<Vec<u8>>();
+        Self(String::from_utf8(bytes).unwrap())
+    }
+}
+
+#[derive(Eq, PartialEq, Debug, Clone, Serialize, Deserialize)]
+pub struct PKCEChallenge {
+    code_challenge: String,
+    method: PKCEMethod
+}
+
+impl PKCEChallenge {
+    fn new(code_verifier: PKCEVerifier, method: PKCEMethod) -> Self {
+        Self {
+            code_challenge: match method {
+                PKCEMethod::S256 => {
+                    let mut hasher = Sha256::new();
+                    hasher.update(code_verifier.as_ref());
+                    BASE64URL.encode(&hasher.finalize())
+                },
+                PKCEMethod::Plain => code_verifier.to_string(),
+            },
+            method
+        }
+    }
+    fn verify(&self, code_verifier: PKCEVerifier) -> bool {
+        Self::new(code_verifier, self.method) == *self
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_pkce() {
+        let verifier = PKCEVerifier::new();
+        let challenge = PKCEChallenge::new(verifier.clone(), PKCEMethod::S256);
+
+        assert!(challenge.verify(verifier));
+    }
+
+}