1use chrono::Duration;
2use relay_auth::{
3 generate_key_pair, generate_relay_id, PublicKey, RegisterRequest, RegisterResponse, RelayId,
4 RelayVersion, SecretKey,
5};
6use serde::Serialize;
7
8use crate::core::{RelayBuf, RelayStr, RelayUuid};
9
10pub struct RelayPublicKey;
12
13pub struct RelaySecretKey;
15
16#[repr(C)]
18pub struct RelayKeyPair {
19 pub public_key: *mut RelayPublicKey,
21 pub secret_key: *mut RelaySecretKey,
23}
24
25pub struct RelayRegisterRequest;
27
28#[no_mangle]
30#[relay_ffi::catch_unwind]
31pub unsafe extern "C" fn relay_publickey_parse(s: *const RelayStr) -> *mut RelayPublicKey {
32 let public_key: PublicKey = (*s).as_str().parse()?;
33 Box::into_raw(Box::new(public_key)) as *mut RelayPublicKey
34}
35
36#[no_mangle]
38#[relay_ffi::catch_unwind]
39pub unsafe extern "C" fn relay_publickey_free(spk: *mut RelayPublicKey) {
40 if !spk.is_null() {
41 let pk = spk as *mut PublicKey;
42 let _dropped = Box::from_raw(pk);
43 }
44}
45
46#[no_mangle]
48#[relay_ffi::catch_unwind]
49pub unsafe extern "C" fn relay_publickey_to_string(spk: *const RelayPublicKey) -> RelayStr {
50 let pk = spk as *const PublicKey;
51 RelayStr::from_string((*pk).to_string())
52}
53
54#[no_mangle]
56#[relay_ffi::catch_unwind]
57pub unsafe extern "C" fn relay_publickey_verify(
58 spk: *const RelayPublicKey,
59 data: *const RelayBuf,
60 sig: *const RelayStr,
61) -> bool {
62 let pk = spk as *const PublicKey;
63 (*pk).verify((*data).as_bytes(), (*sig).as_str())
64}
65
66#[no_mangle]
68#[relay_ffi::catch_unwind]
69pub unsafe extern "C" fn relay_publickey_verify_timestamp(
70 spk: *const RelayPublicKey,
71 data: *const RelayBuf,
72 sig: *const RelayStr,
73 max_age: u32,
74) -> bool {
75 let pk = spk as *const PublicKey;
76 let max_age = Some(Duration::seconds(i64::from(max_age)));
77 (*pk).verify_timestamp((*data).as_bytes(), (*sig).as_str(), max_age)
78}
79
80#[no_mangle]
82#[relay_ffi::catch_unwind]
83pub unsafe extern "C" fn relay_secretkey_parse(s: &RelayStr) -> *mut RelaySecretKey {
84 let secret_key: SecretKey = s.as_str().parse()?;
85 Box::into_raw(Box::new(secret_key)) as *mut RelaySecretKey
86}
87
88#[no_mangle]
90#[relay_ffi::catch_unwind]
91pub unsafe extern "C" fn relay_secretkey_free(spk: *mut RelaySecretKey) {
92 if !spk.is_null() {
93 let pk = spk as *mut SecretKey;
94 let _dropped = Box::from_raw(pk);
95 }
96}
97
98#[no_mangle]
100#[relay_ffi::catch_unwind]
101pub unsafe extern "C" fn relay_secretkey_to_string(spk: *const RelaySecretKey) -> RelayStr {
102 let pk = spk as *const SecretKey;
103 RelayStr::from_string((*pk).to_string())
104}
105
106#[no_mangle]
108#[relay_ffi::catch_unwind]
109pub unsafe extern "C" fn relay_secretkey_sign(
110 spk: *const RelaySecretKey,
111 data: *const RelayBuf,
112) -> RelayStr {
113 let pk = spk as *const SecretKey;
114 RelayStr::from_string((*pk).sign((*data).as_bytes()))
115}
116
117#[no_mangle]
119#[relay_ffi::catch_unwind]
120pub unsafe extern "C" fn relay_generate_key_pair() -> RelayKeyPair {
121 let (sk, pk) = generate_key_pair();
122 RelayKeyPair {
123 secret_key: Box::into_raw(Box::new(sk)) as *mut RelaySecretKey,
124 public_key: Box::into_raw(Box::new(pk)) as *mut RelayPublicKey,
125 }
126}
127
128#[no_mangle]
130#[relay_ffi::catch_unwind]
131pub unsafe extern "C" fn relay_generate_relay_id() -> RelayUuid {
132 let relay_id = generate_relay_id();
133 RelayUuid::new(relay_id)
134}
135
136#[no_mangle]
138#[relay_ffi::catch_unwind]
139pub unsafe extern "C" fn relay_create_register_challenge(
140 data: *const RelayBuf,
141 signature: *const RelayStr,
142 secret: *const RelayStr,
143 max_age: u32,
144) -> RelayStr {
145 let max_age = match max_age {
146 0 => None,
147 m => Some(Duration::seconds(i64::from(m))),
148 };
149
150 let req =
151 RegisterRequest::bootstrap_unpack((*data).as_bytes(), (*signature).as_str(), max_age)?;
152
153 let challenge = req.into_challenge((*secret).as_str().as_bytes());
154 RelayStr::from_string(serde_json::to_string(&challenge)?)
155}
156
157#[derive(Serialize)]
158struct RelayRegisterResponse<'a> {
159 pub relay_id: RelayId,
160 pub token: &'a str,
161 pub public_key: &'a PublicKey,
162 pub version: RelayVersion,
163}
164
165#[no_mangle]
167#[relay_ffi::catch_unwind]
168pub unsafe extern "C" fn relay_validate_register_response(
169 data: *const RelayBuf,
170 signature: *const RelayStr,
171 secret: *const RelayStr,
172 max_age: u32,
173) -> RelayStr {
174 let max_age = match max_age {
175 0 => None,
176 m => Some(Duration::seconds(i64::from(m))),
177 };
178
179 let (response, state) = RegisterResponse::unpack(
180 (*data).as_bytes(),
181 (*signature).as_str(),
182 (*secret).as_str().as_bytes(),
183 max_age,
184 )?;
185
186 let relay_response = RelayRegisterResponse {
187 relay_id: response.relay_id(),
188 token: response.token(),
189 public_key: state.public_key(),
190 version: response.version(),
191 };
192
193 let json = serde_json::to_string(&relay_response)?;
194 RelayStr::from_string(json)
195}
196
197#[no_mangle]
199#[relay_ffi::catch_unwind]
200pub unsafe extern "C" fn relay_version_supported(version: &RelayStr) -> bool {
201 let relay_version = match version.as_str() {
202 "" => RelayVersion::default(),
203 s => s.parse::<RelayVersion>()?,
204 };
205
206 relay_version.supported()
207}