1
- use async_std:: task;
2
1
use chrono:: Utc ;
3
2
use diesel:: {
4
3
connection:: SimpleConnection ,
5
4
r2d2:: { ConnectionManager , Pool } ,
6
5
SqliteConnection ,
7
6
} ;
8
7
use diesel_migrations:: { embed_migrations, EmbeddedMigrations , MigrationHarness } ;
9
- use sha2 :: Digest ;
10
- use std:: { borrow:: Cow , error:: Error , fs, io, iter, time:: Duration } ;
8
+ use rand :: distributions :: { Alphanumeric , DistString } ;
9
+ use std:: { borrow:: Cow , collections :: HashMap , error:: Error , fs, io, iter, time:: Duration } ;
11
10
12
11
use directories:: ProjectDirs ;
13
12
use futures:: {
14
13
channel:: { mpsc, oneshot} ,
15
- select, FutureExt , SinkExt , StreamExt ,
14
+ select, StreamExt ,
16
15
} ;
17
16
use libp2p:: {
18
17
core:: upgrade:: Version ,
@@ -34,16 +33,17 @@ use crate::{
34
33
BitmessageBehaviourEvent , BitmessageNetBehaviour , BitmessageProtocol ,
35
34
BitmessageProtocolCodec , BitmessageResponse ,
36
35
} ,
37
- messages:: { self , MessageCommand , MessagePayload , ObjectKind , UnencryptedMsg } ,
36
+ messages:: { self , MessageCommand , MessagePayload , MsgEncoding , ObjectKind , UnencryptedMsg } ,
38
37
} ,
39
- pow,
40
38
repositories:: {
41
39
address:: AddressRepositorySync ,
42
40
inventory:: InventoryRepositorySync ,
43
41
message:: MessageRepositorySync ,
44
42
sqlite:: {
45
- address:: SqliteAddressRepository , inventory:: SqliteInventoryRepository ,
46
- message:: SqliteMessageRepository , models,
43
+ address:: SqliteAddressRepository ,
44
+ inventory:: SqliteInventoryRepository ,
45
+ message:: SqliteMessageRepository ,
46
+ models:: { self , MessageStatus } ,
47
47
} ,
48
48
} ,
49
49
} ;
@@ -135,6 +135,7 @@ pub enum WorkerCommand {
135
135
} ,
136
136
SendMessage {
137
137
msg : models:: Message ,
138
+ from : String ,
138
139
sender : oneshot:: Sender < Result < ( ) , DynError > > ,
139
140
} ,
140
141
}
@@ -143,7 +144,12 @@ pub struct NodeWorker {
143
144
local_peer_id : PeerId ,
144
145
swarm : Swarm < BitmessageNetBehaviour > ,
145
146
handler : Handler ,
147
+ command_sender : mpsc:: Sender < WorkerCommand > ,
146
148
command_receiver : mpsc:: Receiver < WorkerCommand > ,
149
+
150
+ pubkey_notifier : mpsc:: Receiver < String > ,
151
+ tracked_pubkeys : HashMap < String , bool > , // TODO populate it on startup
152
+
147
153
pending_commands : Vec < WorkerCommand > ,
148
154
_sqlite_connection_pool : Pool < ConnectionManager < SqliteConnection > > ,
149
155
common_topic : Sha256Topic ,
@@ -251,6 +257,7 @@ impl NodeWorker {
251
257
. expect ( "subscription not to fail" ) ;
252
258
253
259
let ( sender, receiver) = mpsc:: channel ( 0 ) ;
260
+ let ( pubkey_notifier_sink, pubkey_notifier) = mpsc:: channel ( 0 ) ;
254
261
let inventory_repo = Box :: new ( SqliteInventoryRepository :: new ( pool. clone ( ) ) ) ;
255
262
let address_repo = Box :: new ( SqliteAddressRepository :: new ( pool. clone ( ) ) ) ;
256
263
let message_repo = Box :: new ( SqliteMessageRepository :: new ( pool. clone ( ) ) ) ;
@@ -263,7 +270,11 @@ impl NodeWorker {
263
270
inventory_repo. clone ( ) ,
264
271
message_repo. clone ( ) ,
265
272
sender. clone ( ) ,
273
+ pubkey_notifier_sink,
266
274
) ,
275
+ command_sender : sender. clone ( ) ,
276
+ pubkey_notifier,
277
+ tracked_pubkeys : HashMap :: new ( ) ,
267
278
command_receiver : receiver,
268
279
pending_commands : Vec :: new ( ) ,
269
280
_sqlite_connection_pool : pool,
@@ -384,6 +395,18 @@ impl NodeWorker {
384
395
. expect ( "receiver not to be dropped" ) ,
385
396
} ,
386
397
WorkerCommand :: NonceCalculated { obj } => {
398
+ match & obj. kind {
399
+ ObjectKind :: Msg { encrypted : _ } => self
400
+ . messages_repo
401
+ . update_message_status (
402
+ bs58:: encode ( & obj. hash ) . into_string ( ) ,
403
+ MessageStatus :: Sent ,
404
+ )
405
+ . await
406
+ . unwrap ( ) ,
407
+ _ => { }
408
+ }
409
+
387
410
self . inventory_repo
388
411
. store_object ( bs58:: encode ( & obj. hash ) . into_string ( ) , obj)
389
412
. await
@@ -468,7 +491,71 @@ impl NodeWorker {
468
491
. expect ( "receiver not to be dropped" ) ,
469
492
} ,
470
493
} ,
471
- WorkerCommand :: SendMessage { msg, sender } => { }
494
+ WorkerCommand :: SendMessage {
495
+ mut msg,
496
+ from,
497
+ sender,
498
+ } => {
499
+ let identity = self
500
+ . address_repo
501
+ . get_by_ripe_or_tag ( from)
502
+ . await
503
+ . unwrap ( )
504
+ . unwrap ( ) ;
505
+ let recipient: Option < Address > = self
506
+ . address_repo
507
+ . get_by_ripe_or_tag ( msg. recipient . clone ( ) )
508
+ . await
509
+ . unwrap ( ) ;
510
+ match recipient {
511
+ Some ( v) => {
512
+ msg. status = MessageStatus :: WaitingForPOW . to_string ( ) ;
513
+ let unenc_msg = UnencryptedMsg {
514
+ behavior_bitfield : 0 ,
515
+ sender_ripe : msg. sender . clone ( ) ,
516
+ destination_ripe : msg. recipient . clone ( ) ,
517
+ encoding : MsgEncoding :: Simple ,
518
+ message : msg. data . clone ( ) ,
519
+ public_encryption_key : v
520
+ . public_encryption_key
521
+ . unwrap ( )
522
+ . serialize ( )
523
+ . to_vec ( ) ,
524
+ public_signing_key : v. public_signing_key . unwrap ( ) . serialize ( ) . to_vec ( ) ,
525
+ } ;
526
+ let encrypted = Self :: serialize_and_encrypt_payload_pub (
527
+ unenc_msg,
528
+ & v. public_encryption_key . unwrap ( ) ,
529
+ ) ;
530
+ let object = messages:: Object :: with_signing (
531
+ & identity,
532
+ ObjectKind :: Msg { encrypted } ,
533
+ Utc :: now ( ) + chrono:: Duration :: days ( 7 ) ,
534
+ ) ;
535
+
536
+ msg. hash = bs58:: encode ( & object. hash ) . into_string ( ) ;
537
+ self . messages_repo . save_model ( msg. clone ( ) ) . await . unwrap ( ) ;
538
+ object. do_proof_of_work ( self . command_sender . clone ( ) ) ;
539
+ }
540
+ None => {
541
+ msg. status = MessageStatus :: WaitingForPubkey . to_string ( ) ;
542
+ // we generate random hash value, cuz we don't really know real hash value of the message at the moment, and it's not that important
543
+ msg. hash = Alphanumeric . sample_string ( & mut rand:: thread_rng ( ) , 16 ) ;
544
+ self . messages_repo . save_model ( msg. clone ( ) ) . await . unwrap ( ) ;
545
+ // send getpubkey request
546
+ let obj = messages:: Object :: with_signing (
547
+ & identity,
548
+ ObjectKind :: Getpubkey {
549
+ tag : Address :: new ( bs58:: decode ( msg. recipient ) . into_vec ( ) . unwrap ( ) )
550
+ . tag ,
551
+ } ,
552
+ Utc :: now ( ) + chrono:: Duration :: days ( 7 ) ,
553
+ ) ;
554
+ obj. do_proof_of_work ( self . command_sender . clone ( ) ) ;
555
+ }
556
+ }
557
+ sender. send ( Ok ( ( ) ) ) . unwrap ( ) ;
558
+ }
472
559
} ;
473
560
}
474
561
@@ -492,11 +579,18 @@ impl NodeWorker {
492
579
log:: debug!( "Shutting down network event loop..." ) ;
493
580
return ;
494
581
} ,
495
- }
582
+ } ,
583
+ pubkey_notification = self . pubkey_notifier. next( ) => self . handle_pubkey_notification( pubkey_notification. unwrap( ) ) . await ,
496
584
}
497
585
}
498
586
}
499
587
588
+ async fn handle_pubkey_notification ( & mut self , tag : String ) {
589
+ if let Some ( _) = self . tracked_pubkeys . get ( & tag) {
590
+ // TODO seek for messages which haven't been sent yet because of empty public key of recipient
591
+ }
592
+ }
593
+
500
594
/// When we receive IdentityInfo, if the peer supports our Kademlia protocol, we add
501
595
/// their listen addresses to the DHT, so they will be propagated to other peers.
502
596
fn handle_identify_event ( & mut self , identify_event : identify:: Event ) {
@@ -541,6 +635,21 @@ impl NodeWorker {
541
635
. unwrap ( ) ;
542
636
encrypted
543
637
}
638
+
639
+ pub fn serialize_and_encrypt_payload_pub < T > (
640
+ object : T ,
641
+ public_key : & libsecp256k1:: PublicKey ,
642
+ ) -> Vec < u8 >
643
+ where
644
+ T : Serialize ,
645
+ {
646
+ let encrypted = ecies:: encrypt (
647
+ & public_key. serialize ( ) ,
648
+ serde_cbor:: to_vec ( & object) . unwrap ( ) . as_ref ( ) ,
649
+ )
650
+ . unwrap ( ) ;
651
+ encrypted
652
+ }
544
653
}
545
654
546
655
fn extract_peer_id_from_multiaddr (
0 commit comments