use rand_core::OsRng;
use x25519_dalek::{PublicKey, StaticSecret};
use super::helper::{
get_did_document_from_body,
get_did_exchange_message,
get_exchange_info_from_message,
DidExchangeOptions,
DidExchangeType,
};
use crate::{
datatypes::{BaseMessage, MessageWithBody, DidDocumentBodyAttachment, Base64Container},
get_from_to_from_message,
keypair::save_com_keypair,
protocols::{
did_exchange::{
datatypes::{State, UserType},
did_exchange::{save_didexchange, save_state},
helper::DidExchangeBaseMessage
},
protocol::{generate_step_output, StepResult},
},
};
pub fn send_request(options: &str, message: &str) -> StepResult {
let parsed_message: DidExchangeBaseMessage = serde_json::from_str(message)?;
let options: DidExchangeOptions = serde_json::from_str(options)?;
let exchange_info = get_from_to_from_message(&parsed_message.base_message)?;
let secret_key = options
.did_exchange_my_secret
.map(StaticSecret::from)
.unwrap_or_else(|| StaticSecret::new(OsRng));
let pub_key = PublicKey::from(&secret_key);
let codec: &[u8] = &[0xec, 0x1];
let data = [codec, pub_key.as_bytes()].concat();
let key_did = parsed_message
.base_message
.from
.as_ref()
.map(|v| v.to_owned())
.unwrap_or_else(|| format!("did:key:z{}", bs58::encode(data).into_string()));
let encoded_keypair = save_com_keypair(
&exchange_info.from,
&exchange_info.to,
&key_did,
"",
&hex::encode(pub_key.to_bytes()),
&hex::encode(secret_key.to_bytes()),
None,
None,
)?;
let metadata = serde_json::to_string(&encoded_keypair)?;
let pub_key_bytes = hex::decode(encoded_keypair.pub_key)?;
let pub_key_base58_string = &bs58::encode(pub_key_bytes).into_string();
let (request_message, did_document) = get_did_exchange_message(
DidExchangeType::Request,
&exchange_info.from,
&key_did,
&exchange_info.to,
&options.service_endpoint.unwrap_or_else(|| "".to_string()),
pub_key_base58_string,
&parsed_message,
)?;
if exchange_info.from != did_document.id {
save_com_keypair(
&exchange_info.from,
&exchange_info.to,
&key_did,
"",
&hex::encode(pub_key.to_bytes()),
&hex::encode(secret_key.to_bytes()),
None,
None,
)?;
}
let thid = parsed_message.thid.ok_or("Thread id can't be empty")?;
save_state(&thid, &State::SendRequest, &UserType::Inviter)?;
save_didexchange(
&exchange_info.from,
&exchange_info.to,
&thid,
&serde_json::to_string(&did_document)?,
&State::SendRequest,
)?;
generate_step_output(&serde_json::to_string(&request_message)?, &metadata)
}
pub fn receive_request(options: &str, message: &str) -> StepResult {
let parsed_message: MessageWithBody<DidDocumentBodyAttachment<Base64Container>> = serde_json::from_str(message)?;
let thid = parsed_message.thid.ok_or("Thread id can't be empty")?;
let did_document = get_did_document_from_body(message)?;
let parsed_message: BaseMessage = serde_json::from_str(message)?;
let exchange_info = get_exchange_info_from_message(&parsed_message, did_document)?;
let options: DidExchangeOptions = serde_json::from_str(options)?;
let secret_key = options
.did_exchange_my_secret
.map(StaticSecret::from)
.unwrap_or_else(|| StaticSecret::new(OsRng));
let pub_key = PublicKey::from(&secret_key);
let codec: &[u8] = &[0xec, 0x1];
let data = [codec, pub_key.as_bytes()].concat();
let key_did = format!("did:key:z{}", bs58::encode(data).into_string());
let encoded_keypair = save_com_keypair(
&exchange_info.to,
&exchange_info.from,
&key_did,
&exchange_info.did_id,
&hex::encode(pub_key.to_bytes()),
&hex::encode(secret_key.to_bytes()),
Some(exchange_info.clone().pub_key_hex),
Some(exchange_info.clone().service_endpoint),
)?;
if exchange_info.from != exchange_info.did_id {
save_com_keypair(
&exchange_info.to,
&exchange_info.did_id,
&key_did,
&exchange_info.did_id,
&hex::encode(pub_key.to_bytes()),
&hex::encode(secret_key.to_bytes()),
Some(exchange_info.pub_key_hex),
Some(exchange_info.service_endpoint),
)?;
}
let metadata = serde_json::to_string(&encoded_keypair)?;
save_state(&thid, &State::ReceiveRequest, &UserType::Invitee)?;
save_didexchange(
&exchange_info.from,
&exchange_info.to,
&thid,
&serde_json::to_string(&encoded_keypair)?,
&State::ReceiveRequest,
)?;
generate_step_output(message, &metadata)
}