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
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
use ed25519_dalek::{
    Keypair, PublicKey, Signature, SignatureError, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH,
    SIGNATURE_LENGTH,
};
use rand::rngs::OsRng;
use rand_core::RngCore;
use std::{collections::HashMap, convert::From};

type PublicKeyBytes = [u8; PUBLIC_KEY_LENGTH];
type SignatureBytes = [u8; SIGNATURE_LENGTH];
type TokenBytes = [u8; 64];

/// Identity schema
///
/// + pkey: https://oin.example.com/pkey
/// + name: https://oin.example.com/pkey/name
pub struct Identity {
    pub name: String,
    pub pkey: PublicKeyBytes,
    pub sigs: HashMap<PublicKeyBytes, SignatureBytes>,
}

impl Identity {
    /// Generate a new identity
    pub fn new() -> (Identity, [u8; SECRET_KEY_LENGTH]) {
        let mut csprng = OsRng {};
        let keypair = Keypair::generate(&mut csprng);

        (
            Identity {
                name: "".to_string(),
                pkey: keypair.public.to_bytes(),
                sigs: HashMap::new(),
            },
            keypair.secret.to_bytes(),
        )
    }

    /// Generate random token
    pub fn token() -> TokenBytes {
        let mut rng = [0; 64];
        let mut orng = rand::rngs::OsRng {};
        orng.fill_bytes(&mut rng);

        rng
    }

    /// Make the msg is signed by the publickey
    pub fn auth(
        &mut self,
        // services id
        id: PublicKeyBytes,
        // login token
        tk: TokenBytes,
        // user signature with token
        sig: SignatureBytes,
    ) -> Result<(), Error> {
        PublicKey::from_bytes(&self.pkey)?.verify(&tk, &Signature::from_bytes(&sig)?)?;
        self.sigs.insert(id, sig);
        Ok(())
    }

    /// Check if identity token paired
    pub fn state(&self, id: PublicKeyBytes, sig: SignatureBytes) -> Result<(), Error> {
        if let Some(s) = self.sigs.get(&id) {
            if s.to_vec() == sig.to_vec() {
                return Ok(());
            }

            return Err(Error::TokenError);
        }

        Err(Error::TokenError)
    }

    /// Update token for id
    pub fn update(&mut self, id: PublicKeyBytes, sig: SignatureBytes) -> Result<(), Error> {
        if self.sigs.insert(id, sig).is_some() {
            return Ok(());
        }

        Err(Error::TokenError)
    }
}

/// Generete identity from public key
impl From<PublicKeyBytes> for Identity {
    fn from(b: PublicKeyBytes) -> Identity {
        Identity {
            name: "".to_string(),
            pkey: b,
            sigs: HashMap::new(),
        }
    }
}

/// Abstract Errors
#[derive(Debug)]
pub enum Error {
    LoginError,
    TokenError,
}

impl From<SignatureError> for Error {
    fn from(_: SignatureError) -> Self {
        Error::LoginError
    }
}