koibumi_box/
lib.rs

1//! This crate is an inbox/outbox module for Koibumi, an experimental Bitmessage client.
2//!
3//! See [`koibumi`](https://crates.io/crates/koibumi) for more about the application.
4//! See [Bitmessage](https://bitmessage.org/) for more about the protocol.
5
6#![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/// This error indicates that an operation on boxes failed.
36#[derive(Debug)]
37pub enum Error {
38    /// A SQLx error was caught during operation on boxes.
39    /// The actual error caught is returned as a payload of this variant.
40    SqlxError(sqlx::Error),
41    /// Indicates that tags did not match.
42    TagMismatch,
43    /// Indicates that the construction from public keys failed.
44    AddressError(AddressError),
45    /// An error was caught during parsing a Bitmessage address.
46    /// The actual error caught is returned as a payload of this variant.
47    ParseAddressError(ParseAddressError),
48    /// Indicates that the conversion from object to msg failed.
49    /// The actual error caught is returned as a payload of this variant.
50    TryIntoMsgError(object::TryIntoMsgError),
51    /// Indicates that the conversion from object to broadcast failed.
52    /// The actual error caught is returned as a payload of this variant.
53    TryIntoBroadcastError(object::TryIntoBroadcastError),
54    /// Indicates that the decryption failed.
55    /// The actual error caught is returned as a payload of this variant.
56    DecryptError(object::DecryptError),
57    /// Indicates that conversion from message row to message failed.
58    /// The actual error caught is returned as a payload of this variant.
59    TryIntoMessageError(TryIntoMessageError),
60    /// The item attempted to insert already exists.
61    AlreadyExists,
62    /// The item attempted to retrieve does not exists.
63    NotExists,
64    /// The identity is invalid.
65    InvalidIdentity,
66    /// The conversion to private keys failed.
67    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/// An object represents a contact.
140#[derive(Clone, PartialEq, Eq, Debug)]
141pub struct Contact {
142    address: Address,
143}
144
145impl Contact {
146    /// Creates a contact from an address.
147    pub fn new(address: Address) -> Self {
148        Self { address }
149    }
150
151    /// Returns the address.
152    pub fn address(&self) -> &Address {
153        &self.address
154    }
155}
156
157/// An object represents an user.
158#[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    /// Returns the ID.
169    pub fn id(&self) -> &[u8] {
170        &self.id
171    }
172
173    /// Returns the subscription list.
174    pub fn subscriptions(&self) -> &[Address] {
175        &self.subscriptions
176    }
177
178    /// Returns the subscription list as mutable reference.
179    pub fn subscriptions_mut(&mut self) -> &mut Vec<Address> {
180        &mut self.subscriptions
181    }
182
183    /// Returns the private identity list.
184    pub fn private_identities(&self) -> &[PrivateIdentity] {
185        &self.private_identities
186    }
187
188    /// Returns the private identity list as mutable reference.
189    pub fn private_identities_mut(&mut self) -> &mut Vec<PrivateIdentity> {
190        &mut self.private_identities
191    }
192
193    /// Finds the private identity by address.
194    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    /// Returns the contact list.
201    pub fn contacts(&self) -> &[Contact] {
202        &self.contacts
203    }
204
205    /// Returns the contact list as mutable reference.
206    pub fn contacts_mut(&mut self) -> &mut Vec<Contact> {
207        &mut self.contacts
208    }
209
210    /// Returns the aliases.
211    pub fn aliases(&self) -> &HashMap<String, String> {
212        &self.aliases
213    }
214
215    /// Returns the aliases as mutable reference.
216    pub fn aliases_mut(&mut self) -> &mut HashMap<String, String> {
217        &mut self.aliases
218    }
219
220    /// Returns the alias corresponding to the address.
221    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    /// Returns the rich alias corresponding to the address.
229    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/// A message structure stored on database.
244#[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    /// Returns the received time.
259    pub fn time(&self) -> Time {
260        self.time
261    }
262
263    /// Returns the receiver's Bitmessage address.
264    pub fn to_address(&self) -> Option<&Address> {
265        self.to.as_ref()
266    }
267
268    /// Returns the sender's Bitmessage address.
269    pub fn from_address(&self) -> &Address {
270        &self.from
271    }
272
273    /// Returns the encoding.
274    pub fn encoding(&self) -> Encoding {
275        self.encoding
276    }
277
278    /// Returns the content bytes.
279    pub fn content(&self) -> &[u8] {
280        &self.content
281    }
282}
283
284/// This error indicates that conversion from message row to message failed.
285#[derive(Debug)]
286pub enum TryIntoMessageError {
287    /// A standard I/O error was caught during converting a message.
288    /// The actual error caught is returned as a payload of this variant.
289    IoError(io::Error),
290    /// An error was caught during parsing a Bitmessage address.
291    /// The actual error caught is returned as a payload of this variant.
292    ParseAddressError(ParseAddressError),
293    /// An error was caught during parsing a message encoding type.
294    /// The actual error caught is returned as a payload of this variant.
295    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/// The conversion to private keys failed.
473#[derive(Debug)]
474pub enum TryIntoPrivateKeysError {
475    /// There was an out of range parameter.
476    OutOfRange,
477    /// Indicates that parsing an address failed.
478    ParseAddressError(ParseAddressError),
479    /// Indicates array length mismatch.
480    TryFromSliceError(std::array::TryFromSliceError),
481    /// Indicates that the operation on a private key failed.
482    PrivateKeyError(PrivateKeyError),
483    /// Indicates that the construction of the address from public keys failed.
484    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/// An inbox/outbox manager.
566#[derive(Debug)]
567pub struct Manager {
568    pool: db::SqlitePool,
569}
570
571impl Manager {
572    /// Constructs an inbox/outbox manager from database connection pool.
573    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        /*
614        sqlx::query(
615            "CREATE TABLE IF NOT EXISTS public_keys (
616                user BLOB NOT NULL,
617                address TEXT NOT NULL,
618                features INTEGER NOT NULL,
619                signing_key BLOB NOT NULL,
620                encryption_key BLOB NOT NULL,
621                nonce_trials_per_byte INTEGER NOT NULL,
622                payload_length_extra_bytes INTEGER NOT NULL,
623                hash BLOB NOT NULL,
624                object BLOB NOT NULL,
625                expires INTEGER NOT NULL,
626                PRIMARY KEY(user, address)
627            )",
628        )
629        .execute(pool.write())
630        .await?;
631        */
632
633        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    /// Retrieves a user object specified by its ID.
676    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    /// Inserts a user object.
757    pub async fn add_user(&self, id: &[u8], name: &str) -> Result<(), Error> {
758        // XXX guard
759        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    /// Insert a subscription address for a user.
789    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    /// Retrieves a message specified by a user ID and an inventory hash.
815    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    /// Inserts a msg object.
858    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 ******"); // DEBUG
866        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    /// Inserts a broadcast object.
896    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 ******"); // DEBUG
910            }
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    /// Retrieves a list of message entries for a user specified by a user ID.
942    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    /// Sets the read flag of the message specified by a user ID and an inventory hash.
991    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    /// Adds private identity in database.
1002    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    /// Insert a contact address for a user.
1037    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    /// Insert an alias.
1063    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/// A message object without its content.
1095#[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    /// Returns the inventory hash.
1107    pub fn hash(&self) -> &InvHash {
1108        &self.hash
1109    }
1110
1111    /// Returns the subject.
1112    pub fn subject(&self) -> &str {
1113        &self.subject
1114    }
1115
1116    /// Returns the read flag.
1117    pub fn read(&self) -> bool {
1118        self.read
1119    }
1120
1121    /// Sets the read flag.
1122    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}