1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// rtj provides a generic job execution framework in Rust
// Copyright 2021-2022 Anthony Martinez
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! **rtj** aims to provide a generic, robust, and secure framework for users to develop
//! their own job execution applications. Encryption uses [`crypto_box`] and is compatible with
//! other implementations of the [standard](https://doc.libsodium.org/public-key_cryptography/authenticated_encryption).
//!
//! ### Example:
//! ``` 
//! // Full example avaialble in the source repo under /examples/hello.rs
//! use rtj::{Job, Message};
//!# use crypto_box::SecretKey;
//!# use rmp_serde as rmps;
//!# use serde::{Deserialize, Serialize};
//!# type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
//!# enum MsgType {
//!#   Hello,
//!#   Unknown,
//!# }
//!# impl From<u8> for MsgType {
//!#     fn from(t: u8) -> MsgType {
//!#         match t {
//!#             0 => MsgType::Hello,
//!#             _ => MsgType::Unknown,
//!#         }
//!#     }
//!# }
//!# impl From<MsgType> for u8 {
//!#    fn from(t: MsgType) -> u8 {
//!#        match t {
//!#            MsgType::Hello => 0,
//!#            MsgType::Unknown => 255,
//!#        }
//!#    }
//!# }
//!# #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
//!# struct Hello {
//!#    name: String,
//!#    age: u8,
//!# }
//!# impl Job for Hello {
//!#    fn encode(&self) -> Vec<u8> {
//!#        rmps::to_vec(&self).unwrap()
//!#    }
//!#    fn decode(input: &[u8]) -> Hello {
//!#        let hello: Hello = rmps::from_read(input).unwrap();
//!#        hello
//!#    }
//!#    fn ack(&self) -> Vec<u8> {
//!#        let name = &self.name;
//!#        let age = &self.age;
//!#        let ack_string = format!("Hello from {name}, age {age}");
//!#        Vec::from(ack_string)
//!#    }
//!#    fn run(&self) -> Result<()> {
//!#        let ack_string = String::from_utf8(self.ack())?;
//!#        println!("{ack_string}");
//!#        Ok(())
//!#    }
//!# }
//!# fn main() -> Result<()> {
//!#     let mut rng = rand::thread_rng();
//!#     // Create the sender's keys
//!#     // This would normally be loaded from a secure location
//!#     let send_secret = SecretKey::generate(&mut rng);
//!#     let send_pub = send_secret.public_key().as_bytes().to_owned();
//!#     // Create the recipient's keys
//!#     // This would normally exist on a remote node, and be loaded
//!#     // from a secure location. The sender should have a copy of
//!#     // the remote node's public key to encrypt towards.
//!#     let recv_secret = SecretKey::generate(&mut rng);
//!#
//!#     let name = "Anthony J. Martinez".to_owned();
//!#     let age = 38;
//!     // Create a struct that implements Job
//!     let hello = Hello { name, age };
//!
//!     // Build a Message from that struct
//!     let msg = Message::new()
//!         .set_payload(&hello)
//!         .set_header(MsgType::Hello, send_pub, &mut rng)?;
//!
//!     // Encrypt the message payload for the recipient.
//!     let encrypted_to_recv = msg.encrypt(recv_secret.public_key(), send_secret)?;
//!
//!     // Decrypt the message payload as the recipient.
//!     let hello_again = encrypted_to_recv.decrypt(recv_secret)?;
//!
//!     // Verify the message type.
//!     if let MsgType::Hello = hello_again.header.msgtype.into() {
//!         // Deserialize the message payload as the correct type
//!         let hello = Hello::decode(&hello_again.payload);
//!
//!         // Execute the runner method on the deserialized type
//!         hello.run()?;
//!     }
//!
//!#     Ok(())
//!# }
//! ```

use crypto_box::{
    aead::{consts::U24, generic_array::GenericArray, AeadMut},
    PublicKey, SecretKey,
};
use rand::{CryptoRng, RngCore};
use serde::{Deserialize, Serialize};

mod error;
mod header;
mod job;
mod message;

pub use error::RtjError;
pub use header::Header;
pub use job::Job;
pub use message::Message;

type Result<T> = std::result::Result<T, RtjError>;