1#![deny(unsafe_code)]
7#![warn(missing_docs)]
8
9use std::{
10 collections::HashMap,
11 convert::{TryFrom, TryInto},
12 fmt, io,
13 os::raw::c_int,
14};
15
16use log::debug;
17
18use koibumi_core::{
19 address::{Address, Error as AddressError, ParseError as ParseAddressError},
20 crypto::{PrivateKey, PrivateKeyError},
21 encoding::{self, Encoding},
22 identity::{Features, Private as PrivateIdentity},
23 io::{SizedReadFromExact, WriteTo},
24 message::{self, InvHash},
25 object,
26 pow::{NonceTrialsPerByte, PayloadLengthExtraBytes},
27 time::Time,
28};
29use koibumi_node::db;
30
31const SQLITE_CONSTRAINT_PRIMARYKEY: c_int = 1555;
32
33const SUBSCRIBERS: &str = "(Subscribers)";
34
35#[derive(Debug)]
37pub enum Error {
38 SqlxError(sqlx::Error),
41 TagMismatch,
43 AddressError(AddressError),
45 ParseAddressError(ParseAddressError),
48 TryIntoMsgError(object::TryIntoMsgError),
51 TryIntoBroadcastError(object::TryIntoBroadcastError),
54 DecryptError(object::DecryptError),
57 TryIntoMessageError(TryIntoMessageError),
60 AlreadyExists,
62 NotExists,
64 InvalidIdentity,
66 TryIntoPrivateKeysError(TryIntoPrivateKeysError),
68}
69
70impl fmt::Display for Error {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 match self {
73 Self::SqlxError(err) => err.fmt(f),
74 Self::TagMismatch => "tag mismatch".fmt(f),
75 Self::AddressError(err) => err.fmt(f),
76 Self::ParseAddressError(err) => err.fmt(f),
77 Self::TryIntoMsgError(err) => err.fmt(f),
78 Self::TryIntoBroadcastError(err) => err.fmt(f),
79 Self::DecryptError(err) => err.fmt(f),
80 Self::TryIntoMessageError(err) => err.fmt(f),
81 Self::AlreadyExists => "already exists".fmt(f),
82 Self::NotExists => "not exists".fmt(f),
83 Self::InvalidIdentity => "invalid identity".fmt(f),
84 Self::TryIntoPrivateKeysError(err) => err.fmt(f),
85 }
86 }
87}
88
89impl std::error::Error for Error {}
90
91impl From<sqlx::Error> for Error {
92 fn from(err: sqlx::Error) -> Self {
93 Self::SqlxError(err)
94 }
95}
96
97impl From<AddressError> for Error {
98 fn from(err: AddressError) -> Self {
99 Self::AddressError(err)
100 }
101}
102
103impl From<ParseAddressError> for Error {
104 fn from(err: ParseAddressError) -> Self {
105 Self::ParseAddressError(err)
106 }
107}
108
109impl From<object::TryIntoMsgError> for Error {
110 fn from(err: object::TryIntoMsgError) -> Self {
111 Self::TryIntoMsgError(err)
112 }
113}
114
115impl From<object::TryIntoBroadcastError> for Error {
116 fn from(err: object::TryIntoBroadcastError) -> Self {
117 Self::TryIntoBroadcastError(err)
118 }
119}
120
121impl From<object::DecryptError> for Error {
122 fn from(err: object::DecryptError) -> Self {
123 Self::DecryptError(err)
124 }
125}
126
127impl From<TryIntoMessageError> for Error {
128 fn from(err: TryIntoMessageError) -> Self {
129 Self::TryIntoMessageError(err)
130 }
131}
132
133impl From<TryIntoPrivateKeysError> for Error {
134 fn from(err: TryIntoPrivateKeysError) -> Self {
135 Self::TryIntoPrivateKeysError(err)
136 }
137}
138
139#[derive(Clone, PartialEq, Eq, Debug)]
141pub struct Contact {
142 address: Address,
143}
144
145impl Contact {
146 pub fn new(address: Address) -> Self {
148 Self { address }
149 }
150
151 pub fn address(&self) -> &Address {
153 &self.address
154 }
155}
156
157#[derive(Clone, PartialEq, Eq, Debug)]
159pub struct User {
160 id: Vec<u8>,
161 subscriptions: Vec<Address>,
162 private_identities: Vec<PrivateIdentity>,
163 contacts: Vec<Contact>,
164 aliases: HashMap<String, String>,
165}
166
167impl User {
168 pub fn id(&self) -> &[u8] {
170 &self.id
171 }
172
173 pub fn subscriptions(&self) -> &[Address] {
175 &self.subscriptions
176 }
177
178 pub fn subscriptions_mut(&mut self) -> &mut Vec<Address> {
180 &mut self.subscriptions
181 }
182
183 pub fn private_identities(&self) -> &[PrivateIdentity] {
185 &self.private_identities
186 }
187
188 pub fn private_identities_mut(&mut self) -> &mut Vec<PrivateIdentity> {
190 &mut self.private_identities
191 }
192
193 pub fn private_identity_by_address(&self, address: &Address) -> Option<&PrivateIdentity> {
195 self.private_identities
196 .iter()
197 .find(|i| &i.address() == address)
198 }
199
200 pub fn contacts(&self) -> &[Contact] {
202 &self.contacts
203 }
204
205 pub fn contacts_mut(&mut self) -> &mut Vec<Contact> {
207 &mut self.contacts
208 }
209
210 pub fn aliases(&self) -> &HashMap<String, String> {
212 &self.aliases
213 }
214
215 pub fn aliases_mut(&mut self) -> &mut HashMap<String, String> {
217 &mut self.aliases
218 }
219
220 pub fn alias<'a>(&'a self, address: &'a str) -> &'a str {
222 match self.aliases.get(address) {
223 Some(alias) => alias,
224 None => address,
225 }
226 }
227
228 pub fn rich_alias(&self, address: &str) -> String {
230 match self.aliases.get(address) {
231 Some(alias) => format!("{} ({})", alias, address),
232 None => address.to_string(),
233 }
234 }
235}
236
237impl From<User> for koibumi_node::User {
238 fn from(user: User) -> Self {
239 Self::new(user.id, user.subscriptions, user.private_identities)
240 }
241}
242
243#[derive(Clone, PartialEq, Eq, Hash, Debug)]
245pub struct Message {
246 user_id: Vec<u8>,
247 object: message::Object,
248 time: Time,
249 to: Option<Address>,
250 from: Address,
251 encoding: Encoding,
252 content: Vec<u8>,
253 subject: String,
254 read: bool,
255}
256
257impl Message {
258 pub fn time(&self) -> Time {
260 self.time
261 }
262
263 pub fn to_address(&self) -> Option<&Address> {
265 self.to.as_ref()
266 }
267
268 pub fn from_address(&self) -> &Address {
270 &self.from
271 }
272
273 pub fn encoding(&self) -> Encoding {
275 self.encoding
276 }
277
278 pub fn content(&self) -> &[u8] {
280 &self.content
281 }
282}
283
284#[derive(Debug)]
286pub enum TryIntoMessageError {
287 IoError(io::Error),
290 ParseAddressError(ParseAddressError),
293 InvalidEncoding(encoding::InvalidEncoding),
296}
297
298impl fmt::Display for TryIntoMessageError {
299 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300 match self {
301 Self::IoError(err) => err.fmt(f),
302 Self::ParseAddressError(err) => err.fmt(f),
303 Self::InvalidEncoding(err) => err.fmt(f),
304 }
305 }
306}
307
308impl std::error::Error for TryIntoMessageError {}
309
310impl From<io::Error> for TryIntoMessageError {
311 fn from(err: io::Error) -> Self {
312 Self::IoError(err)
313 }
314}
315
316impl From<ParseAddressError> for TryIntoMessageError {
317 fn from(err: ParseAddressError) -> Self {
318 Self::ParseAddressError(err)
319 }
320}
321
322impl From<encoding::InvalidEncoding> for TryIntoMessageError {
323 fn from(err: encoding::InvalidEncoding) -> Self {
324 Self::InvalidEncoding(err)
325 }
326}
327
328impl TryFrom<MessageRow> for Message {
329 type Error = TryIntoMessageError;
330
331 fn try_from(value: MessageRow) -> Result<Self, <Self as TryFrom<MessageRow>>::Error> {
332 let object = message::Object::sized_read_from_exact(value.object)?;
333
334 let to = if value.to_address == SUBSCRIBERS {
335 None
336 } else {
337 Some(value.to_address.parse::<Address>()?)
338 };
339
340 let from = value.from_address.parse::<Address>()?;
341
342 let encoding: Encoding = (value.encoding as u64).try_into()?;
343
344 Ok(Self {
345 user_id: value.user,
346 object,
347 time: (value.time as u64).into(),
348 to,
349 from,
350 encoding,
351 content: value.content,
352 subject: value.subject,
353 read: value.read != 0,
354 })
355 }
356}
357
358#[derive(sqlx::FromRow, Clone)]
359struct MessageRow {
360 user: Vec<u8>,
361 object: Vec<u8>,
362 time: i64,
363 to_address: String,
364 from_address: String,
365 encoding: i64,
366 content: Vec<u8>,
367 subject: String,
368 read: i8,
369}
370
371impl From<Message> for MessageRow {
372 fn from(value: Message) -> Self {
373 let mut object = Vec::new();
374 value.object.write_to(&mut object).unwrap();
375
376 let time = if value.time.as_secs() > i64::MAX as u64 {
377 i64::MAX
378 } else {
379 value.time.as_secs() as i64
380 };
381
382 let to_address = if let Some(address) = value.to {
383 address.to_string()
384 } else {
385 SUBSCRIBERS.to_string()
386 };
387
388 Self {
389 user: value.user_id,
390 object,
391 time,
392 to_address,
393 from_address: value.from.to_string(),
394 encoding: value.encoding as i64,
395 content: value.content,
396 subject: value.subject,
397 read: value.read as i8,
398 }
399 }
400}
401
402#[derive(Clone, PartialEq, Eq, Hash, Debug)]
403struct PrivateKeys {
404 user_id: Vec<u8>,
405 enabled: bool,
406 private_identity: PrivateIdentity,
407}
408
409#[derive(sqlx::FromRow, Clone)]
410struct PrivateKeysRow {
411 user: Vec<u8>,
412 address: String,
413 enabled: bool,
414 features: i64,
415 nonce_trials_per_byte: i64,
416 payload_length_extra_bytes: i64,
417 signing_key: Vec<u8>,
418 encryption_key: Vec<u8>,
419 chan: bool,
420}
421
422#[derive(Debug)]
423enum TryIntoPrivateKeysRowError {
424 OutOfRange,
425}
426
427impl fmt::Display for TryIntoPrivateKeysRowError {
428 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
429 match self {
430 Self::OutOfRange => "out of range".fmt(f),
431 }
432 }
433}
434
435impl std::error::Error for TryIntoPrivateKeysRowError {}
436
437impl TryFrom<PrivateKeys> for PrivateKeysRow {
438 type Error = TryIntoPrivateKeysRowError;
439
440 fn try_from(value: PrivateKeys) -> Result<Self, <Self as TryFrom<PrivateKeys>>::Error> {
441 let nonce_trials_per_byte = value.private_identity.nonce_trials_per_byte().as_u64();
442 if nonce_trials_per_byte > i64::MAX as u64 {
443 return Err(TryIntoPrivateKeysRowError::OutOfRange);
444 }
445 let payload_length_extra_bytes =
446 value.private_identity.payload_length_extra_bytes().as_u64();
447 if payload_length_extra_bytes > i64::MAX as u64 {
448 return Err(TryIntoPrivateKeysRowError::OutOfRange);
449 }
450 Ok(Self {
451 user: value.user_id,
452 address: value.private_identity.address().to_string(),
453 enabled: value.enabled,
454 features: value.private_identity.features().bits() as i64,
455 nonce_trials_per_byte: nonce_trials_per_byte as i64,
456 payload_length_extra_bytes: payload_length_extra_bytes as i64,
457 signing_key: value
458 .private_identity
459 .private_signing_key()
460 .as_ref()
461 .to_vec(),
462 encryption_key: value
463 .private_identity
464 .private_encryption_key()
465 .as_ref()
466 .to_vec(),
467 chan: value.private_identity.chan(),
468 })
469 }
470}
471
472#[derive(Debug)]
474pub enum TryIntoPrivateKeysError {
475 OutOfRange,
477 ParseAddressError(ParseAddressError),
479 TryFromSliceError(std::array::TryFromSliceError),
481 PrivateKeyError(PrivateKeyError),
483 AddressError(AddressError),
485}
486
487impl fmt::Display for TryIntoPrivateKeysError {
488 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
489 match self {
490 Self::OutOfRange => "out of range".fmt(f),
491 Self::ParseAddressError(err) => err.fmt(f),
492 Self::TryFromSliceError(err) => err.fmt(f),
493 Self::PrivateKeyError(err) => err.fmt(f),
494 Self::AddressError(err) => err.fmt(f),
495 }
496 }
497}
498
499impl std::error::Error for TryIntoPrivateKeysError {}
500
501impl From<ParseAddressError> for TryIntoPrivateKeysError {
502 fn from(err: ParseAddressError) -> Self {
503 Self::ParseAddressError(err)
504 }
505}
506
507impl From<std::array::TryFromSliceError> for TryIntoPrivateKeysError {
508 fn from(err: std::array::TryFromSliceError) -> Self {
509 Self::TryFromSliceError(err)
510 }
511}
512
513impl From<PrivateKeyError> for TryIntoPrivateKeysError {
514 fn from(err: PrivateKeyError) -> Self {
515 Self::PrivateKeyError(err)
516 }
517}
518
519impl From<AddressError> for TryIntoPrivateKeysError {
520 fn from(err: AddressError) -> Self {
521 Self::AddressError(err)
522 }
523}
524impl TryFrom<PrivateKeysRow> for PrivateKeys {
525 type Error = TryIntoPrivateKeysError;
526
527 fn try_from(value: PrivateKeysRow) -> Result<Self, <Self as TryFrom<PrivateKeysRow>>::Error> {
528 let address = value.address.parse::<Address>()?;
529 if value.features < 0 || value.features > u32::MAX as i64 {
530 return Err(TryIntoPrivateKeysError::OutOfRange);
531 }
532 let features = Features::from_bits_retain(value.features as u32);
533 if value.nonce_trials_per_byte < 0 {
534 return Err(TryIntoPrivateKeysError::OutOfRange);
535 }
536 let nonce_trials_per_byte = NonceTrialsPerByte::from(value.nonce_trials_per_byte as u64);
537 if value.payload_length_extra_bytes < 0 {
538 return Err(TryIntoPrivateKeysError::OutOfRange);
539 }
540 let payload_length_extra_bytes =
541 PayloadLengthExtraBytes::from(value.payload_length_extra_bytes as u64);
542 let bytes: &[u8] = value.signing_key.as_ref();
543 let private_signing_key = PrivateKey::new(bytes.try_into()?)?;
544 let bytes: &[u8] = value.encryption_key.as_ref();
545 let private_encryption_key = PrivateKey::new(bytes.try_into()?)?;
546
547 let private_identity = PrivateIdentity::new(
548 address.version(),
549 address.stream(),
550 features,
551 nonce_trials_per_byte,
552 payload_length_extra_bytes,
553 private_signing_key,
554 private_encryption_key,
555 value.chan,
556 )?;
557 Ok(Self {
558 user_id: value.user,
559 enabled: value.enabled,
560 private_identity,
561 })
562 }
563}
564
565#[derive(Debug)]
567pub struct Manager {
568 pool: db::SqlitePool,
569}
570
571impl Manager {
572 pub async fn new(pool: db::SqlitePool) -> Result<Manager, Error> {
574 sqlx::query(
575 "CREATE TABLE IF NOT EXISTS users (
576 id BLOB NOT NULL PRIMARY KEY,
577 enabled INTEGER NOT NULL,
578 name TEXT NOT NULL
579 )",
580 )
581 .execute(pool.write())
582 .await?;
583
584 sqlx::query(
585 "CREATE TABLE IF NOT EXISTS subscriptions (
586 user BLOB NOT NULL,
587 address TEXT NOT NULL,
588 enabled INTEGER NOT NULL,
589 PRIMARY KEY(user, address)
590 )",
591 )
592 .execute(pool.write())
593 .await?;
594
595 sqlx::query(
596 "CREATE TABLE IF NOT EXISTS messages (
597 user BLOB NOT NULL,
598 hash BLOB NOT NULL,
599 object BLOB NOT NULL,
600 time INTEGER NOT NULL,
601 to_address TEXT NOT NULL,
602 from_address TEXT NOT NULL,
603 encoding INTEGER NOT NULL,
604 content BLOB NOT NULL,
605 subject TEXT NOT NULL,
606 read INTEGER NOT NULL,
607 PRIMARY KEY(user, hash)
608 )",
609 )
610 .execute(pool.write())
611 .await?;
612
613 sqlx::query(
634 "CREATE TABLE IF NOT EXISTS private_keys (
635 user BLOB NOT NULL,
636 address TEXT NOT NULL,
637 enabled INTEGER NOT NULL,
638 features INTEGER NOT NULL,
639 nonce_trials_per_byte INTEGER NOT NULL,
640 payload_length_extra_bytes INTEGER NOT NULL,
641 signing_key BLOB NOT NULL,
642 encryption_key BLOB NOT NULL,
643 chan INTEGER NOT NULL,
644 PRIMARY KEY(user, address)
645 )",
646 )
647 .execute(pool.write())
648 .await?;
649
650 sqlx::query(
651 "CREATE TABLE IF NOT EXISTS contacts (
652 user BLOB NOT NULL,
653 address TEXT NOT NULL,
654 enabled INTEGER NOT NULL,
655 PRIMARY KEY(user, address)
656 )",
657 )
658 .execute(pool.write())
659 .await?;
660
661 sqlx::query(
662 "CREATE TABLE IF NOT EXISTS aliases (
663 user BLOB NOT NULL,
664 address TEXT NOT NULL,
665 alias TEXT NOT NULL,
666 PRIMARY KEY(user, address)
667 )",
668 )
669 .execute(pool.write())
670 .await?;
671
672 Ok(Self { pool })
673 }
674
675 pub async fn user(&self, id: &[u8]) -> Result<User, Error> {
677 let list = sqlx::query_as::<sqlx::Sqlite, (i8, String)>(
678 "SELECT enabled, name FROM users WHERE id=?1",
679 )
680 .bind(id)
681 .fetch_all(self.pool.read())
682 .await?;
683 if list.is_empty() {
684 return Err(Error::NotExists);
685 }
686 let subscriptions = sqlx::query_as::<sqlx::Sqlite, (String, i8)>(
687 "SELECT address, enabled FROM subscriptions WHERE user=?1",
688 )
689 .bind(id)
690 .fetch_all(self.pool.read())
691 .await?;
692 let mut slist = Vec::new();
693 for subscription in subscriptions {
694 let address = subscription.0.parse::<Address>();
695 if address.is_err() {
696 continue;
697 }
698 slist.push(address.unwrap());
699 }
700
701 let private_identities = sqlx::query_as::<sqlx::Sqlite, PrivateKeysRow>(
702 "SELECT user, address, enabled,
703 features, nonce_trials_per_byte, payload_length_extra_bytes,
704 signing_key, encryption_key, chan
705 FROM private_keys
706 WHERE user=?1",
707 )
708 .bind(id)
709 .fetch_all(self.pool.read())
710 .await?;
711 let mut ilist = Vec::new();
712 for i in private_identities {
713 let private_keys: PrivateKeys = i.try_into()?;
714 ilist.push(private_keys.private_identity);
715 }
716
717 let contacts = sqlx::query_as::<sqlx::Sqlite, (String,)>(
718 "SELECT address
719 FROM contacts
720 WHERE user=?1",
721 )
722 .bind(id)
723 .fetch_all(self.pool.read())
724 .await?;
725 let mut clist = Vec::new();
726 for i in contacts {
727 let address = i.0.parse::<Address>()?;
728 let contact = Contact { address };
729 clist.push(contact);
730 }
731
732 let aliases = sqlx::query_as::<sqlx::Sqlite, (String, String)>(
733 "SELECT address, alias FROM aliases WHERE user=?1",
734 )
735 .bind(id)
736 .fetch_all(self.pool.read())
737 .await?;
738 let mut amap = HashMap::new();
739 for alias in aliases {
740 let address = alias.0.parse::<Address>();
741 if address.is_err() {
742 continue;
743 }
744 amap.insert(alias.0.clone(), alias.1.clone());
745 }
746
747 Ok(User {
748 id: id.to_vec(),
749 subscriptions: slist,
750 private_identities: ilist,
751 contacts: clist,
752 aliases: amap,
753 })
754 }
755
756 pub async fn add_user(&self, id: &[u8], name: &str) -> Result<(), Error> {
758 if let Ok(_user) = self.user(id).await {
760 return Err(Error::AlreadyExists);
761 }
762
763 let result = sqlx::query(
764 "INSERT INTO users (
765 id, enabled, name
766 ) VALUES (?1, ?2, ?3)",
767 )
768 .bind(id)
769 .bind(true)
770 .bind(name)
771 .execute(self.pool.write())
772 .await;
773 match result {
774 Ok(_) => Ok(()),
775 Err(sqlx::Error::Database(err)) => {
776 if let Some(code) = err.code() {
777 debug!("code: {}", code);
778 if code == SQLITE_CONSTRAINT_PRIMARYKEY.to_string() {
779 return Err(Error::AlreadyExists);
780 }
781 }
782 Err(Error::SqlxError(sqlx::Error::Database(err)))
783 }
784 Err(err) => Err(Error::SqlxError(err)),
785 }
786 }
787
788 pub async fn subscribe(&self, user_id: &[u8], address: &Address) -> Result<(), Error> {
790 let result = sqlx::query(
791 "INSERT INTO subscriptions (
792 user, address, enabled
793 ) VALUES (?1, ?2, ?3)",
794 )
795 .bind(user_id)
796 .bind(address.to_string())
797 .bind(true)
798 .execute(self.pool.write())
799 .await;
800 match result {
801 Ok(_) => Ok(()),
802 Err(sqlx::Error::Database(err)) => {
803 if let Some(code) = err.code() {
804 if code == SQLITE_CONSTRAINT_PRIMARYKEY.to_string() {
805 return Err(Error::AlreadyExists);
806 }
807 }
808 Err(Error::SqlxError(sqlx::Error::Database(err)))
809 }
810 Err(err) => Err(Error::SqlxError(err)),
811 }
812 }
813
814 pub async fn get_message(
816 &self,
817 user_id: &[u8],
818 hash: &InvHash,
819 ) -> Result<Option<Message>, Error> {
820 let list =
821 sqlx::query_as::<sqlx::Sqlite, MessageRow>("SELECT user, object, time, to_address,
822 from_address, encoding, content, subject, read FROM messages WHERE user=?1 AND hash=?2")
823 .bind(user_id)
824 .bind(hash.as_ref())
825 .fetch_all(self.pool.read())
826 .await?;
827 if list.is_empty() {
828 return Ok(None);
829 }
830 Ok(Some(list[0].clone().try_into()?))
831 }
832
833 async fn insert_message(&self, message: &Message) -> Result<(), Error> {
834 let hash = message.object.inv_hash();
835 let row: MessageRow = message.clone().into();
836
837 sqlx::query(
838 "INSERT INTO messages (
839 user, hash, object, time, to_address, from_address, encoding, content, subject, read
840 ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)",
841 )
842 .bind(row.user)
843 .bind(hash.as_ref())
844 .bind(row.object)
845 .bind(row.time)
846 .bind(row.to_address)
847 .bind(row.from_address)
848 .bind(row.encoding)
849 .bind(row.content)
850 .bind(row.subject)
851 .bind(row.read)
852 .execute(self.pool.write())
853 .await?;
854 Ok(())
855 }
856
857 pub async fn insert_msg(
859 &self,
860 user_id: Vec<u8>,
861 identity: &PrivateIdentity,
862 object: message::Object,
863 ) -> Result<Message, Error> {
864 let msg = object::Msg::try_from(object.clone())?;
865 println!("****** MSG FOUND ******"); let content = msg.decrypt(object.header(), &identity)?;
867
868 let subject = if content.encoding() == encoding::Encoding::Simple {
869 if let Ok(simple) = encoding::Simple::try_from(content.message()) {
870 String::from_utf8_lossy(simple.subject()).to_string()
871 } else {
872 "(No subject)".to_string()
873 }
874 } else {
875 "(No subject)".to_string()
876 };
877
878 let message = Message {
879 user_id,
880 object,
881 time: Time::now(),
882 to: Some(identity.address()),
883 from: content.address()?,
884 encoding: content.encoding(),
885 content: content.message().to_vec(),
886 subject,
887 read: false,
888 };
889
890 self.insert_message(&message).await?;
891
892 Ok(message)
893 }
894
895 pub async fn insert_broadcast(
897 &self,
898 user_id: Vec<u8>,
899 address: Address,
900 object: message::Object,
901 ) -> Result<Message, Error> {
902 let broadcast = object::Broadcast::try_from(object.clone())?;
903 match &broadcast {
904 object::Broadcast::V4(_) => (),
905 object::Broadcast::V5(v5) => {
906 if address.broadcast_tag() != *v5.tag() {
907 return Err(Error::TagMismatch);
908 }
909 println!("****** BROADCAST V5 FOUND ******"); }
911 }
912 let content = broadcast.decrypt(object.header(), &address)?;
913
914 let subject = if content.encoding() == encoding::Encoding::Simple {
915 if let Ok(simple) = encoding::Simple::try_from(content.message()) {
916 String::from_utf8_lossy(simple.subject()).to_string()
917 } else {
918 "(No subject)".to_string()
919 }
920 } else {
921 "(No subject)".to_string()
922 };
923
924 let message = Message {
925 user_id,
926 object,
927 time: Time::now(),
928 to: None,
929 from: address,
930 encoding: content.encoding(),
931 content: content.message().to_vec(),
932 subject,
933 read: false,
934 };
935
936 self.insert_message(&message).await?;
937
938 Ok(message)
939 }
940
941 pub async fn message_list(&self, user_id: &[u8]) -> Result<Vec<MessageEntry>, Error> {
943 let list = sqlx::query_as::<sqlx::Sqlite, (Vec<u8>, i64, String, String, String, i8)>(
944 "SELECT hash, time, to_address,
945 from_address, subject, read FROM messages WHERE user=?1 ORDER BY time DESC",
946 )
947 .bind(user_id)
948 .fetch_all(self.pool.read())
949 .await?;
950 let mut r: Vec<MessageEntry> = Vec::new();
951 for elem in list {
952 if elem.0.len() != 32 {
953 continue;
954 }
955 let hash: &[u8] = elem.0.as_ref();
956 let hash: [u8; 32] = hash.try_into().unwrap();
957 let hash = InvHash::new(hash);
958
959 let time = Time::new(elem.1 as u64);
960
961 let to = if elem.2 == SUBSCRIBERS {
962 None
963 } else {
964 let to = elem.2.parse::<Address>();
965 if to.is_err() {
966 continue;
967 }
968 Some(to.unwrap())
969 };
970
971 let from = elem.3.parse::<Address>();
972 if from.is_err() {
973 continue;
974 }
975 let from = from.unwrap();
976
977 let entry = MessageEntry {
978 hash,
979 time,
980 to,
981 from,
982 subject: elem.4,
983 read: elem.5 != 0,
984 };
985 r.push(entry);
986 }
987 Ok(r)
988 }
989
990 pub async fn set_read(&self, user_id: &[u8], hash: &InvHash, read: bool) -> Result<(), Error> {
992 sqlx::query("UPDATE messages SET read=?1 WHERE user=?2 and hash=?3")
993 .bind(read)
994 .bind(user_id)
995 .bind(hash.as_ref())
996 .execute(self.pool.write())
997 .await?;
998 Ok(())
999 }
1000
1001 pub async fn add_private_identity(
1003 &self,
1004 user_id: &[u8],
1005 identity: PrivateIdentity,
1006 ) -> Result<(), Error> {
1007 if identity.nonce_trials_per_byte().as_u64() > i64::MAX as u64 {
1008 return Err(Error::InvalidIdentity);
1009 }
1010 if identity.payload_length_extra_bytes().as_u64() > i64::MAX as u64 {
1011 return Err(Error::InvalidIdentity);
1012 }
1013
1014 sqlx::query(
1015 "INSERT INTO private_keys (
1016 user, address, enabled,
1017 features, nonce_trials_per_byte, payload_length_extra_bytes,
1018 signing_key, encryption_key, chan
1019 ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)",
1020 )
1021 .bind(user_id)
1022 .bind(identity.address().to_string())
1023 .bind(true)
1024 .bind(identity.features().bits() as i64)
1025 .bind(identity.nonce_trials_per_byte().as_u64() as i64)
1026 .bind(identity.payload_length_extra_bytes().as_u64() as i64)
1027 .bind(identity.private_signing_key().as_ref())
1028 .bind(identity.private_encryption_key().as_ref())
1029 .bind(identity.chan())
1030 .execute(self.pool.write())
1031 .await?;
1032
1033 Ok(())
1034 }
1035
1036 pub async fn add_contact(&self, user_id: &[u8], contact: &Contact) -> Result<(), Error> {
1038 let result = sqlx::query(
1039 "INSERT INTO contacts (
1040 user, address, enabled
1041 ) VALUES (?1, ?2, ?3)",
1042 )
1043 .bind(user_id)
1044 .bind(contact.address.to_string())
1045 .bind(true)
1046 .execute(self.pool.write())
1047 .await;
1048 match result {
1049 Ok(_) => Ok(()),
1050 Err(sqlx::Error::Database(err)) => {
1051 if let Some(code) = err.code() {
1052 if code == SQLITE_CONSTRAINT_PRIMARYKEY.to_string() {
1053 return Err(Error::AlreadyExists);
1054 }
1055 }
1056 Err(Error::SqlxError(sqlx::Error::Database(err)))
1057 }
1058 Err(err) => Err(Error::SqlxError(err)),
1059 }
1060 }
1061
1062 pub async fn add_alias(
1064 &self,
1065 user_id: &[u8],
1066 address: &Address,
1067 alias: &str,
1068 ) -> Result<(), Error> {
1069 let result = sqlx::query(
1070 "INSERT INTO aliases (
1071 user, address, alias
1072 ) VALUES (?1, ?2, ?3)",
1073 )
1074 .bind(user_id)
1075 .bind(address.to_string())
1076 .bind(alias)
1077 .execute(self.pool.write())
1078 .await;
1079 match result {
1080 Ok(_) => Ok(()),
1081 Err(sqlx::Error::Database(err)) => {
1082 if let Some(code) = err.code() {
1083 if code == SQLITE_CONSTRAINT_PRIMARYKEY.to_string() {
1084 return Err(Error::AlreadyExists);
1085 }
1086 }
1087 Err(Error::SqlxError(sqlx::Error::Database(err)))
1088 }
1089 Err(err) => Err(Error::SqlxError(err)),
1090 }
1091 }
1092}
1093
1094#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1096pub struct MessageEntry {
1097 hash: InvHash,
1098 time: Time,
1099 to: Option<Address>,
1100 from: Address,
1101 subject: String,
1102 read: bool,
1103}
1104
1105impl MessageEntry {
1106 pub fn hash(&self) -> &InvHash {
1108 &self.hash
1109 }
1110
1111 pub fn subject(&self) -> &str {
1113 &self.subject
1114 }
1115
1116 pub fn read(&self) -> bool {
1118 self.read
1119 }
1120
1121 pub fn set_read(&mut self, read: bool) {
1123 self.read = read;
1124 }
1125}
1126
1127impl From<&Message> for MessageEntry {
1128 fn from(message: &Message) -> MessageEntry {
1129 Self {
1130 hash: message.object.inv_hash(),
1131 time: message.time,
1132 to: message.to.clone(),
1133 from: message.from.clone(),
1134 subject: message.subject.clone(),
1135 read: message.read,
1136 }
1137 }
1138}