1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use std::collections::HashMap;
use std::borrow::Cow;
use chrono::{Duration, Utc};

use super::{Authorizer, Request, Grant, Scope, Time, TokenGenerator, Url};

struct SpecificGrant {
    owner_id: String,
    client_id: String,
    scope: Scope,
    redirect_url: Url,
    until: Time,
}

impl<'a> Into<Grant<'a>> for SpecificGrant {
    fn into(self) -> Grant<'a> {
        Grant {
            owner_id: Cow::Owned(self.owner_id),
            client_id: Cow::Owned(self.client_id),
            scope: Cow::Owned(self.scope),
            redirect_url: Cow::Owned(self.redirect_url),
            until: Cow::Owned(self.until),
        }
    }
}

impl<'a> Grant<'a> {
    fn from_refs(owner_id: &'a str, client_id: &'a str, scope: &'a Scope,
        redirect_url: &'a Url, until: &'a Time) -> Grant<'a> {
        Grant {
            owner_id: Cow::Borrowed(owner_id),
            client_id: Cow::Borrowed(client_id),
            scope: Cow::Borrowed(scope),
            redirect_url: Cow::Borrowed(redirect_url),
            until: Cow::Borrowed(until),
        }
    }
}

pub struct Storage<I: TokenGenerator> {
    issuer: I,
    tokens: HashMap<String, SpecificGrant>
}

impl<I: TokenGenerator> Storage<I> {
    pub fn new(issuer: I) -> Storage<I> {
        Storage {issuer: issuer, tokens: HashMap::new()}
    }
}

impl<I: TokenGenerator> Authorizer for Storage<I> {
    fn authorize(&mut self, req: Request) -> String {
        let owner_id = req.owner_id.to_string();
        let client_id = req.client_id.to_string();
        let scope = req.scope.clone();
        let redirect_url = req.redirect_url.clone();
        let until = Utc::now() + Duration::minutes(10);

        let token = self.issuer.generate(
            &Grant::from_refs(&owner_id, &client_id, &scope, &redirect_url, &until));
        self.tokens.insert(token.clone(), SpecificGrant {
            owner_id, client_id, scope, redirect_url, until
        });
        token
    }

    fn extract<'a>(&mut self, grant: &'a str) -> Option<Grant<'a>> {
        self.tokens.remove(grant).map(|v| v.into())
    }
}