pub struct Macaroon<C, M>(/* private fields */)
where
M: OutputSizeUser;Expand description
A macaroon token. For an introduction to macaroons, see fly.io’s execellent blog post. Our format isn’t exactly the same as the one in their examples, but it’s very similar.
To generate a new macaroon on the server side, see Macaroon::new.
Implementations§
Source§impl<C, M> Macaroon<C, M>
impl<C, M> Macaroon<C, M>
Sourcepub fn attenuate(self, caveat: C) -> Self
pub fn attenuate(self, caveat: C) -> Self
Add a caveat to a token. See the documentation of Macaroon::new for an example.
Sourcepub fn tail(&self) -> &GenericArray<u8, <M as OutputSizeUser>::OutputSize>
pub fn tail(&self) -> &GenericArray<u8, <M as OutputSizeUser>::OutputSize>
Get the tail of the caveat. Useful e.g. for generating and checking third party caveats.
Source§impl<C, M> Macaroon<C, M>
impl<C, M> Macaroon<C, M>
Sourcepub fn new<T, K>(id: T, key: K) -> Self
pub fn new<T, K>(id: T, key: K) -> Self
Create a new macaroon given a key, caveat type, hmac function and token identifier.
To create a macaroon, you need to first define the caveats. To do this, create a type that
implements Caveat:
use rustmacaroon::Caveat;
use anyhow::anyhow;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
enum MyCaveats {
Path(String),
Readonly,
}
struct Request {
path: String,
is_write: bool
}
impl Caveat for MyCaveats {
type Error = anyhow::Error;
type Context = Request;
fn verify(&self, ctx: &Self::Context) -> Result<(), Self::Error> {
match self {
MyCaveats::Path(path) if path != ctx.path => Err(anyhow!("You can only access path {path}")),
MyCaveats::Readonly if ctx.is_write => Err(anyhow!("You can only read")),
_ => Ok(())
}
}
}Note: If you’re only a client and just want to add a caveat but not verify caveats, you do not need to implement the
Caveattrait.
When verifying, caveats have access to a user-defined “context”. This is everything the verifier needs to know in order to accurately verify the caveat. For example, in a web server, the context might be the request the user is making.
This caveat type provides the validation logic for your macaroon. Now, you can create a token:
use sha2::Sha256;
use hmac::{Hmac};
let key = b"mysecretkey";
// Note that the token ID ("asdfghjkl" here) should be some (ideally random) byte array or
// string that uniquely identifies this token.
let macaroon: Macaroon<MyCaveats, Hmac<Sha256>> = Macaroon::new(
"asdfghjkl",
&key,
);
// Add some caveats:
let macaroon = macaroon
.attenuate(MyCaveats::Path("/images"))
.attenuate(MyCaveats::Readonly);Use verify to check your token’s signature and validate all caveats.
verify will only return Ok(()) if the signature is valid and every
caveat passes:
// Error: You can only read
assert!(
macaroon.verify(key, Request {
path: "/images",
is_write: true
}).is_err()
);
// Okay!
assert!(
macaroon.verify(key, Request {
path: "/images",
is_write: false
}).is_ok()
);Sourcepub fn verify<K>(
&self,
key: K,
ctx: &C::Context,
) -> Result<(), VerificationError<C>>
pub fn verify<K>( &self, key: K, ctx: &C::Context, ) -> Result<(), VerificationError<C>>
Check the signature and verify every caveat. See the documentation of
Macaroon::new for an example.