summaryrefslogtreecommitdiffstats
path: root/net/tests/hkp.rs
blob: 544c453390ca551d2962acf47a32e7c7254e7113 (plain)
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use http::{Request, Response};
use hyper::{Server, Body};
use hyper::service::{make_service_fn, service_fn};
use hyper::{Method, StatusCode};
use rand::RngCore;
use rand::rngs::OsRng;
use std::io::Cursor;
use std::net::{SocketAddr, IpAddr, Ipv4Addr};

use sequoia_openpgp::armor::Reader;
use sequoia_openpgp::Cert;
use sequoia_openpgp::parse::Parse;
use sequoia_core::{Context, NetworkPolicy};
use sequoia_net::KeyServer;

const RESPONSE: &'static str = "-----BEGIN PGP PUBLIC KEY BLOCK-----

xsBNBFoVcvoBCACykTKOJddF8SSUAfCDHk86cNTaYnjCoy72rMgWJsrMLnz/V16B
J9M7l6nrQ0JMnH2Du02A3w+kNb5q97IZ/M6NkqOOl7uqjyRGPV+XKwt0G5mN/ovg
8630BZAYS3QzavYf3tni9aikiGH+zTFX5pynTNfYRXNBof3Xfzl92yad2bIt4ITD
NfKPvHRko/tqWbclzzEn72gGVggt1/k/0dKhfsGzNogHxg4GIQ/jR/XcqbDFR3RC
/JJjnTOUPGsC1y82Xlu8udWBVn5mlDyxkad5laUpWWg17anvczEAyx4TTOVItLSu
43iPdKHSs9vMXWYID0bg913VusZ2Ofv690nDABEBAAG0JFRlc3R5IE1jVGVzdGZh
Y2UgPHRlc3R5QGV4YW1wbGUub3JnPsLAlAQTAQgAPhYhBD6Id8h3J0aSl1GJ9dA/
b4ZSJv6LBQJaFXL6AhsDBQkDwmcABQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJ
ENA/b4ZSJv6Lxo8H/1XMt+Nqa6e0SG/up3ypKe5nplA0p/9j/s2EIsP8S8uPUd+c
WS17XOmPwkNDmHeL3J6hzwL74NlYSLEtyf7WoOV74xAKQA9WkqaKPHCtpll8aFWA
ktQDLWTPeKuUuSlobAoRtO17ZmheSQzmm7JYt4Ahkxt3agqGT05OsaAey6nIKqpq
ArokvdHTZ7AFZeSJIWmuCoT9M1lo3LAtLnRGOhBMJ5dDIeOwflJwNBXlJVi4mDPK
+fumV0MbSPvZd1/ivFjSpQyudWWtv1R1nAK7+a4CPTGxPvAQkLtRsL/V+Q7F3BJG
jAn4QVx8p4t3NOPuNgcoZpLBE3sc4Nfs5/CphMLOwE0EWhVy+gEIALSpjYD+tuWC
rj6FGP6crQjQzVlH+7axoM1ooTwiPs4fzzt2iLw3CJyDUviM5F9ZBQTei635RsAR
a/CJTSQYAEU5yXXxhoe0OtwnuvsBSvVT7Fox3pkfNTQmwMvkEbodhfKpqBbDKCL8
f5A8Bb7aISsLf0XRHWDkHVqlz8LnOR3f44wEWiTeIxLc8S1QtwX/ExyW47oPsjs9
ShCmwfSpcngH/vGBRTO7WeI54xcAtKSm/20B/MgrUl5qFo17kUWot2C6KjuZKkHk
3WZmJwQz+6rTB11w4AXt8vKkptYQCkfat2FydGpgRO5dVg6aWNJefOJNkC7MmlzC
ZrrAK8FJ6jcAEQEAAcLAdgQYAQgAIBYhBD6Id8h3J0aSl1GJ9dA/b4ZSJv6LBQJa
FXL6AhsMAAoJENA/b4ZSJv6Lt7kH/jPr5wg8lcamuLj4lydYiLttvvTtDTlD1TL+
IfwVARB/ruoerlEDr0zX1t3DCEcvJDiZfOqJbXtHt70+7NzFXrYxfaNFmikMgSQT
XqHrMQho4qpseVOeJPWGzGOcrxCdw/ZgrWbkDlAU5KaIvk+M4wFPivjbtW2Ro2/F
J4I/ZHhJlIPmM+hUErHC103b08pBENXDQlXDma7LijH5kWhyfF2Ji7Ft0EjghBaW
AeGalQHjc5kAZu5R76Mwt06MEQ/HL1pIvufTFxkr/SzIv8Ih7Kexb0IrybmfD351
Pu1xwz57O4zo1VYf6TqHJzVC3OMvMUM2hhdecMUe5x6GorNaj6g=
=z5uK
-----END PGP PUBLIC KEY BLOCK-----
";

