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
use byteorder::{LittleEndian, WriteBytesExt};
use crate::{lp_encode, vlp_encode, InformalProperty, WithInformalProperty};
use std::io;

#[derive(Default, Debug)]
pub struct DNSCryptProvider {
    name: String,
    pk: Vec<u8>,
}

impl DNSCryptProvider {
    pub fn new(name: String, pk: Vec<u8>) -> Self {
        DNSCryptProvider { name, pk }
    }
}

#[derive(Default, Debug)]
pub struct DNSCryptBuilder {
    informal_properties: u64,
    addrs: Vec<String>,
    provider: DNSCryptProvider,
}

impl DNSCryptBuilder {
    pub fn new(provider: DNSCryptProvider) -> Self {
        DNSCryptBuilder {
            informal_properties: 0,
            addrs: vec![],
            provider,
        }
    }

    pub fn with_addr(mut self, addr: String) -> Self {
        self.addrs.push(addr);
        self
    }

    pub fn serialize(self) -> io::Result<String> {
        let mut bin = vec![];
        bin.push(0x01);
        bin.write_u64::<LittleEndian>(self.informal_properties)?;
        let addrs_bin: Vec<_> = self
            .addrs
            .iter()
            .map(|addr| addr.as_bytes().to_vec())
            .collect();
        vlp_encode(&mut bin, &addrs_bin)?;
        let provider_bin = {
            let mut bin = vec![];
            bin.extend(&self.provider.pk);
            bin.extend(self.provider.name.as_str().as_bytes());
            bin
        };
        lp_encode(&mut bin, &provider_bin)?;
        let serialized = base64::encode_config(
            &bin,
            base64::Config::new(base64::CharacterSet::UrlSafe, false),
        );
        Ok(format!("sdns://{}", serialized))
    }
}

impl WithInformalProperty for DNSCryptBuilder {
    fn with_informal_property(mut self, informal_property: InformalProperty) -> Self {
        self.informal_properties |= u64::from(informal_property);
        self
    }
}