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
//! keystore

pub mod json;
pub mod key;
pub mod node;

use crate::{
    api::config::GearConfig,
    keystore::key::Key,
    result::{Error, Result},
    utils,
};
use lazy_static::lazy_static;
use std::{
    fs,
    path::{Path, PathBuf},
};
use subxt::{sp_core::sr25519, PairSigner};

lazy_static! {
    // @WARNING: THIS WILL ONLY BE SECURE IF THE keystore IS SECURE.
    // when you have NO PASSWORD, If it can be got by an attacker then
    // they can also get your key.
    static ref KEYSTORE_PATH: PathBuf = utils::home().join("keystore");

    // @WARNING: THIS WILL ONLY BE SECURE IF THE keystore IS SECURE.
    // when you have NO PASSWORD, If it can be got by an attacker then
    // they can also get your key.
    static ref KEYSTORE_JSON_PATH: PathBuf = utils::home().join("keystore.json");
}

/// Generate a new keypair.
///
/// @WARNING: THIS WILL ONLY BE SECURE IF THE keystore IS SECURE.
/// when you have NO PASSWORD, If it can be got by an attacker then
/// they can also get your key.
pub fn generate(passwd: Option<&str>) -> Result<PairSigner<GearConfig, sr25519::Pair>> {
    let pair = Key::generate_with_phrase::<sr25519::Pair>(passwd)?;
    fs::write(&*KEYSTORE_PATH, pair.1)?;

    Ok(pair.0)
}

/// Login with suri.
///
/// @WARNING: THIS WILL ONLY BE SECURE IF THE keystore IS SECURE.
/// when you have NO PASSWORD, If it can be got by an attacker then
/// they can also get your key.
pub fn login(suri: &str, passwd: Option<&str>) -> Result<PairSigner<GearConfig, sr25519::Pair>> {
    let pair = Key::from_string(suri).pair::<sr25519::Pair>(passwd)?;
    fs::write(&*KEYSTORE_PATH, suri)?;

    Ok(pair.0)
}

/// Get signer from cache.
///
/// @WARNING: THIS WILL ONLY BE SECURE IF THE keystore IS SECURE.
/// when you have NO PASSWORD, If it can be got by an attacker then
/// they can also get your key.
pub fn cache(passwd: Option<&str>) -> Result<PairSigner<GearConfig, sr25519::Pair>> {
    let pair = if (*KEYSTORE_PATH).exists() {
        let suri = fs::read_to_string(&*KEYSTORE_PATH).map_err(|_| Error::Logout)?;
        Key::from_string(&suri).pair::<sr25519::Pair>(passwd)?.0
    } else if (*KEYSTORE_JSON_PATH).exists() {
        decode_json_file(&*KEYSTORE_JSON_PATH, passwd)?
    } else {
        return Err(Error::Logout);
    };

    Ok(pair)
}

/// Decode pair from json file.
///
/// @WARNING: THIS WILL ONLY BE SECURE IF THE keystore IS SECURE.
/// when you have NO PASSWORD, If it can be got by an attacker then
/// they can also get your key.
pub fn decode_json_file(
    path: impl AsRef<Path>,
    passphrase: Option<&str>,
) -> Result<PairSigner<GearConfig, sr25519::Pair>> {
    let encrypted = serde_json::from_slice::<json::Encrypted>(&fs::read(&path)?)?;
    let pair = encrypted.create(passphrase.ok_or(Error::InvalidPassword)?)?;

    fs::copy(path, &*KEYSTORE_JSON_PATH)?;
    Ok(PairSigner::new(pair))
}