const FP: &'static str = "3E8877C877274692975189F5D03F6F865226FE8B";
const ID: &'static str = "D03F6F865226FE8B";

async fn service(req: Request<Body>)
           -> Result<Response<Body>, Box<dyn std::error::Error + Send + Sync>> {
    let (parts, body) = req.into_parts();
    match (parts.method, parts.uri.path()) {
        (Method::GET, "/pks/lookup") => {
            if let Some(args) = parts.uri.query() {
                for (key, value) in url::form_urlencoded::parse(args.as_bytes()) {
                    match key.clone().into_owned().as_ref() {
                        "op" => assert_eq!(value, "get"),
                        "options" => assert_eq!(value, "mr"),
                        "search" => assert_eq!(value, "0xD03F6F865226FE8B"),
                        _ => panic!("Bad query: {}:{}", key, value),
                    }
                }
            } else {
                panic!("Expected query string");
            }

            Ok(Response::new(Body::from(RESPONSE)))
        },
        (Method::POST, "/pks/add") => {
            let b = hyper::body::to_bytes(body).await?;

            for (key, value) in url::form_urlencoded::parse(b.as_ref()) {
                match key.clone().into_owned().as_ref() {
                    "keytext" => {
			let key = Cert::from_reader(
                            Reader::new(Cursor::new(value.into_owned()),
                                        None)).unwrap();
                        assert_eq!(
                            key.fingerprint(),
                            FP.parse()
                                .unwrap());
                    },
                    _ => panic!("Bad post: {}:{}", key, value),
                }
	    }

            Ok(Response::new(Body::from("Ok")))
        },
        _ => {
            Ok(Response::builder()
               .status(StatusCode::NOT_FOUND)
               .body(Body::from("Not found")).unwrap())
        },
    }
}

/// Starts a server on a random port.
///
/// Returns the address, a channel to drop() to kill the server, and
/// the thread handle to join the server thread.
fn start_server() -> SocketAddr {
    let (addr, server) = loop {
        let port = OsRng.next_u32() as u16;
        let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port);
        if let Ok(s) = Server::try_bind(&addr) {
            break (addr, s);
        }
    };

    let start_server = server.serve(make_service_fn(|_| async {
        Ok::<_, hyper::Error>(service_fn(service))
    }));
    tokio::spawn(start_server);

    addr
}

#[tokio::test]
async fn get() -> anyhow::Result<()> {
    let ctx = Context::configure()
        .ephemeral()
        .network_policy(NetworkPolicy::Insecure)
        .build()?;

    // Start server.
    let addr = start_server();

    let mut keyserver = KeyServer::new(&ctx, &format!("hkp://{}", addr))?;
    let keyid = ID.parse()?;
    let key = keyserver.get(&keyid).await?;

    assert_eq!(key.fingerprint(),
               FP.parse().unwrap());
    Ok(())
}

#[tokio::test]
async fn send() -> anyhow::Result<()> {
    let ctx = Context::configure()
        .ephemeral()
        .network_policy(NetworkPolicy::Insecure)
        .build()?;

    // Start server.
    let addr = start_server();
    eprintln!("{}", format!("hkp://{}", addr));
    let mut keyserver =
        KeyServer::new(&ctx, &format!("hkp://{}", addr))?;
    let key = Cert::from_reader(Reader::new(Cursor::new(RESPONSE), None))?;
    keyserver.send(&key).await?;

    Ok(())
}