This repository has no description
1.8 kB
72 lines
1use http::HeaderValue;
2use knot_runtime::{Entropy, HttpRequest, Signer};
3use knot_types::{KnotId, Nsid, ServiceDid, UnixSeconds};
4
5use crate::AtprotoError;
6use crate::jwt;
7use crate::jwt::JwtNonce;
8
9const POINTER_NONCE_BYTES: usize = 16;
10
11pub struct PointerAuth<'a> {
12 pub issuer: &'a KnotId,
13 pub audience: &'a ServiceDid,
14 pub lxm: &'a Nsid,
15 pub now_unix: UnixSeconds,
16}
17
18pub trait PointerAuthorizer {
19 fn authorize(
20 &self,
21 request: &mut HttpRequest,
22 ctx: &PointerAuth<'_>,
23 ) -> Result<(), AtprotoError>;
24}
25
26pub struct ServiceAuth<'a> {
27 signer: &'a dyn Signer,
28 entropy: &'a dyn Entropy,
29}
30
31impl<'a> ServiceAuth<'a> {
32 pub fn new(signer: &'a dyn Signer, entropy: &'a dyn Entropy) -> Self {
33 Self { signer, entropy }
34 }
35}
36
37impl PointerAuthorizer for ServiceAuth<'_> {
38 fn authorize(
39 &self,
40 request: &mut HttpRequest,
41 ctx: &PointerAuth<'_>,
42 ) -> Result<(), AtprotoError> {
43 let mut bytes = [0u8; POINTER_NONCE_BYTES];
44 self.entropy.fill(&mut bytes);
45 let nonce = JwtNonce::new(knot_types::lowercase_hex(&bytes))?;
46 let token = jwt::mint(
47 self.signer,
48 ctx.issuer,
49 ctx.audience,
50 ctx.lxm,
51 nonce,
52 ctx.now_unix,
53 );
54 let header = HeaderValue::from_str(&format!("Bearer {token}"))
55 .expect("base64url jwt is valid header value");
56 request.headers.insert(http::header::AUTHORIZATION, header);
57 Ok(())
58 }
59}
60
61pub struct OauthAuthorizer;
62
63impl PointerAuthorizer for OauthAuthorizer {
64 fn authorize(
65 &self,
66 _request: &mut HttpRequest,
67 _ctx: &PointerAuth<'_>,
68 ) -> Result<(), AtprotoError> {
69 todo!("OAuth+DPoP authorizer is waiting on an OAuth client")
70 // one day...
71 }
72}