12
12
// See the License for the specific language governing permissions and
13
13
// limitations under the License.
14
14
use crypto:: identity:: MixIdentityPublicKey ;
15
+ use models:: Topology ;
15
16
use nymsphinx:: addressing:: nodes:: NymNodeRoutingAddress ;
16
17
use nymsphinx:: chunking:: split_and_prepare_payloads;
18
+ use nymsphinx:: Node as SphinxNode ;
17
19
use nymsphinx:: {
18
- delays, Destination , DestinationAddressBytes , Node , NodeAddressBytes , SphinxPacket ,
19
- IDENTIFIER_LENGTH ,
20
+ delays, Destination , DestinationAddressBytes , NodeAddressBytes , SphinxPacket , IDENTIFIER_LENGTH ,
20
21
} ;
21
22
use serde:: { Deserialize , Serialize } ;
22
- use serde_json;
23
23
use std:: convert:: TryFrom ;
24
24
use std:: convert:: TryInto ;
25
25
use std:: net:: SocketAddr ;
26
26
use std:: time:: Duration ;
27
+ use topology:: provider:: Node as TopologyNode ;
27
28
use wasm_bindgen:: prelude:: * ;
28
29
30
+ mod models;
29
31
mod utils;
30
32
31
33
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
@@ -53,10 +55,10 @@ pub struct NodeData {
53
55
/// Message chunking is currently not implemented. If the message exceeds the
54
56
/// capacity of a single Sphinx packet, the extra information will be discarded.
55
57
#[ wasm_bindgen]
56
- pub fn create_sphinx_packet ( raw_route : & str , msg : & str , destination : & str ) -> Vec < u8 > {
58
+ pub fn create_sphinx_packet ( topology_json : & str , msg : & str , destination : & str ) -> Vec < u8 > {
57
59
utils:: set_panic_hook ( ) ; // nicer js errors.
58
60
59
- let route = sphinx_route_from ( raw_route ) ;
61
+ let route = sphinx_route_from ( topology_json ) ;
60
62
61
63
let average_delay = Duration :: from_secs_f64 ( 0.1 ) ;
62
64
let delays = delays:: generate_from_average_duration ( route. len ( ) , average_delay) ;
@@ -76,7 +78,7 @@ pub fn create_sphinx_packet(raw_route: &str, msg: &str, destination: &str) -> Ve
76
78
/// it should send a packet it receives. So we prepend the packet with the
77
79
/// address bytes of the first mix inside the packet, so that the gateway can
78
80
/// forward the packet to it.
79
- fn payload ( sphinx_packet : SphinxPacket , route : Vec < Node > ) -> Vec < u8 > {
81
+ fn payload ( sphinx_packet : SphinxPacket , route : Vec < SphinxNode > ) -> Vec < u8 > {
80
82
let packet = sphinx_packet. to_bytes ( ) ;
81
83
let first_mix_address = route. first ( ) . unwrap ( ) . clone ( ) . address . to_bytes ( ) . to_vec ( ) ;
82
84
@@ -93,29 +95,16 @@ fn payload(sphinx_packet: SphinxPacket, route: Vec<Node>) -> Vec<u8> {
93
95
///
94
96
/// This function panics if the supplied `raw_route` json string can't be
95
97
/// extracted to a `JsonRoute`.
96
- ///
97
- /// # Panics
98
- ///
99
- /// This function panics if `JsonRoute.nodes` doesn't contain at least 1
100
- /// node.
101
- ///
102
- fn sphinx_route_from ( raw_route : & str ) -> Vec < Node > {
103
- let json_route: JsonRoute = serde_json:: from_str ( raw_route) . unwrap ( ) ;
104
-
105
- assert ! (
106
- json_route. nodes. len( ) > 0 ,
107
- "Sphinx packet must route to at least one mixnode."
108
- ) ;
109
-
110
- let mut sphinx_route: Vec < Node > = vec ! [ ] ;
111
- for node_data in json_route. nodes . iter ( ) {
112
- let x = Node :: try_from ( node_data. clone ( ) ) . expect ( "Malformed NodeData" ) ;
113
- sphinx_route. push ( x) ;
114
- }
115
- sphinx_route
98
+ fn sphinx_route_from ( topology_json : & str ) -> Vec < SphinxNode > {
99
+ let topology = Topology :: new ( topology_json) ;
100
+ let p: TopologyNode = topology. providers ( ) . first ( ) . unwrap ( ) . to_owned ( ) ;
101
+ let provider = p. into ( ) ;
102
+ let route = topology. route_to ( provider) . unwrap ( ) ;
103
+ assert_eq ! ( 4 , route. len( ) ) ;
104
+ route
116
105
}
117
106
118
- impl TryFrom < NodeData > for Node {
107
+ impl TryFrom < NodeData > for SphinxNode {
119
108
type Error = ( ) ;
120
109
121
110
fn try_from ( node_data : NodeData ) -> Result < Self , Self :: Error > {
@@ -130,6 +119,162 @@ impl TryFrom<NodeData> for Node {
130
119
nymsphinx:: key:: new ( dest)
131
120
} ;
132
121
133
- Ok ( Node { address, pub_key } )
122
+ Ok ( SphinxNode { address, pub_key } )
134
123
}
135
124
}
125
+
126
+ #[ cfg( test) ]
127
+ mod test_constructing_a_sphinx_packet {
128
+ use super :: * ;
129
+ #[ test]
130
+ fn produces_1404_bytes ( ) {
131
+ // 32 byte address + 1372 byte sphinx packet
132
+ let packet = create_sphinx_packet (
133
+ topology_fixture ( ) ,
134
+ "foomp" ,
135
+ "AetTDvynUNB2N35rvCVDxkPR593Cx4PCe4QQKrMgm5RR" ,
136
+ ) ;
137
+ assert_eq ! ( 1404 , packet. len( ) ) ;
138
+ }
139
+
140
+ #[ test]
141
+ fn starts_with_a_mix_address ( ) {
142
+ let mut payload = create_sphinx_packet (
143
+ topology_fixture ( ) ,
144
+ "foomp" ,
145
+ "AetTDvynUNB2N35rvCVDxkPR593Cx4PCe4QQKrMgm5RR" ,
146
+ ) ;
147
+ let mut address_buffer = [ 0 ; 32 ] ;
148
+ let _ = payload. split_off ( 32 ) ;
149
+ address_buffer. copy_from_slice ( payload. as_slice ( ) ) ;
150
+ let address = NymNodeRoutingAddress :: try_from_bytes ( & address_buffer) ;
151
+
152
+ assert ! ( address. is_ok( ) ) ;
153
+ }
154
+ }
155
+
156
+ #[ cfg( test) ]
157
+ mod building_a_topology_from_json {
158
+ use super :: * ;
159
+
160
+ #[ test]
161
+ #[ should_panic]
162
+ fn panics_on_empty_string ( ) {
163
+ sphinx_route_from ( "" ) ;
164
+ }
165
+
166
+ #[ test]
167
+ #[ should_panic]
168
+ fn panics_on_bad_json ( ) {
169
+ sphinx_route_from ( "bad bad bad not json" ) ;
170
+ }
171
+
172
+ #[ test]
173
+ #[ should_panic]
174
+ fn panics_when_there_are_no_mixnodes ( ) {
175
+ let mut topology: Topology = serde_json:: from_str ( topology_fixture ( ) ) . unwrap ( ) ;
176
+ topology. mix_nodes = vec ! [ ] ;
177
+ let json = serde_json:: to_string ( & topology) . unwrap ( ) ;
178
+ sphinx_route_from ( & json) ;
179
+ }
180
+
181
+ #[ test]
182
+ #[ should_panic]
183
+ fn panics_when_there_are_not_enough_mixnodes ( ) {
184
+ let mut topology: Topology = serde_json:: from_str ( topology_fixture ( ) ) . unwrap ( ) ;
185
+ let node = topology. mix_nodes . first ( ) . unwrap ( ) . clone ( ) ;
186
+ topology. mix_nodes = vec ! [ node] ; // 1 mixnode isn't enough. Panic!
187
+ let json = serde_json:: to_string ( & topology) . unwrap ( ) ;
188
+ sphinx_route_from ( & json) ;
189
+ }
190
+
191
+ #[ test]
192
+ fn test_works_on_happy_json ( ) {
193
+ let route = sphinx_route_from ( topology_fixture ( ) ) ;
194
+ assert_eq ! ( 4 , route. len( ) ) ;
195
+ }
196
+ }
197
+
198
+ #[ cfg( test) ]
199
+ fn topology_fixture ( ) -> & ' static str {
200
+ let json = r#"
201
+ {
202
+ "cocoNodes": [],
203
+ "mixNodes": [
204
+ {
205
+ "host": "nym.300baud.de:1789",
206
+ "pubKey": "AetTDvynUNB2N35rvCVDxkPR593Cx4PCe4QQKrMgm5RR",
207
+ "version": "0.6.0",
208
+ "location": "Falkenstein, DE",
209
+ "layer": 3,
210
+ "lastSeen": 1587572945877713700
211
+ },
212
+ {
213
+ "host": "testnet_nymmixnode.roussel-zeter.eu:1789",
214
+ "pubKey": "9wJ3zLoyat41e4ZgT1AWeueExv5c6uwnjvkRepj8Ebis",
215
+ "version": "0.6.0",
216
+ "location": "Geneva, CH",
217
+ "layer": 3,
218
+ "lastSeen": 1587572945907250400
219
+ },
220
+ {
221
+ "host": "185.144.83.134:1789",
222
+ "pubKey": "59tCzpCYsiKXz89rtvNiEYwQDdkseSShPEkifQXhsCgA",
223
+ "version": "0.6.0",
224
+ "location": "Bucharest",
225
+ "layer": 1,
226
+ "lastSeen": 1587572946007431400
227
+ },
228
+ {
229
+ "host": "[2a0a:e5c0:2:2:0:c8ff:fe68:bf6b]:1789",
230
+ "pubKey": "J9f9uS1hN8iwcN2STqH55fPRYqt7McEPyhNzpTYsxNdG",
231
+ "version": "0.6.0",
232
+ "location": "Glarus",
233
+ "layer": 1,
234
+ "lastSeen": 1587572945920982000
235
+ },
236
+ {
237
+ "host": "[2a0a:e5c0:2:2:0:c8ff:fe68:bf6b]:1789",
238
+ "pubKey": "J9f9uS1hN8iwcN2STqH55fPRYqt7McEPyhNzpTYsxNdG",
239
+ "version": "0.6.0",
240
+ "location": "Glarus",
241
+ "layer": 2,
242
+ "lastSeen": 1587572945920982000
243
+ },
244
+ {
245
+ "host": "[2a0a:e5c0:2:2:0:c8ff:fe68:bf6b]:1789",
246
+ "pubKey": "J9f9uS1hN8iwcN2STqH55fPRYqt7McEPyhNzpTYsxNdG",
247
+ "version": "0.6.0",
248
+ "location": "Glarus",
249
+ "layer": 2,
250
+ "lastSeen": 1587572945920982000
251
+ }
252
+ ],
253
+ "mixProviderNodes": [
254
+ {
255
+ "clientListener": "139.162.246.48:9000",
256
+ "mixnetListener": "139.162.246.48:1789",
257
+ "pubKey": "7vhgER4Gz789QHNTSu4apMpTcpTuUaRiLxJnbz1g2HFh",
258
+ "version": "0.6.0",
259
+ "location": "London, UK",
260
+ "registeredClients": [
261
+ {
262
+ "pubKey": "5pgrc4gPHP2tBQgfezcdJ2ZAjipoAsy6evrqHdxBbVXq"
263
+ }
264
+ ],
265
+ "lastSeen": 1587572946261865200
266
+ },
267
+ {
268
+ "clientListener": "127.0.0.1:9000",
269
+ "mixnetListener": "127.0.0.1:1789",
270
+ "pubKey": "2XK8RDcUTRcJLUWoDfoXc2uP4YViscMLEM5NSzhSi87M",
271
+ "version": "0.6.0",
272
+ "location": "unknown",
273
+ "registeredClients": [],
274
+ "lastSeen": 1587572946304564700
275
+ }
276
+ ]
277
+ }
278
+ "# ;
279
+ json
280
+ }
0 commit comments