Create new user

This commit is contained in:
Sosthene00 2024-03-23 23:24:00 +01:00
parent 8dde96b93c
commit 38beda8007
4 changed files with 275 additions and 206 deletions

View File

@ -30,8 +30,6 @@ img-parts = "0.3.0"
bytes = "1.5.0"
scrypt = "0.11.0"
shamir = "2.0.0"
bitcoin = { version = "0.31.1", features = ["serde", "base64"] }
[dev-dependencies]
wasm-bindgen-test = "0.3"

View File

@ -1,8 +1,9 @@
use rand::Rng;
use anyhow::Error as AnyhowError;
use sp_backend::silentpayments::Error as SpError;
use serde_json::Error as SerdeJsonError;
use sp_backend::silentpayments::Error as SpError;
use sp_backend::bitcoin::secp256k1::SecretKey;
use serde::{Deserialize, Serialize};
use sp_backend::silentpayments::sending::SilentPaymentAddress;
@ -12,6 +13,9 @@ use wasm_bindgen::prelude::*;
use sp_backend::spclient::SpendKey;
use sp_backend::spclient::{derive_keys_from_seed, OutputList, SpClient};
use web_sys::js_sys::JsString;
use crate::user::User;
type ApiResult<T: FromWasmAbi> = Result<T, ApiError>;
@ -24,19 +28,25 @@ struct ApiError {
impl From<AnyhowError> for ApiError {
fn from(value: AnyhowError) -> Self {
ApiError {message: value.to_string()}
ApiError {
message: value.to_string(),
}
}
}
impl From<SpError> for ApiError {
fn from(value: SpError) -> Self {
ApiError { message: value.to_string() }
ApiError {
message: value.to_string(),
}
}
}
impl From<SerdeJsonError> for ApiError {
fn from(value: SerdeJsonError) -> Self {
ApiError { message: value.to_string() }
ApiError {
message: value.to_string(),
}
}
}
@ -104,3 +114,44 @@ pub fn get_receiving_address(sp_client: String) -> String {
let sp_client: SpClient = serde_json::from_str(&sp_client).unwrap();
sp_client.get_receiving_address()
}
#[wasm_bindgen]
pub fn create_user(
recover_wallet: String,
revoke_wallet: String,
password: JsString,
image_to_recover: &[u8],
image_to_revoke: &[u8],
) -> ApiResult<User> {
let recover_sp_client: SpClient = serde_json::from_str(&recover_wallet)?;
let revoke_sp_client: SpClient = serde_json::from_str(&revoke_wallet)?;
let recover_spend_key: SecretKey = match recover_sp_client.get_spend_key() {
SpendKey::Secret(sk) => sk,
SpendKey::Public(_) => {
return Err(ApiError {
message: "Can't create user from a watch-only sp_client".to_owned(),
})
}
};
let revoke_spend_key: SecretKey = match revoke_sp_client.get_spend_key() {
SpendKey::Secret(sk) => sk,
SpendKey::Public(_) => {
return Err(ApiError {
message: "Can't create user from a watch-only sp_client".to_owned(),
})
}
};
let revoke_scan_key = revoke_sp_client.get_scan_key();
let user = User::new(
recover_spend_key,
revoke_spend_key,
revoke_scan_key,
&password,
image_to_recover,
image_to_revoke,
)?;
Ok(user)
}

View File

@ -1,21 +1,37 @@
use anyhow::Error;
use bitcoin::secp256k1::SecretKey;
use aes::cipher::generic_array::GenericArray;
use aes_gcm::aead::Aead;
use aes_gcm::AeadCore;
use aes_gcm::KeyInit;
use aes_gcm::{aead::Buffer, Aes256Gcm, Key};
use anyhow::{Error, Result};
use bytes::Buf;
use rand::{self, thread_rng, Rng, RngCore};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use sp_backend::bitcoin::hashes::Hash;
use sp_backend::bitcoin::hashes::HashEngine;
use sp_backend::bitcoin::hex::{DisplayHex, FromHex};
use sp_backend::bitcoin::secp256k1::SecretKey;
use tsify::Tsify;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsValue;
use web_sys::console;
use web_sys::js_sys::JsString;
use crate::aesgcm::{Aes256GcmIv96Bit, KeyEncryption};
use crate::secretdata::SecretData;
// use crate::secretdata::SecretData;
use bytes::Bytes;
use hex;
use sha2::{Digest, Sha256};
use shamir::SecretData;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::str::FromStr;
use crate::api::{generate_sp_wallet, generate_sp_wallet_return};
use sp_backend::bitcoin::secp256k1::constants::SECRET_KEY_SIZE;
use sp_backend::silentpayments::bitcoin_hashes::sha256;
use sp_backend::silentpayments::sending::SilentPaymentAddress;
use sp_backend::spclient::SpendKey;
use sp_backend::spclient::{OutputList, SpClient};
@ -31,90 +47,100 @@ use scrypt::{
//extern crate shamir;
//use shamir::SecretData;
#[wasm_bindgen]
#[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(Debug, Serialize, Deserialize, Clone, Tsify)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct User {
image_recover: ImageRecover,
image_revoke: ImageRevoke,
sharding: Sharding,
pre_id: String,
recovered_spend_key: Option<String>,
image_recover: BackUpImage,
image_revoke: BackUpImage,
sharding: Sharding,
pre_id: String,
recovered_spend_key: Option<String>,
}
#[wasm_bindgen]
impl User {
#[wasm_bindgen(constructor)]
pub fn new(new_password: &str, image_to_recover: &[u8], image_to_revoke: &[u8]) -> Self {
pub fn new(
recover_spend_key: SecretKey,
revoke_spend_key: SecretKey,
revoke_scan_key: SecretKey,
user_password: &JsString,
recover_image: &[u8],
revoke_image: &[u8],
) -> Result<Self> {
// image revoke
// We just take the 2 revoke keys and put it in the revoke_img file
let mut revoke_data = [0u8; SECRET_KEY_SIZE * 2];
revoke_data[..SECRET_KEY_SIZE].copy_from_slice(revoke_scan_key.as_ref());
revoke_data[SECRET_KEY_SIZE..].copy_from_slice(revoke_spend_key.as_ref());
let password = new_password.to_string();
let random_seed1 = generate_random_key(32);
let random_seed2 = generate_random_key(32);
//wallet recover
let wallet_rec: String = match generate_sp_wallet(None,50000, true) {
Some(sp_wallet) => sp_wallet.sp_client_json,
None => panic!("No wallet recover available"),
};
let sp_client_rec: SpClient = serde_json::from_str(&wallet_rec).unwrap();
let priv_recover_scan_key_bytes = sp_client_rec.get_scan_key().secret_bytes();
let priv_recover_scan_key = from_b64_to_hex(&base64::encode(priv_recover_scan_key_bytes));
let priv_recover_spend_key_bytes = match sp_client_rec.get_spend_key(){
SpendKey::Secret(key)=> key.secret_bytes(),
SpendKey::Public(_) => panic!("No recover spend key created on Signet"),
};
let priv_recover_spend_key = from_b64_to_hex(&base64::encode(priv_recover_spend_key_bytes));
console::log_2(&"priv_recover_spend_key".into(),&JsValue::from_str(&priv_recover_spend_key));
//wallet revoke
let wallet_rev: String = match generate_sp_wallet(None, 50000, true) {
Some(sp_wallet) => sp_wallet.sp_client_json,
None => panic!("No wallet revoke available"),
};
let sp_client_rev: SpClient = serde_json::from_str(&wallet_rec).unwrap();
let priv_revoke_scan_key_bytes = sp_client_rev.get_scan_key().secret_bytes();
let priv_revoke_scan_key = from_b64_to_hex(&base64::encode(priv_revoke_scan_key_bytes));
let priv_revoke_spend_key_bytes = match sp_client_rev.get_spend_key(){
SpendKey::Secret(key)=> key.secret_bytes(),
SpendKey::Public(_) => panic!("No revoke spend key created on Signet"),
};
let priv_revoke_spend_key = from_b64_to_hex(&base64::encode(priv_revoke_spend_key_bytes));
let revoke_img_with_data = BackUpImage::new_revoke(revoke_image, &revoke_data)?;
//split recover spend key
let (part1_key, part2_key) = priv_recover_spend_key.split_at(priv_recover_spend_key.len()/2);
// split recover spend key
let (part1_key, part2_key) = recover_spend_key.as_ref().split_at(SECRET_KEY_SIZE / 2);
let mut recover_data = Vec::<u8>::with_capacity(88);
//part1 enc
let pwd_hash_part1 = from_hex_to_b64(&sha_256(&format!("{}{}",password, &random_seed1)));
// generate 2 tokens of 32B entropy
let mut entropy_1 = [0u8; 32];
entropy_1.copy_from_slice(&generate_random_key(32));
let mut entropy_2 = [0u8; 32];
entropy_2.copy_from_slice(&generate_random_key(32));
//split recover spend key
let (part1_key, part2_key) =
priv_recover_spend_key.split_at(priv_recover_spend_key.len() / 2);
recover_data.extend_from_slice(&entropy_1);
recover_data.extend_from_slice(&entropy_2);
// convert the password in a Vec<u8>
// Be careful of javascript strings: https://rustwasm.github.io/wasm-bindgen/reference/types/str.html#utf-16-vs-utf-8
assert!(user_password.is_valid_utf16());
let password: String = user_password.into();
// hash the concatenation
let mut engine = sha256::HashEngine::default();
engine.write_all(&password.as_bytes());
engine.write_all(&entropy_1);
let hash1 = sha256::Hash::from_engine(engine);
// take it as a AES key
let key1: &Key<Aes256Gcm> = hash1.as_byte_array().try_into()?;
let cipher = Aes256Gcm::new(&key1);
// encrypt the part1 of the key
let nonce1 = Aes256Gcm::generate_nonce(&mut thread_rng());
let nonce2 = Aes256Gcm::generate_nonce(&mut thread_rng());
let cipher_recover_part1 = cipher
.encrypt(&nonce1, part1_key)
.map_err(|e| anyhow::Error::msg(format!("{}", e)))?;
log::debug!("cipher_part1 length: {}", cipher_recover_part1.len());
recover_data.extend_from_slice(&nonce1);
recover_data.extend_from_slice(&nonce2);
recover_data.extend_from_slice(&cipher_recover_part1);
//part1 enc
let pwd_hash_part1 = from_hex_to_b64(&sha_256(&format!("{}{}", password, &random_seed1)));
let key_enc_part1 = KeyEncryption::new(None, Some(pwd_hash_part1.clone()), None);
let part1_key_enc = key_enc_part1.enc_string(part1_key.to_string());
//part2 enc
let pwd_hash_part2 = from_hex_to_b64(&sha_256(&format!("{}{}", password, random_seed2)));
let key_enc_part2 = KeyEncryption::new(None, Some(pwd_hash_part2.clone()), None);
let part2_key_enc = key_enc_part2.enc_string(part2_key.to_string());
//image recover
let image_recover = ImageRecover::new(
image_to_recover,
&random_seed1,
&random_seed2,
&part1_key_enc,
);
//image revoke
//let priv_revoke_spend_key = wallet.priv_revoke_spend_key.to_owned();
//let priv_revoke_scan_key = wallet.priv_revoke_scan_key.to_owned();
let image_revoke = ImageRevoke::new(
image_to_revoke,
&priv_revoke_spend_key,
&priv_revoke_scan_key,
);
let recover_img_with_data = BackUpImage::new_recover(recover_image, &recover_data)?;
// encrypt the part 2 of the key
let mut engine = sha256::HashEngine::default();
engine.write_all(&password.as_bytes());
engine.write_all(&entropy_2);
let hash2 = sha256::Hash::from_engine(engine);
// take it as a AES key
let key2: &Key<Aes256Gcm> = hash2.as_byte_array().try_into()?;
let cipher = Aes256Gcm::new(&key2);
// encrypt the part2 of the key
let cipher_recover_part2 = cipher
.encrypt(&nonce2, part2_key)
.map_err(|e| anyhow::Error::msg(format!("{}", e)))?;
//create shardings
let sharding = Sharding::new(&part2_key_enc, 10u8); //nMembers = 10 for testing, need to recover nmember elsewhere
//Pre ID
let pre_id = sha_256(&format!("{}{}", password, part2_key_enc));
let sharding = Sharding::new(&cipher_recover_part2.to_lower_hex_string(), 10u8); //nMembers = 10 for testing, need to recover nmember elsewhere
//Pre ID
let mut engine = sha256::HashEngine::default();
engine.write_all(&password.as_bytes());
engine.write_all(&cipher_recover_part1);
let pre_id = sha256::Hash::from_engine(engine);
//Create PRDList
//@todo
@ -122,86 +148,118 @@ impl User {
//@todo
//Receive List Items (PCD)
console::log_1(&"authentication: ok".into());
User {
image_recover,
image_revoke,
Ok(User {
image_recover: recover_img_with_data,
image_revoke: revoke_img_with_data,
sharding,
pre_id,
pre_id: pre_id.to_string(),
recovered_spend_key: None,
}
})
}
pub fn login(&self, password: &str, image_recover: &[u8]) -> Option<String> {
let exif_image_bytes = read_exif(image_recover).unwrap_or_else(|error| {
panic!("Unable to read the image exif: {}", error);
});
pub fn login(&self, user_password: JsString, image_recover: &[u8]) -> Result<SecretKey> {
let mut retrieved_key = [0u8; 32];
let mut entropy1 = [0u8; 32];
let mut entropy2 = [0u8; 32];
let mut nonce1 = [0u8; 12];
let mut nonce2 = [0u8; 12];
let mut part1_ciphertext = Vec::with_capacity(32); // just a guess
let exif_image_string = String::from_utf8(exif_image_bytes.to_vec()).unwrap();
let exif_image_json: Value = serde_json::from_str(&exif_image_string).unwrap();
let random_seed1 = exif_image_json["random_seed1"].as_str().unwrap_or("N/A");
let random_seed2 = exif_image_json["random_seed2"].as_str().unwrap_or("N/A");
let part1_key_enc = exif_image_json["part1_key_enc"].as_str().unwrap_or("N/A");
let part1_recovered = Self::recover_part1(password, random_seed1, part1_key_enc);
let part1_trimmed = part1_recovered.trim_matches('"');
assert!(user_password.is_valid_utf16());
let password: String = user_password.into();
//@todo: get shardings from member managers!!
let exif_image_bytes =
Bytes::from(read_exif(image_recover).map_err(|e| Error::msg(format!("{}", e)))?);
let mut reader = exif_image_bytes.reader();
reader.read_exact(&mut entropy1)?;
reader.read_exact(&mut entropy2)?;
reader.read_exact(&mut nonce1)?;
reader.read_exact(&mut nonce2)?;
reader.read_to_end(&mut part1_ciphertext)?;
retrieved_key[..16].copy_from_slice(&Self::recover_part1(
&password,
&entropy1,
&nonce1,
&part1_ciphertext,
)?);
//@todo: get shardings from member managers!
let shardings = self.sharding.shares_vec.clone(); // temporary
let part2_recovered = Self::recover_part2(&password, &random_seed2, shardings);
let part2_trimmed = part2_recovered.trim_matches('"');
let recover_key_hex: String = format!("{}{}", part1_trimmed, part2_trimmed);
retrieved_key[16..].copy_from_slice(&Self::recover_part2(
&password, &entropy2, &nonce2, shardings,
)?);
Some(recover_key_hex)
let key = SecretKey::from_slice(&retrieved_key)?;
Ok(key)
}
fn recover_part1(password: &str, random_seed1: &str, part1_key_enc: &str) -> String {
let pwd_hash_part1 = from_hex_to_b64(&sha_256(&format!("{}{}", password, random_seed1)));
let key_dec_part1 = KeyEncryption::new(None, Some(pwd_hash_part1), None);
let part1_key_recovered = key_dec_part1
.decode(part1_key_enc.to_string())
.unwrap_or_else(|_| "".to_string());
part1_key_recovered
fn recover_part1(
password: &str,
entropy: &[u8],
nonce: &[u8],
part1_ciphertext: &[u8],
) -> Result<Vec<u8>> {
let mut engine = sha256::HashEngine::default();
engine.write_all(&password.as_bytes());
engine.write_all(&entropy);
let hash = sha256::Hash::from_engine(engine);
let key: &Key<Aes256Gcm> = hash.as_byte_array().try_into()?;
let cipher = Aes256Gcm::new(&key);
cipher
.decrypt(nonce.into(), part1_ciphertext)
.map_err(|e| anyhow::Error::msg(format!("{}", e)))
}
fn recover_part2(password: &str, random_seed2: &str, shares_vec: Vec<Vec<u8>>) -> String {
let quorum_sharding =
(Sharding::QUORUM_SHARD * f32::from(shares_vec.len() as u8)).round() as u8;
let part2_key_enc = SecretData::recover_secret(quorum_sharding, shares_vec).unwrap();
let pwd_hash_part2 = from_hex_to_b64(&sha_256(&format!("{}{}", password, random_seed2)));
let key_dec_part2 = KeyEncryption::new(None, Some(pwd_hash_part2), None);
let part2_key_recovered = key_dec_part2
.decode(part2_key_enc)
.unwrap_or_else(|_| "".to_string());
part2_key_recovered
fn recover_part2(
password: &str,
entropy: &[u8],
nonce: &[u8],
shares_vec: Vec<Vec<u8>>,
) -> Result<Vec<u8>> {
let mut engine = sha256::HashEngine::default();
engine.write_all(&password.as_bytes());
engine.write_all(&entropy);
let hash = sha256::Hash::from_engine(engine);
let shares_total: f32 = u8::try_from(shares_vec.len())?.try_into()?;
let quorum_sharding: u8 = (Sharding::QUORUM_SHARD * shares_total).round() as u8;
let part2_key_enc = Vec::from_hex(
&SecretData::recover_secret(quorum_sharding, shares_vec)
.ok_or_else(|| anyhow::Error::msg("Failed to retrieve the sharded secret"))?,
)?;
let key: &Key<Aes256Gcm> = hash.as_byte_array().try_into()?;
let cipher = Aes256Gcm::new(&key);
cipher
.decrypt(nonce.into(), &*part2_key_enc)
.map_err(|e| anyhow::Error::msg(format!("{}", e)))
}
//not used
pub fn pbkdf2(password: &str, data: &str) -> String {
let data_salt = data.trim_end_matches('=');
let salt = SaltString::from_b64(data_salt)
.map(|s| s)
.unwrap_or_else(|_| panic!("Failed to parse salt value from base64 string"));
// pub fn pbkdf2(password: &str, data: &str) -> String {
// let data_salt = data.trim_end_matches('=');
// let salt = SaltString::from_b64(data_salt)
// .map(|s| s)
// .unwrap_or_else(|_| panic!("Failed to parse salt value from base64 string"));
let mut password_hash = String::new();
if let Ok(pwd) = Scrypt.hash_password(password.as_bytes(), &salt) {
password_hash.push_str(&pwd.to_string());
}
sha_256(&password_hash)
}
pub fn get_image_recover(&self) -> Vec<u8> {
return self.image_recover.image_recover_bytes.clone();
}
// let mut password_hash = String::new();
// if let Ok(pwd) = Scrypt.hash_password(password.as_bytes(), &salt) {
// password_hash.push_str(&pwd.to_string());
// }
// sha_256(&password_hash)
// }
pub fn get_exif_image(&self, image: &[u8]) -> Vec<u8> {
return read_exif(image).expect("Error reading the exif");
}
pub fn get_image_revoke(&self) -> Vec<u8> {
return self.image_revoke.image_revoke_bytes.clone();
}
// Test sharing JS side
pub fn get_shares(&self) -> Vec<String> {
self.sharding.shares_format_str.clone()
@ -223,52 +281,21 @@ impl User {
}
}
#[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ImageRecover {
image_recover_bytes: Vec<u8>,
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum BackUpImage {
Recover(Vec<u8>),
Revoke(Vec<u8>),
}
impl ImageRecover {
pub fn new(
image_to_recover: &[u8],
random_seed1: &str,
random_seed2: &str,
part1_key_enc: &str,
) -> Self {
let data_exif_json = json!({
"random_seed1": random_seed1,
"random_seed2": random_seed2,
"part1_key_enc": part1_key_enc
});
let data = serde_json::to_string(&data_exif_json).unwrap();
let image_recover = write_exif(image_to_recover, &data);
ImageRecover {
image_recover_bytes: image_recover.expect("Image recover not generated!"),
}
impl BackUpImage {
pub fn new_recover(image: &[u8], data: &[u8]) -> Result<Self> {
let img = write_exif(image, data)?;
Ok(Self::Recover(img))
}
}
#[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ImageRevoke {
image_revoke_bytes: Vec<u8>,
}
impl ImageRevoke {
pub fn new(
image_to_revoke: &[u8],
priv_revoke_spend_key: &str,
priv_revoke_scan_key: &str,
) -> Self {
let data_exif_json = json!({
"priv_revoke_spend_key":priv_revoke_spend_key,
"priv_revoke_scan_key":priv_revoke_scan_key
});
let data = serde_json::to_string(&data_exif_json).unwrap();
let image_revoke = write_exif(image_to_revoke, &data);
ImageRevoke {
image_revoke_bytes: image_revoke.expect("Image revoke not generated!"),
}
pub fn new_revoke(image: &[u8], data: &[u8]) -> Result<Self> {
let img = write_exif(image, data)?;
Ok(Self::Recover(img))
}
}
@ -315,27 +342,20 @@ impl Sharding {
}
//associated functions
pub fn generate_random_key(length: usize) -> String {
pub fn generate_random_key(length: usize) -> Vec<u8> {
let mut rng = rand::thread_rng();
let random_bytes: Vec<u8> = (0..length).map(|_| rng.gen_range(0x00..=0xFF)).collect();
base64::encode(random_bytes)
let mut entropy = Vec::<u8>::with_capacity(length);
rng.fill_bytes(&mut entropy);
entropy
}
pub fn sha_256(data: &str) -> String {
let mut hasher = Sha256::new();
hasher.update(data);
let result = hasher.finalize();
hex::encode(result)
}
pub fn write_exif(image_to_recover: &[u8], data: &str) -> Result<Vec<u8>, String> {
let image_to_recover_bytes = Bytes::from(image_to_recover.to_vec());
let mut jpeg = Jpeg::from_bytes(image_to_recover_bytes).unwrap();
let data_bytes = Bytes::from(data.as_bytes().to_vec());
pub fn write_exif(image_to_recover: &[u8], data: &[u8]) -> Result<Vec<u8>> {
let mut jpeg = Jpeg::from_bytes(Bytes::from(image_to_recover.to_vec()))?;
let data_bytes = Bytes::from(data.to_owned());
jpeg.set_exif(Some(data_bytes));
let output_image_bytes = jpeg.encoder().bytes();
let output_image = output_image_bytes.as_ref();
Ok(output_image.to_vec())
let output_image = output_image_bytes.to_vec();
Ok(output_image)
}
pub fn read_exif(image: &[u8]) -> Result<Vec<u8>, String> {

View File

@ -1,4 +1,4 @@
import { GenerateSpWalletReturn } from '../dist/pkg/sdk_client';
import { generate_sp_wallet_return, User } from '../dist/pkg/sdk_client';
import IndexedDB from './database'
import Processstore from './store/processstore';
import Userstore from './store/userstore';
@ -26,7 +26,7 @@ class Services {
this.sdkClient.setup();
}
public new_sp_client(label: string, current_tip: number, is_testnet: boolean): GenerateSpWalletReturn {
public new_sp_client(label: string, current_tip: number, is_testnet: boolean): generate_sp_wallet_return {
return this.sdkClient.generate_sp_wallet(label, current_tip, is_testnet);
}
@ -91,12 +91,12 @@ class Services {
if (!Services.instance.isPasswordValid(password)) return;
// TODO get secretpart1 from User object
// const user = new this.sdkClient.User(password);
let secretpart1 = "LKHGKJJJ3H";
// const user: User = new this.sdkClient.create_user(password);
const user: User = this.sdkClient.create_user(password);
// let secretpart1 = "LKHGKJJJ3H";
try {
let userstore = new Userstore;
userstore.secretpart1 = secretpart1;
userstore.process = process;
const indexedDb = await IndexedDB.getInstance();
const db = indexedDb.getDb();