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
//! This example uses the asynchronous proxy instances.
//!
//! The client configuration must be passed as a string blob, including any certificates/keys inline (PEM format). A basic username/password authentication handler is also included.
//!

use async_std::task;

static CONFIG_STR: &str = "
client
dev tun
persist-tun
persist-key
proto udp
remote my-server 1194
resolv-retry infinite
<ca>
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
</ca>
<cert>
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
</cert>
<key>
-----BEGIN PRIVATE KEY-----
-----END PRIVATE KEY-----
</key>
<tls-auth>
-----BEGIN OpenVPN Static key V1-----
-----END OpenVPN Static key V1-----
</tls-auth>
key-direction 1
remote-cert-tls server
auth-user-pass
pull
";

fn main() {
    task::block_on(async {
        let connection = zbus::Connection::system().await.unwrap();
        let config_manager = openvpn3_rs::ConfigurationProxy::new(&connection)
            .await
            .unwrap();
        let config = config_manager
            .import("My VPN", CONFIG_STR, true, false)
            .await
            .unwrap();

        let sessions_manager = openvpn3_rs::SessionsProxy::new(&connection).await.unwrap();
        let session = sessions_manager.new_tunnel(&config.path()).await.unwrap();

        let mut ready = false;
        while !ready {
            // If the session is ready, the `ready()` method will return Ok(), otherwise an error will be returned with more details.
            if let Err(err) = session.ready().await {
                let err_str = err.to_string();
                if err_str.contains("Missing user credentials") {
                    // This loop queries the session for which credentials are needed. This example covers username/password authentication.

                    let ui_type_group = session.user_input_queue_get_type_group().await.unwrap();

                    for (ca_type, ca_group) in ui_type_group {
                        let ui_queue_ids = session
                            .user_input_queue_check(ca_type, ca_group)
                            .await
                            .unwrap();

                        for id in ui_queue_ids {
                            let (ca_type, ca_group, id, name, _description, _hidden_input) =
                                session
                                    .user_input_queue_fetch(ca_type, ca_group, id)
                                    .await
                                    .unwrap();

                            if name == "username" {
                                session
                                    .user_input_provide(ca_type, ca_group, id, "smith")
                                    .await
                                    .unwrap();
                            }

                            if name == "password" {
                                session
                                    .user_input_provide(ca_type, ca_group, id, "hunter2")
                                    .await
                                    .unwrap();
                            }
                        }
                    }
                } else if err_str.contains("Backend VPN process is not ready") {
                    task::sleep(std::time::Duration::from_secs(1)).await;
                }
            } else {
                ready = true;
            }
        }

        session.connect().await.unwrap();

        // wait for signal to disconnect

        session.disconnect().await.unwrap();
    });
}