use crate::keyutil;
use crate::storage::Storage;
use bip39::Mnemonic;
use chrono::{DateTime, Utc};
use heed::types::{SerdeRmp, Str};
use heed::{Database, RoTxn};
use nostr_sdk::prelude::*;
use serde::{Deserialize, Serialize};
use std::error::Error;
#[derive(Debug, Serialize, Deserialize)]
pub struct NostrKeys<'a> {
#[serde(borrow)]
pub sec_key_hex: &'a str,
pub datetime_created: DateTime<Utc>,
pub active: bool,
pub flags: u32,
}
type KeysDatabase<'a> = Database<Str, SerdeRmp<NostrKeys<'a>>>;
const DB_NAME: &str = "nostr_keys";
const KEYS_DEFAULT: &str = "default";
impl Storage {
fn keys_db(
&self,
) -> Result<KeysDatabase<'_>, Box<dyn Error + Send + Sync>> {
let mut rtxn = self.get_read_txn()?;
let dbo: Option<KeysDatabase> =
self.env.open_database(&mut rtxn, Some(DB_NAME))?;
if dbo.is_some() {
Ok(dbo.unwrap())
} else {
Err(Box::from("Error opening nostr keys db"))
}
}
pub fn create_keys_db(
&self,
) -> Result<KeysDatabase<'_>, Box<dyn Error + Send + Sync>> {
let mut wtxn = self.env.write_txn()?;
let db: KeysDatabase =
self.env.create_database(&mut wtxn, Some(DB_NAME))?;
wtxn.commit()?;
Ok(db)
}
pub fn get_keys(
&self,
rtxn: &mut RoTxn,
idx: &str,
) -> Result<Keys, Box<dyn Error + Send + Sync>> {
return match self.keys_db()?.get(rtxn, idx)? {
Some(k) => {
if let Ok(keys) = Keys::parse(k.sec_key_hex) {
return Ok(keys);
}
Err(Box::from("Cannot parse key!"))
}
None => Err(Box::from("No key")),
};
}
pub fn get_default_keys(
&self,
rtxn: &mut RoTxn,
) -> Result<Keys, Box<dyn Error + Send + Sync>> {
self.get_keys(rtxn, KEYS_DEFAULT)
}
pub fn create_default_keys(
&self,
) -> Result<Keys, Box<dyn Error + Send + Sync>> {
self.create_keys(KEYS_DEFAULT)
}
pub fn create_keys<'c>(
&self,
name: &str,
) -> Result<Keys, Box<dyn Error + Send + Sync>> {
if let Ok(db) = self.keys_db() {
let mut wtxn = self.env.write_txn()?;
let keys = Keys::generate();
let ks = keys.secret_key().to_secret_hex().clone();
let k = NostrKeys {
sec_key_hex: ks.as_str(),
datetime_created: Utc::now(),
active: true,
flags: 0,
};
db.put(&mut wtxn, name, &k)?;
wtxn.commit()?;
Ok(keys)
} else {
Err(Box::from("No keys database"))
}
}
pub fn create_keys_with_mnemonic<'c>(
&self,
name: &str,
) -> Result<(Keys, Mnemonic), Box<dyn Error + Send + Sync>> {
if let Ok(db) = self.keys_db() {
let mut wtxn = self.env.write_txn()?;
let (keys, mnemo) = keyutil::genkeys_with_mnemonic().unwrap();
let ks = keys.secret_key().to_secret_hex().clone();
let k = NostrKeys {
sec_key_hex: ks.as_str(),
datetime_created: Utc::now(),
active: true,
flags: 0,
};
db.put(&mut wtxn, name, &k)?;
wtxn.commit()?;
Ok((keys, mnemo))
} else {
Err(Box::from("No keys db"))
}
}
}