Merge branch 'release'
|
|
@ -3379,6 +3379,12 @@ namespace tools
|
|||
return wordsArray[n];
|
||||
}
|
||||
|
||||
bool valid_word(const std::string& w)
|
||||
{
|
||||
auto it = wordsMap.find(w);
|
||||
return it != wordsMap.end();
|
||||
}
|
||||
|
||||
uint64_t num_by_word(const std::string& w)
|
||||
{
|
||||
auto it = wordsMap.find(w);
|
||||
|
|
|
|||
|
|
@ -46,5 +46,6 @@ namespace tools
|
|||
std::string binary2text(const std::vector<unsigned char>& binary);
|
||||
std::string word_by_num(uint32_t n);
|
||||
uint64_t num_by_word(const std::string& w);
|
||||
bool valid_word(const std::string& w);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,14 +12,14 @@ DISABLE_VS_WARNINGS(4146 4244)
|
|||
|
||||
/* Predeclarations */
|
||||
|
||||
static void fe_mul(fe, const fe, const fe);
|
||||
static void fe_sq(fe, const fe);
|
||||
static void fe_tobytes(unsigned char *, const fe);
|
||||
void fe_mul(fe, const fe, const fe);
|
||||
void fe_sq(fe, const fe);
|
||||
void fe_tobytes(unsigned char *, const fe);
|
||||
static void ge_madd(ge_p1p1 *, const ge_p3 *, const ge_precomp *);
|
||||
static void ge_msub(ge_p1p1 *, const ge_p3 *, const ge_precomp *);
|
||||
static void ge_p2_0(ge_p2 *);
|
||||
static void ge_p3_dbl(ge_p1p1 *, const ge_p3 *);
|
||||
static void ge_sub(ge_p1p1 *, const ge_p3 *, const ge_cached *);
|
||||
void ge_sub(ge_p1p1 *, const ge_p3 *, const ge_cached *);
|
||||
static void fe_divpowm1(fe, const fe, const fe);
|
||||
|
||||
/* Common functions */
|
||||
|
|
@ -48,7 +48,7 @@ static uint64_t load_4(const unsigned char *in)
|
|||
h = 0
|
||||
*/
|
||||
|
||||
static void fe_0(fe h) {
|
||||
void fe_0(fe h) {
|
||||
h[0] = 0;
|
||||
h[1] = 0;
|
||||
h[2] = 0;
|
||||
|
|
@ -232,7 +232,7 @@ static void fe_copy(fe h, const fe f) {
|
|||
|
||||
/* From fe_invert.c */
|
||||
|
||||
static void fe_invert(fe out, const fe z) {
|
||||
void fe_invert(fe out, const fe z) {
|
||||
fe t0;
|
||||
fe t1;
|
||||
fe t2;
|
||||
|
|
@ -351,7 +351,7 @@ Can get away with 11 carries, but then data flow is much deeper.
|
|||
With tighter constraints on inputs can squeeze carries into int32.
|
||||
*/
|
||||
|
||||
static void fe_mul(fe h, const fe f, const fe g) {
|
||||
void fe_mul(fe h, const fe f, const fe g) {
|
||||
int32_t f0 = f[0];
|
||||
int32_t f1 = f[1];
|
||||
int32_t f2 = f[2];
|
||||
|
|
@ -631,7 +631,7 @@ Postconditions:
|
|||
See fe_mul.c for discussion of implementation strategy.
|
||||
*/
|
||||
|
||||
static void fe_sq(fe h, const fe f) {
|
||||
void fe_sq(fe h, const fe f) {
|
||||
int32_t f0 = f[0];
|
||||
int32_t f1 = f[1];
|
||||
int32_t f2 = f[2];
|
||||
|
|
@ -1005,7 +1005,7 @@ Proof:
|
|||
so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
|
||||
*/
|
||||
|
||||
static void fe_tobytes(unsigned char *s, const fe h) {
|
||||
void fe_tobytes(unsigned char *s, const fe h) {
|
||||
int32_t h0 = h[0];
|
||||
int32_t h1 = h[1];
|
||||
int32_t h2 = h[2];
|
||||
|
|
@ -1398,7 +1398,7 @@ void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) {
|
|||
|
||||
/* From ge_p3_0.c */
|
||||
|
||||
static void ge_p3_0(ge_p3 *h) {
|
||||
void ge_p3_0(ge_p3 *h) {
|
||||
fe_0(h->X);
|
||||
fe_1(h->Y);
|
||||
fe_1(h->Z);
|
||||
|
|
@ -1565,7 +1565,7 @@ void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) {
|
|||
r = p - q
|
||||
*/
|
||||
|
||||
static void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
|
||||
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
|
||||
fe t0;
|
||||
fe_add(r->X, p->Y, p->X);
|
||||
fe_sub(r->Y, p->Y, p->X);
|
||||
|
|
@ -2963,3 +2963,53 @@ int sc_isnonzero(const unsigned char *s) {
|
|||
s[18] | s[19] | s[20] | s[21] | s[22] | s[23] | s[24] | s[25] | s[26] |
|
||||
s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1;
|
||||
}
|
||||
|
||||
// see implmentation of ge_frombytes_vartime above
|
||||
void fe_frombytes(fe h, const unsigned char *s)
|
||||
{
|
||||
/* From fe_frombytes.c */
|
||||
|
||||
int64_t h0 = load_4(s);
|
||||
int64_t h1 = load_3(s + 4) << 6;
|
||||
int64_t h2 = load_3(s + 7) << 5;
|
||||
int64_t h3 = load_3(s + 10) << 3;
|
||||
int64_t h4 = load_3(s + 13) << 2;
|
||||
int64_t h5 = load_4(s + 16);
|
||||
int64_t h6 = load_3(s + 20) << 7;
|
||||
int64_t h7 = load_3(s + 23) << 5;
|
||||
int64_t h8 = load_3(s + 26) << 4;
|
||||
int64_t h9 = (load_3(s + 29) & 8388607) << 2;
|
||||
int64_t carry0;
|
||||
int64_t carry1;
|
||||
int64_t carry2;
|
||||
int64_t carry3;
|
||||
int64_t carry4;
|
||||
int64_t carry5;
|
||||
int64_t carry6;
|
||||
int64_t carry7;
|
||||
int64_t carry8;
|
||||
int64_t carry9;
|
||||
|
||||
carry9 = (h9 + (int64_t)(1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
|
||||
carry1 = (h1 + (int64_t)(1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
|
||||
carry3 = (h3 + (int64_t)(1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
|
||||
carry5 = (h5 + (int64_t)(1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
|
||||
carry7 = (h7 + (int64_t)(1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
|
||||
|
||||
carry0 = (h0 + (int64_t)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
|
||||
carry2 = (h2 + (int64_t)(1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
|
||||
carry4 = (h4 + (int64_t)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
|
||||
carry6 = (h6 + (int64_t)(1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
|
||||
carry8 = (h8 + (int64_t)(1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
|
||||
|
||||
h[0] = h0;
|
||||
h[1] = h1;
|
||||
h[2] = h2;
|
||||
h[3] = h3;
|
||||
h[4] = h4;
|
||||
h[5] = h5;
|
||||
h[6] = h6;
|
||||
h[7] = h7;
|
||||
h[8] = h8;
|
||||
h[9] = h9;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,13 +104,17 @@ void ge_scalarmult(ge_p2 *, const unsigned char *, const ge_p3 *);
|
|||
void ge_scalarmult_p3(ge_p3 *, const unsigned char *, const ge_p3 *);
|
||||
void ge_double_scalarmult_precomp_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *, const ge_dsmp);
|
||||
void ge_mul8(ge_p1p1 *, const ge_p2 *);
|
||||
void ge_fromfe_frombytes_vartime(ge_p2 *, const unsigned char *);
|
||||
void ge_p3_0(ge_p3 *h);
|
||||
void ge_sub(ge_p1p1 *, const ge_p3 *, const ge_cached *);
|
||||
|
||||
extern const fe fe_ma2;
|
||||
extern const fe fe_ma;
|
||||
extern const fe fe_fffb1;
|
||||
extern const fe fe_fffb2;
|
||||
extern const fe fe_fffb3;
|
||||
extern const fe fe_fffb4;
|
||||
void ge_fromfe_frombytes_vartime(ge_p2 *, const unsigned char *);
|
||||
|
||||
void sc_0(unsigned char *);
|
||||
void sc_reduce32(unsigned char *);
|
||||
void sc_add(unsigned char *, const unsigned char *, const unsigned char *);
|
||||
|
|
@ -118,3 +122,9 @@ void sc_sub(unsigned char *, const unsigned char *, const unsigned char *);
|
|||
void sc_mulsub(unsigned char *, const unsigned char *, const unsigned char *, const unsigned char *);
|
||||
int sc_check(const unsigned char *);
|
||||
int sc_isnonzero(const unsigned char *); /* Doesn't normalize */
|
||||
|
||||
void fe_sq(fe h, const fe f);
|
||||
void fe_mul(fe, const fe, const fe);
|
||||
void fe_frombytes(fe h, const unsigned char *s);
|
||||
void fe_invert(fe out, const fe z);
|
||||
void fe_tobytes(unsigned char *s, const fe h);
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ namespace crypto {
|
|||
uint8_t* const m_p_data;
|
||||
size_t m_data_used;
|
||||
bool m_ready;
|
||||
};
|
||||
}; // class stream_cn_hash
|
||||
|
||||
} // namespace crypto
|
||||
|
||||
|
|
|
|||
|
|
@ -60,18 +60,42 @@ namespace currency
|
|||
return m_keys;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
std::string account_base::get_seed_phrase() const
|
||||
void crypt_with_pass(const void* scr_data, std::size_t src_length, void* dst_data, const std::string& password)
|
||||
{
|
||||
crypto::chacha8_key key = AUTO_VAL_INIT(key);
|
||||
crypto::generate_chacha8_key(password, key);
|
||||
crypto::hash pass_hash = crypto::cn_fast_hash(password.data(), password.size());
|
||||
crypto::chacha8_iv iv = AUTO_VAL_INIT(iv);
|
||||
CHECK_AND_ASSERT_THROW_MES(sizeof(pass_hash) >= sizeof(iv), "Invalid configuration: hash size is less than keys_file_data.iv");
|
||||
iv = *((crypto::chacha8_iv*)&pass_hash);
|
||||
crypto::chacha8(scr_data, src_length, key, iv, (char*)dst_data);
|
||||
}
|
||||
|
||||
|
||||
std::string account_base::get_seed_phrase(const std::string& password) const
|
||||
{
|
||||
if (m_keys_seed_binary.empty())
|
||||
return "";
|
||||
std::string keys_seed_text = tools::mnemonic_encoding::binary2text(m_keys_seed_binary);
|
||||
std::string timestamp_word = currency::get_word_from_timstamp(m_creation_timestamp);
|
||||
|
||||
std::vector<unsigned char> processed_seed_binary = m_keys_seed_binary;
|
||||
if (!password.empty())
|
||||
{
|
||||
//encrypt seed phrase binary data
|
||||
crypt_with_pass(&m_keys_seed_binary[0], m_keys_seed_binary.size(), &processed_seed_binary[0], password);
|
||||
}
|
||||
|
||||
std::string keys_seed_text = tools::mnemonic_encoding::binary2text(processed_seed_binary);
|
||||
std::string timestamp_word = currency::get_word_from_timstamp(m_creation_timestamp, !password.empty());
|
||||
|
||||
// floor creation time to WALLET_BRAIN_DATE_QUANTUM to make checksum calculation stable
|
||||
uint64_t creation_timestamp_rounded = get_timstamp_from_word(timestamp_word);
|
||||
bool self_check_is_password_used = false;
|
||||
uint64_t creation_timestamp_rounded = get_timstamp_from_word(timestamp_word, self_check_is_password_used);
|
||||
CHECK_AND_ASSERT_THROW_MES(self_check_is_password_used == !password.empty(), "Account seed phrase internal error: password flag encoded wrong");
|
||||
|
||||
constexpr uint16_t checksum_max = tools::mnemonic_encoding::NUMWORDS >> 1; // maximum value of checksum
|
||||
crypto::hash h = crypto::cn_fast_hash(m_keys_seed_binary.data(), m_keys_seed_binary.size());
|
||||
std::string binary_for_check_sum((const char*)&m_keys_seed_binary[0], m_keys_seed_binary.size());
|
||||
binary_for_check_sum.append(password);
|
||||
crypto::hash h = crypto::cn_fast_hash(binary_for_check_sum.data(), binary_for_check_sum.size());
|
||||
*reinterpret_cast<uint64_t*>(&h) = creation_timestamp_rounded;
|
||||
h = crypto::cn_fast_hash(&h, sizeof h);
|
||||
uint64_t h_64 = *reinterpret_cast<uint64_t*>(&h);
|
||||
|
|
@ -104,7 +128,7 @@ namespace currency
|
|||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
bool account_base::restore_from_seed_phrase(const std::string& seed_phrase)
|
||||
bool account_base::restore_from_seed_phrase(const std::string& seed_phrase, const std::string& seed_password)
|
||||
{
|
||||
//cut the last timestamp word from restore_dats
|
||||
std::list<std::string> words;
|
||||
|
|
@ -135,12 +159,39 @@ namespace currency
|
|||
|
||||
uint64_t auditable_flag_and_checksum = UINT64_MAX;
|
||||
if (!auditable_flag_and_checksum_word.empty())
|
||||
auditable_flag_and_checksum = tools::mnemonic_encoding::num_by_word(auditable_flag_and_checksum_word);
|
||||
{
|
||||
try {
|
||||
auditable_flag_and_checksum = tools::mnemonic_encoding::num_by_word(auditable_flag_and_checksum_word);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
std::vector<unsigned char> keys_seed_binary = tools::mnemonic_encoding::text2binary(keys_seed_text);
|
||||
CHECK_AND_ASSERT_MES(keys_seed_binary.size(), false, "text2binary failed to convert the given text"); // don't prints event incorrect seed into the log for security
|
||||
std::vector<unsigned char> keys_seed_processed_binary = keys_seed_binary;
|
||||
|
||||
m_creation_timestamp = get_timstamp_from_word(timestamp_word);
|
||||
|
||||
bool has_password = false;
|
||||
try {
|
||||
m_creation_timestamp = get_timstamp_from_word(timestamp_word, has_password);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//double check is password setting from timestamp word match with passed parameters
|
||||
CHECK_AND_ASSERT_MES(has_password != seed_password.empty(), false, "Seed phrase password wrong interpretation");
|
||||
if (has_password)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!seed_password.empty(), false, "Seed phrase password wrong interpretation: internal error");
|
||||
crypt_with_pass(&keys_seed_binary[0], keys_seed_binary.size(), &keys_seed_processed_binary[0], seed_password);
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(keys_seed_processed_binary.size(), false, "text2binary failed to convert the given text"); // don't prints event incorrect seed into the log for security
|
||||
|
||||
bool auditable_flag = false;
|
||||
|
||||
|
|
@ -150,18 +201,24 @@ namespace currency
|
|||
auditable_flag = (auditable_flag_and_checksum & 1) != 0; // auditable flag is the lower 1 bit
|
||||
uint16_t checksum = static_cast<uint16_t>(auditable_flag_and_checksum >> 1); // checksum -- everything else
|
||||
constexpr uint16_t checksum_max = tools::mnemonic_encoding::NUMWORDS >> 1; // maximum value of checksum
|
||||
crypto::hash h = crypto::cn_fast_hash(keys_seed_binary.data(), keys_seed_binary.size());
|
||||
std::string binary_for_check_sum((const char*)&keys_seed_processed_binary[0], keys_seed_processed_binary.size());
|
||||
binary_for_check_sum.append(seed_password);
|
||||
crypto::hash h = crypto::cn_fast_hash(binary_for_check_sum.data(), binary_for_check_sum.size());
|
||||
*reinterpret_cast<uint64_t*>(&h) = m_creation_timestamp;
|
||||
h = crypto::cn_fast_hash(&h, sizeof h);
|
||||
uint64_t h_64 = *reinterpret_cast<uint64_t*>(&h);
|
||||
uint16_t checksum_calculated = h_64 % (checksum_max + 1);
|
||||
CHECK_AND_ASSERT_MES(checksum == checksum_calculated, false, "seed phase has invalid checksum: " << checksum_calculated << ", while " << checksum << " is expected, check your words");
|
||||
if (checksum != checksum_calculated)
|
||||
{
|
||||
LOG_PRINT_L0("seed phase has invalid checksum: " << checksum_calculated << ", while " << checksum << " is expected, check your words");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool r = restore_keys(keys_seed_binary);
|
||||
bool r = restore_keys(keys_seed_processed_binary);
|
||||
CHECK_AND_ASSERT_MES(r, false, "restore_keys failed");
|
||||
|
||||
m_keys_seed_binary = keys_seed_binary;
|
||||
m_keys_seed_binary = keys_seed_processed_binary;
|
||||
|
||||
if (auditable_flag)
|
||||
m_keys.account_address.flags |= ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE;
|
||||
|
|
@ -169,6 +226,46 @@ namespace currency
|
|||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
bool account_base::is_seed_tracking(const std::string& seed_phrase)
|
||||
{
|
||||
return seed_phrase.find(':') != std::string::npos;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
bool account_base::is_seed_password_protected(const std::string& seed_phrase, bool& is_password_protected)
|
||||
{
|
||||
//cut the last timestamp word from restore_dats
|
||||
std::list<std::string> words;
|
||||
boost::split(words, seed_phrase, boost::is_space());
|
||||
|
||||
//let's validate each word
|
||||
for (const auto& w: words)
|
||||
{
|
||||
if (!tools::mnemonic_encoding::valid_word(w))
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string timestamp_word;
|
||||
if (words.size() == SEED_PHRASE_V1_WORDS_COUNT)
|
||||
{
|
||||
// 24 seed words + one timestamp word = 25 total
|
||||
timestamp_word = words.back();
|
||||
}
|
||||
else if (words.size() == SEED_PHRASE_V2_WORDS_COUNT)
|
||||
{
|
||||
// 24 seed words + one timestamp word + one flags & checksum = 26 total
|
||||
words.erase(--words.end());
|
||||
timestamp_word = words.back();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
get_timstamp_from_word(timestamp_word, is_password_protected);
|
||||
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
bool account_base::restore_from_tracking_seed(const std::string& tracking_seed)
|
||||
{
|
||||
set_null();
|
||||
|
|
|
|||
|
|
@ -53,9 +53,9 @@ namespace currency
|
|||
const account_public_address& get_public_address() const { return m_keys.account_address; };
|
||||
std::string get_public_address_str() const;
|
||||
|
||||
std::string get_seed_phrase() const;
|
||||
std::string get_seed_phrase(const std::string& seed_password) const;
|
||||
std::string get_tracking_seed() const;
|
||||
bool restore_from_seed_phrase(const std::string& seed_phrase);
|
||||
bool restore_from_seed_phrase(const std::string& seed_phrase, const std::string& seed_password);
|
||||
bool restore_from_tracking_seed(const std::string& tracking_seed);
|
||||
|
||||
uint64_t get_createtime() const { return m_creation_timestamp; }
|
||||
|
|
@ -78,6 +78,8 @@ namespace currency
|
|||
|
||||
static std::string vector_of_chars_to_string(const std::vector<unsigned char>& v) { return std::string(v.begin(), v.end()); }
|
||||
static std::vector<unsigned char> string_to_vector_of_chars(const std::string& v) { return std::vector<unsigned char>(v.begin(), v.end()); }
|
||||
static bool is_seed_password_protected(const std::string& seed_phrase, bool& is_password_protected);
|
||||
static bool is_seed_tracking(const std::string& seed_phrase);
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(m_keys)
|
||||
|
|
|
|||
|
|
@ -150,9 +150,10 @@
|
|||
|
||||
#define WALLET_FILE_MAX_KEYS_SIZE 10000 //
|
||||
#define WALLET_BRAIN_DATE_OFFSET 1543622400
|
||||
#define WALLET_BRAIN_DATE_QUANTUM 604800 //by last word we encode a number of week since launch of the project,
|
||||
#define WALLET_BRAIN_DATE_QUANTUM 604800 //by last word we encode a number of week since launch of the project AND password flag,
|
||||
//which let us to address tools::mnemonic_encoding::NUMWORDS weeks after project launch
|
||||
//which is about 30 years
|
||||
//which is about 15 years
|
||||
#define WALLET_BRAIN_DATE_MAX_WEEKS_COUNT 800
|
||||
|
||||
#define OFFER_MAXIMUM_LIFE_TIME (60*60*24*30) // 30 days
|
||||
|
||||
|
|
|
|||
|
|
@ -1316,21 +1316,34 @@ namespace currency
|
|||
return reward;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
std::string get_word_from_timstamp(uint64_t timestamp)
|
||||
std::string get_word_from_timstamp(uint64_t timestamp, bool use_password)
|
||||
{
|
||||
uint64_t date_offset = timestamp > WALLET_BRAIN_DATE_OFFSET ? timestamp - WALLET_BRAIN_DATE_OFFSET : 0;
|
||||
uint64_t weeks_count = date_offset / WALLET_BRAIN_DATE_QUANTUM;
|
||||
CHECK_AND_ASSERT_THROW_MES(weeks_count < WALLET_BRAIN_DATE_MAX_WEEKS_COUNT, "SEED PHRASE need to be extended or refactored");
|
||||
|
||||
if (use_password)
|
||||
weeks_count += WALLET_BRAIN_DATE_MAX_WEEKS_COUNT;
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(weeks_count < std::numeric_limits<uint32_t>::max(), "internal error: unable to convert to uint32, val = " << weeks_count);
|
||||
uint32_t weeks_count_32 = static_cast<uint32_t>(weeks_count);
|
||||
|
||||
return tools::mnemonic_encoding::word_by_num(weeks_count_32);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_timstamp_from_word(std::string word)
|
||||
uint64_t get_timstamp_from_word(std::string word, bool& password_used)
|
||||
{
|
||||
uint64_t count_of_weeks = tools::mnemonic_encoding::num_by_word(word);
|
||||
if (count_of_weeks >= WALLET_BRAIN_DATE_MAX_WEEKS_COUNT)
|
||||
{
|
||||
count_of_weeks -= WALLET_BRAIN_DATE_MAX_WEEKS_COUNT;
|
||||
password_used = true;
|
||||
}
|
||||
else {
|
||||
password_used = false;
|
||||
}
|
||||
uint64_t timestamp = count_of_weeks * WALLET_BRAIN_DATE_QUANTUM + WALLET_BRAIN_DATE_OFFSET;
|
||||
|
||||
|
||||
return timestamp;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -291,8 +291,8 @@ namespace currency
|
|||
bool fill_tx_rpc_details(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce, const crypto::hash& h, uint64_t timestamp, bool is_short = false);
|
||||
bool fill_block_rpc_details(block_rpc_extended_info& pei_rpc, const block_extended_info& bei_chain, const crypto::hash& h);
|
||||
void append_per_block_increments_for_tx(const transaction& tx, std::unordered_map<uint64_t, uint32_t>& gindices);
|
||||
std::string get_word_from_timstamp(uint64_t timestamp);
|
||||
uint64_t get_timstamp_from_word(std::string word);
|
||||
std::string get_word_from_timstamp(uint64_t timestamp, bool use_password);
|
||||
uint64_t get_timstamp_from_word(std::string word, bool& password_used);
|
||||
|
||||
template<class t_txin_v>
|
||||
typename std::conditional<std::is_const<t_txin_v>::value, const std::vector<txin_etc_details_v>, std::vector<txin_etc_details_v> >::type& get_txin_etc_options(t_txin_v& in)
|
||||
|
|
|
|||
|
|
@ -4,9 +4,7 @@
|
|||
<dict>
|
||||
<key>LSEnvironment</key>
|
||||
<dict>
|
||||
<key>QTWEBENGINE_REMOTE_DEBUGGING</key>
|
||||
<string>11113</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>BuildMachineOSBuild</key>
|
||||
<string>14E46</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
|
|
|
|||
|
|
@ -1676,7 +1676,7 @@ QString MainWindow::restore_wallet(const QString& param)
|
|||
//return que_call2<view::restore_wallet_request>("restore_wallet", param, [this](const view::restore_wallet_request& owd, view::api_response& ar){
|
||||
PREPARE_ARG_FROM_JSON(view::restore_wallet_request, owd);
|
||||
PREPARE_RESPONSE(view::open_wallet_response, ar);
|
||||
ar.error_code = m_backend.restore_wallet(epee::string_encoding::utf8_to_wstring(owd.path), owd.pass, owd.restore_key, ar.response_data);
|
||||
ar.error_code = m_backend.restore_wallet(epee::string_encoding::utf8_to_wstring(owd.path), owd.pass, owd.seed_phrase, owd.seed_pass, ar.response_data);
|
||||
return MAKE_RESPONSE(ar);
|
||||
CATCH_ENTRY_FAIL_API_RESPONCE();
|
||||
}
|
||||
|
|
@ -1877,9 +1877,9 @@ QString MainWindow::get_smart_wallet_info(const QString& param)
|
|||
{
|
||||
TRY_ENTRY();
|
||||
LOG_API_TIMING();
|
||||
PREPARE_ARG_FROM_JSON(view::wallet_id_obj, wo);
|
||||
PREPARE_ARG_FROM_JSON(view::request_get_smart_wallet_info, wo);
|
||||
PREPARE_RESPONSE(view::get_restore_info_response, ar);
|
||||
ar.error_code = m_backend.get_wallet_restore_info(wo.wallet_id, ar.response_data.restore_key);
|
||||
ar.error_code = m_backend.get_wallet_restore_info(wo.wallet_id, ar.response_data.seed_phrase, wo.seed_password);
|
||||
return MAKE_RESPONSE(ar);
|
||||
CATCH_ENTRY_FAIL_API_RESPONCE();
|
||||
}
|
||||
|
|
@ -1973,14 +1973,27 @@ QString MainWindow::open_url_in_browser(const QString& param)
|
|||
CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
|
||||
QString MainWindow::is_valid_restore_wallet_text(const QString& param)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
LOG_API_TIMING();
|
||||
return m_backend.is_valid_brain_restore_data(param.toStdString()).c_str();
|
||||
PREPARE_ARG_FROM_JSON(view::seed_info_param, rwtp);
|
||||
return m_backend.is_valid_brain_restore_data(rwtp.seed_phrase, rwtp.seed_password).c_str();
|
||||
CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
QString MainWindow::get_seed_phrase_info(const QString& param)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
LOG_API_TIMING();
|
||||
PREPARE_ARG_FROM_JSON(view::seed_info_param, rwtp);
|
||||
PREPARE_RESPONSE(view::seed_phrase_info, ar);
|
||||
ar.error_code = m_backend.get_seed_phrase_info(rwtp.seed_phrase, rwtp.seed_password, ar.response_data).c_str();
|
||||
LOG_PRINT_CYAN("[get_seed_phrase_info]:" << epee::serialization::store_t_to_json(ar), LOG_LEVEL_0);
|
||||
return MAKE_RESPONSE(ar);
|
||||
CATCH_ENTRY_FAIL_API_RESPONCE();
|
||||
}
|
||||
|
||||
void MainWindow::contextMenuEvent(QContextMenuEvent * event)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ public:
|
|||
QString is_autostart_enabled();
|
||||
QString toggle_autostart(const QString& param);
|
||||
QString is_valid_restore_wallet_text(const QString& param);
|
||||
QString get_seed_phrase_info(const QString& param);
|
||||
QString print_text(const QString& param);
|
||||
QString print_log(const QString& param);
|
||||
QString set_clipboard(const QString& param);
|
||||
|
|
|
|||
|
|
@ -120,13 +120,16 @@
|
|||
"BUTTON_CREATE": "Create wallet",
|
||||
"NOT_CORRECT_FILE_OR_PASSWORD": "Invalid wallet file or password does not match",
|
||||
"CHOOSE_PATH": "Please choose a path",
|
||||
"SEED_PASSWORD": "Seed password",
|
||||
"OK": "OK",
|
||||
"FORM_ERRORS": {
|
||||
"NAME_REQUIRED": "Name is required",
|
||||
"NAME_DUPLICATE": "Name is duplicate",
|
||||
"MAX_LENGTH": "Maximum name length reached",
|
||||
"CONFIRM_NOT_MATCH": "Confirm password not match",
|
||||
"KEY_REQUIRED": "Key is required",
|
||||
"KEY_NOT_VALID": "Key not valid"
|
||||
"KEY_NOT_VALID": "Key not valid",
|
||||
"INCORRECT_PASSWORD": "Incorrect password"
|
||||
}
|
||||
},
|
||||
"SEED_PHRASE": {
|
||||
|
|
@ -214,10 +217,21 @@
|
|||
"SEED_PHRASE_HINT": "Click to reveal the seed phrase",
|
||||
"BUTTON_SAVE": "Save",
|
||||
"BUTTON_REMOVE": "Close wallet",
|
||||
"CREATE_PASSWORD_SECURE": "Create a password to secure your seed",
|
||||
"INFO": "info",
|
||||
"SEED_IS_UNSECURED": "Seed is unsecured",
|
||||
"SEED_IS_SECURED": "Seed is secured",
|
||||
"REMEMBER_YOU_WILL_REQUIRE": "Remember, you will require the password to restore it.",
|
||||
"FORM": {
|
||||
"CONFIRM_PASSWORD": "Confirm password",
|
||||
"GENERATE_SECURE_SEED": "Generate Secure Seed",
|
||||
"SECURED_SEED_WILL_REQUIRE": "Secured seed will require this password to restore."
|
||||
},
|
||||
"FORM_ERRORS": {
|
||||
"NAME_REQUIRED": "Name is required",
|
||||
"NAME_DUPLICATE": "Name is duplicate",
|
||||
"MAX_LENGTH": "Maximum name length reached"
|
||||
"MAX_LENGTH": "Maximum name length reached",
|
||||
"PASSWORDS_DONT_MATCH": "Passwords don't match"
|
||||
}
|
||||
},
|
||||
"ASSIGN_ALIAS": {
|
||||
|
|
|
|||
1
src/gui/qt-daemon/html/assets/icons/info.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 384"><defs><style>.cls-1{fill:#fff;}</style></defs><title>info</title><path class="cls-1" d="M192,42.05476A149.94522,149.94522,0,0,1,298.02728,298.02728,149.94522,149.94522,0,1,1,85.97271,85.97271,148.96374,148.96374,0,0,1,192,42.05476M192,0C85.96132,0,0,85.96132,0,192S85.96132,384,192,384s192-85.96132,192-192S298.03868,0,192,0Z"/><rect class="cls-1" x="171" y="247.94524" width="42" height="42"/><rect class="cls-1" x="171" y="94.05476" width="42" height="120"/></svg>
|
||||
|
After Width: | Height: | Size: 561 B |
21
src/gui/qt-daemon/html/assets/icons/safety.svg
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Слой_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 320 384" style="enable-background:new 0 0 320 384;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{clip-path:url(#SVGID_2_);}
|
||||
.st1{clip-path:url(#SVGID_2_);fill:none;stroke:#000000;stroke-width:42;stroke-miterlimit:10;}
|
||||
</style>
|
||||
<g>
|
||||
<defs>
|
||||
<rect id="SVGID_1_" width="320" height="384"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_2_">
|
||||
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>
|
||||
</clipPath>
|
||||
<path class="st0" d="M159.9,44.5L278,85.8V232c0,0.9-0.4,9.2-14.7,26c-11,13-26.9,27.1-47.3,42c-20.6,15.1-41.6,27.8-56.1,36.1
|
||||
c-14.5-8.3-35.4-21-56-36.1c-20.3-14.9-36.2-29-47.2-42C42.4,241.2,42,232.9,42,232V85.8L159.9,44.5 M159.9,0L0,56v176
|
||||
c0,70.7,159.9,152,159.9,152S320,302.7,320,232V56L159.9,0z"/>
|
||||
<polyline class="st1" points="100.1,182.2 142.3,218.5 220.3,145.1 "/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1 KiB |
10
src/gui/qt-daemon/html/assets/icons/secured.svg
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 32 32" style="enable-background:new 0 0 32 32;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path class="st0" d="M26,15v-5c0-5.5-4.5-10-10-10h-0.1c-5.5,0-10,4.5-10,10v5H3v17h12.9H16h13V15H26z M9.9,10c0-3.3,2.7-6,6-6H16
|
||||
c3.3,0,6,2.7,6,6v5H9.9V10z M14,27v-7h4v7H14z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 582 B |
10
src/gui/qt-daemon/html/assets/icons/unsecured.svg
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 32 32" style="enable-background:new 0 0 32 32;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path class="st0" d="M22,15h-3.4H9.9v-5c0-3.3,2.7-6,6-6H16c3,0,5.4,2.2,5.9,5h4c-0.5-5-4.8-9-9.9-9h-0.1c-5.5,0-10,4.5-10,10v5H3
|
||||
v17h12.9H16h13V15h-3H22z M18,27h-4v-7h4V27z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 581 B |
|
|
@ -205,6 +205,16 @@ button {
|
|||
color: themed(redTextColor);
|
||||
}
|
||||
}
|
||||
.success-block {
|
||||
font-size: 1rem;
|
||||
line-height: 1.4rem;
|
||||
align-self: flex-end;
|
||||
text-align: right;
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(greenTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.error-text {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ $themes: (
|
|||
accountBackgroundColor: rgba(43, 54, 68, 0.5),
|
||||
accountHoverBackgroundColor: rgba(58, 69, 85, 0.5),
|
||||
accountMainTextColor: #e0e0e0,
|
||||
securedSeed: #e0e0e0,
|
||||
seedItemText: #e0e0e0,
|
||||
seedItemBackgroundColor: #18202a,
|
||||
accountOptionalTextColor: #556576,
|
||||
accountIndicatorTextColor: #111921,
|
||||
accountSwitchBackgroundColor: #000000,
|
||||
|
|
@ -90,6 +93,9 @@ $themes: (
|
|||
accountBackgroundColor: rgba(37, 40, 43, 0.5),
|
||||
accountHoverBackgroundColor: rgba(58, 62, 66, 0.5),
|
||||
accountMainTextColor: #e0e0e0,
|
||||
securedSeed: #e0e0e0,
|
||||
seedItemText: #e0e0e0,
|
||||
seedItemBackgroundColor: #292d31,
|
||||
accountOptionalTextColor: #565c62,
|
||||
accountIndicatorTextColor: #1a1a1a,
|
||||
accountSwitchBackgroundColor: #000000,
|
||||
|
|
@ -147,6 +153,9 @@ $themes: (
|
|||
accountBackgroundColor: rgba(30, 136, 229, 1),
|
||||
accountHoverBackgroundColor: rgba(240, 240, 240, 0.5),
|
||||
accountMainTextColor: #ffffff,
|
||||
securedSeed: #a0a5ab,
|
||||
seedItemText: #43454b,
|
||||
seedItemBackgroundColor: #e6e6e6,
|
||||
accountOptionalTextColor: #91baf1,
|
||||
accountIndicatorTextColor: #43454b,
|
||||
accountSwitchBackgroundColor: #ffffff,
|
||||
|
|
|
|||
258
src/gui/qt-daemon/html/assets/scss/layout/_seed-phrase.scss
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
.form-details {
|
||||
margin-top: 1.8rem;
|
||||
|
||||
.input-block {
|
||||
|
||||
&:first-child {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.wallet-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
button {
|
||||
margin: 2.9rem 0;
|
||||
width: 100%;
|
||||
max-width: 15rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-seed {
|
||||
|
||||
label {
|
||||
@include themify($themes) {
|
||||
color: themed(optionalTextColor);
|
||||
}
|
||||
|
||||
font-size: 1.3rem;
|
||||
line-height: 2.4rem;
|
||||
}
|
||||
|
||||
.form-content {
|
||||
@include themify($themes) {
|
||||
border: 2px solid themed(transparentButtonBorderColor);
|
||||
}
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 3rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.text-coral {
|
||||
@include themify($themes) {
|
||||
color: themed(blueTextColor);
|
||||
}
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.seed-phrase-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
max-width: 38rem;
|
||||
width: 100%;
|
||||
|
||||
.input-block,
|
||||
button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
margin-top: 1rem;
|
||||
@include themify($themes) {
|
||||
color: themed(orangeTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
.secured-seed {
|
||||
@include themify($themes) {
|
||||
color: themed(securedSeed);
|
||||
}
|
||||
font-size: 1.2rem;
|
||||
line-height: 2.4rem;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
|
||||
.icon {
|
||||
margin-right: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 3rem;
|
||||
margin-bottom: 2rem;
|
||||
|
||||
.icon {
|
||||
margin-right: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.seed-phrase {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
background-color: transparent !important;
|
||||
|
||||
&-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
@include themify($themes) {
|
||||
color: themed(optionalTextColor);
|
||||
}
|
||||
.right-part {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
.icon {
|
||||
cursor: pointer;
|
||||
width: 1.7rem;
|
||||
height: 1.7rem;
|
||||
|
||||
&.copy {
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
margin-right: 1.2rem;
|
||||
mask: url(~src/assets/icons/copy.svg) no-repeat center;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.75;
|
||||
}
|
||||
}
|
||||
|
||||
&.copied {
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
margin-right: 1.2rem;
|
||||
mask: url(~src/assets/icons/complete-testwallet.svg) no-repeat center;
|
||||
}
|
||||
|
||||
&.secured,
|
||||
&.unsecured {
|
||||
margin-left: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 1.3rem;
|
||||
line-height: 2.4rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
.icon {
|
||||
margin-left: 1.2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-content {
|
||||
@include themify($themes) {
|
||||
border-top: 2px solid themed(transparentButtonBorderColor);
|
||||
border-bottom: 2px solid themed(transparentButtonBorderColor);
|
||||
}
|
||||
padding: 1rem 0 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
.item {
|
||||
@include themify($themes) {
|
||||
color: themed(seedItemText);
|
||||
}
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 2rem;
|
||||
width: calc(100% / 7);
|
||||
min-height: 35px;
|
||||
font-size: 1.3rem;
|
||||
|
||||
&.dark {
|
||||
@include themify($themes) {
|
||||
background-color: themed(seedItemBackgroundColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-footer {
|
||||
text-align: center;
|
||||
|
||||
.title {
|
||||
@include themify($themes) {
|
||||
color: themed(seedItemText);
|
||||
}
|
||||
font-size: 1.3rem;
|
||||
line-height: 2.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: inline-flex;
|
||||
width: 1.6rem;
|
||||
height: 1.6rem;
|
||||
|
||||
&.secured {
|
||||
@include themify($themes) {
|
||||
background-color: themed(greenTextColor);
|
||||
}
|
||||
mask: url(~src/assets/icons/secured.svg) no-repeat center;
|
||||
}
|
||||
|
||||
&.info {
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
mask: url(~src/assets/icons/info.svg) no-repeat center;
|
||||
}
|
||||
|
||||
&.unsecured {
|
||||
@include themify($themes) {
|
||||
background-color: themed(orangeTextColor);
|
||||
}
|
||||
mask: url(~src/assets/icons/unsecured.svg) no-repeat center;
|
||||
}
|
||||
|
||||
&.safety {
|
||||
@include themify($themes) {
|
||||
background-color: themed(alternativeTextColor);
|
||||
}
|
||||
mask: url(~src/assets/icons/safety.svg) no-repeat center;
|
||||
}
|
||||
}
|
||||
|
||||
.wrap-buttons {
|
||||
display: flex;
|
||||
|
||||
.seed-phrase-button {
|
||||
margin: 2.8rem 0;
|
||||
width: 25%;
|
||||
min-width: 1.5rem;
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
margin: 2.8rem 1rem;
|
||||
width: 25%;
|
||||
min-width: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,14 @@ app-wallet {
|
|||
background-color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
&:disabled {
|
||||
background-color: transparent !important;
|
||||
.icon {
|
||||
@include themify($themes) {
|
||||
background-color: themed(accountOptionalTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.alias {
|
||||
|
|
|
|||
1
src/gui/qt-daemon/html/info.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 384"><defs><style>.cls-1{fill:#fff;}</style></defs><title>info</title><path class="cls-1" d="M192,42.05476A149.94522,149.94522,0,0,1,298.02728,298.02728,149.94522,149.94522,0,1,1,85.97271,85.97271,148.96374,148.96374,0,0,1,192,42.05476M192,0C85.96132,0,0,85.96132,0,192S85.96132,384,192,384s192-85.96132,192-192S298.03868,0,192,0Z"/><rect class="cls-1" x="171" y="247.94524" width="42" height="42"/><rect class="cls-1" x="171" y="94.05476" width="42" height="120"/></svg>
|
||||
|
After Width: | Height: | Size: 561 B |
|
|
@ -649,7 +649,7 @@ module.exports = function (NAME, wrapper, methods, common, IS_MAP, IS_WEAK) {
|
|||
/*! no static exports found */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
var core = module.exports = { version: '2.6.11' };
|
||||
var core = module.exports = { version: '2.6.12' };
|
||||
if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef
|
||||
|
||||
|
||||
|
|
@ -1823,7 +1823,7 @@ var store = global[SHARED] || (global[SHARED] = {});
|
|||
})('versions', []).push({
|
||||
version: core.version,
|
||||
mode: __webpack_require__(/*! ./_library */ "./node_modules/core-js/modules/_library.js") ? 'pure' : 'global',
|
||||
copyright: '© 2019 Denis Pushkarev (zloirock.ru)'
|
||||
copyright: '© 2020 Denis Pushkarev (zloirock.ru)'
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -5800,8 +5800,8 @@ __webpack_require__.r(__webpack_exports__);
|
|||
/*! no static exports found */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
__webpack_require__(/*! /Users/mekasan/Projects/Projects/zano_v1/src/gui/qt-daemon/html_source/src/polyfills.ts */"./src/polyfills.ts");
|
||||
module.exports = __webpack_require__(/*! /Users/mekasan/Projects/Projects/zano_v1/src/gui/qt-daemon/html_source/node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/jit-polyfills.js */"./node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/jit-polyfills.js");
|
||||
__webpack_require__(/*! D:\Project\WORK_NEW\zano\src\gui\qt-daemon\html_source\src\polyfills.ts */"./src/polyfills.ts");
|
||||
module.exports = __webpack_require__(/*! D:\Project\WORK_NEW\zano\src\gui\qt-daemon\html_source\node_modules\@angular-devkit\build-angular\src\angular-cli-files\models\jit-polyfills.js */"./node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/jit-polyfills.js");
|
||||
|
||||
|
||||
/***/ })
|
||||
|
|
|
|||
21
src/gui/qt-daemon/html/safety.svg
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Слой_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 320 384" style="enable-background:new 0 0 320 384;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{clip-path:url(#SVGID_2_);}
|
||||
.st1{clip-path:url(#SVGID_2_);fill:none;stroke:#000000;stroke-width:42;stroke-miterlimit:10;}
|
||||
</style>
|
||||
<g>
|
||||
<defs>
|
||||
<rect id="SVGID_1_" width="320" height="384"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_2_">
|
||||
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>
|
||||
</clipPath>
|
||||
<path class="st0" d="M159.9,44.5L278,85.8V232c0,0.9-0.4,9.2-14.7,26c-11,13-26.9,27.1-47.3,42c-20.6,15.1-41.6,27.8-56.1,36.1
|
||||
c-14.5-8.3-35.4-21-56-36.1c-20.3-14.9-36.2-29-47.2-42C42.4,241.2,42,232.9,42,232V85.8L159.9,44.5 M159.9,0L0,56v176
|
||||
c0,70.7,159.9,152,159.9,152S320,302.7,320,232V56L159.9,0z"/>
|
||||
<polyline class="st1" points="100.1,182.2 142.3,218.5 220.3,145.1 "/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1 KiB |
10
src/gui/qt-daemon/html/secured.svg
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 32 32" style="enable-background:new 0 0 32 32;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path class="st0" d="M26,15v-5c0-5.5-4.5-10-10-10h-0.1c-5.5,0-10,4.5-10,10v5H3v17h12.9H16h13V15H26z M9.9,10c0-3.3,2.7-6,6-6H16
|
||||
c3.3,0,6,2.7,6,6v5H9.9V10z M14,27v-7h4v7H14z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 582 B |
10
src/gui/qt-daemon/html/unsecured.svg
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 32 32" style="enable-background:new 0 0 32 32;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path class="st0" d="M22,15h-3.4H9.9v-5c0-3.3,2.7-6,6-6H16c3,0,5.4,2.2,5.9,5h4c-0.5-5-4.8-9-9.9-9h-0.1c-5.5,0-10,4.5-10,10v5H3
|
||||
v17h12.9H16h13V15h-3H22z M18,27h-4v-7h4V27z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 581 B |
|
|
@ -36,6 +36,7 @@
|
|||
"ngx-contextmenu": "^5.1.1",
|
||||
"ngx-papaparse": "^3.0.3",
|
||||
"qrcode": "^1.3.0",
|
||||
"node-sass": "^4.0.0",
|
||||
"rxjs": "~6.3.3",
|
||||
"zone.js": "~0.8.26"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -412,23 +412,28 @@ export class BackendService {
|
|||
this.runCommand('close_wallet', {wallet_id: +wallet_id}, callback);
|
||||
}
|
||||
|
||||
getSmartWalletInfo(wallet_id, callback) {
|
||||
this.runCommand('get_smart_wallet_info', {wallet_id: +wallet_id}, callback);
|
||||
getSmartWalletInfo({wallet_id, seed_password}, callback) {
|
||||
this.runCommand('get_smart_wallet_info', {wallet_id: +wallet_id, seed_password}, callback);
|
||||
}
|
||||
|
||||
getSeedPhraseInfo(param, callback) {
|
||||
this.runCommand('get_seed_phrase_info', param, callback);
|
||||
}
|
||||
|
||||
runWallet(wallet_id, callback?) {
|
||||
this.runCommand('run_wallet', {wallet_id: +wallet_id}, callback);
|
||||
}
|
||||
|
||||
isValidRestoreWalletText(text, callback) {
|
||||
this.runCommand('is_valid_restore_wallet_text', text, callback);
|
||||
isValidRestoreWalletText(param, callback) {
|
||||
this.runCommand('is_valid_restore_wallet_text', param, callback);
|
||||
}
|
||||
|
||||
restoreWallet(path, pass, restore_key, callback) {
|
||||
restoreWallet(path, pass, seed_phrase, seed_pass, callback) {
|
||||
const params = {
|
||||
restore_key: restore_key,
|
||||
seed_phrase: seed_phrase,
|
||||
path: path,
|
||||
pass: pass
|
||||
pass: pass,
|
||||
seed_pass
|
||||
};
|
||||
this.runCommand('restore_wallet', params, callback);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,4 +59,4 @@
|
|||
|
||||
</div>
|
||||
|
||||
<app-progress-container [width]="progressWidth" [labels]="['PROGRESS.ADD_WALLET', 'PROGRESS.SELECT_LOCATION', 'PROGRESS.CREATE_WALLET']"></app-progress-container>
|
||||
<app-progress-container [width]="progressWidth" [labels]="['PROGRESS.ADD_WALLET', 'PROGRESS.SELECT_LOCATION', 'Seed Phrase', 'PROGRESS.CREATE_WALLET']"></app-progress-container>
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ export class CreateWalletComponent implements OnInit {
|
|||
this.variablesService.opening_wallet.currentPage = 1;
|
||||
this.ngZone.run(() => {
|
||||
this.walletSaved = true;
|
||||
this.progressWidth = '50%';
|
||||
this.progressWidth = '33%';
|
||||
});
|
||||
} else {
|
||||
if (errorCode && errorCode === 'ALREADY_EXISTS') {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<form class="open-form" (ngSubmit)="openWallet()">
|
||||
<div class="wallet-path">{{ wallet.name }}</div>
|
||||
<div class="wallet-path">{{ wallet.path }}</div>
|
||||
<div class="input-block" *ngIf="!wallet.notFound && !wallet.emptyPass">
|
||||
<div class="input-block" *ngIf="!wallet.notFound">
|
||||
<label for="password">{{ 'OPEN_WALLET.MODAL.LABEL' | translate }}</label>
|
||||
<input type="password" id="password" name="password" [(ngModel)]="wallet.pass" (contextmenu)="variablesService.onContextMenuPasteSelect($event)"/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -35,18 +35,6 @@ export class OpenWalletModalComponent implements OnInit {
|
|||
if (this.wallets.length) {
|
||||
this.wallet = this.wallets[0];
|
||||
this.wallet.pass = '';
|
||||
|
||||
this.backend.openWallet(this.wallet.path, '', this.variablesService.count, true, (status, data, error) => {
|
||||
if (error === 'FILE_NOT_FOUND') {
|
||||
this.wallet.notFound = true;
|
||||
}
|
||||
if (status) {
|
||||
this.wallet.pass = '';
|
||||
this.wallet.emptyPass = true;
|
||||
this.backend.closeWallet(data.wallet_id);
|
||||
this.openWallet();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -56,6 +44,9 @@ export class OpenWalletModalComponent implements OnInit {
|
|||
}
|
||||
this.backend.openWallet(this.wallet.path, this.wallet.pass, this.variablesService.count, false, (open_status, open_data, open_error) => {
|
||||
if (open_error && open_error === 'FILE_NOT_FOUND') {
|
||||
this.ngZone.run(() => {
|
||||
this.wallet.notFound = true;
|
||||
});
|
||||
let error_translate = this.translate.instant('OPEN_WALLET.FILE_NOT_FOUND1');
|
||||
error_translate += ':<br>' + this.wallet.path;
|
||||
error_translate += this.translate.instant('OPEN_WALLET.FILE_NOT_FOUND2');
|
||||
|
|
|
|||
|
|
@ -62,9 +62,20 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-block half-block" *ngIf="this.seedPhraseInfo?.syntax_correct && this.seedPhraseInfo?.require_password">
|
||||
<label for="seed-password">{{ 'RESTORE_WALLET.SEED_PASSWORD' | translate }}</label>
|
||||
<input type="password" id="seed-password" formControlName="seedPassword">
|
||||
<div class="error-block" *ngIf="(restoreForm.controls['seedPassword'].dirty || restoreForm.controls['seedPassword'].touched) && !this.seedPhraseInfo?.hash_sum_matched">
|
||||
<span>{{ 'RESTORE_WALLET.FORM_ERRORS.INCORRECT_PASSWORD' | translate }}</span>
|
||||
</div>
|
||||
<div class="success-block" *ngIf="this.seedPhraseInfo?.hash_sum_matched">
|
||||
<span>{{ 'RESTORE_WALLET.OK' | translate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wrap-buttons">
|
||||
<button type="button" class="transparent-button" *ngIf="walletSaved" disabled><i class="icon"></i>{{walletSavedName}}</button>
|
||||
<button type="button" class="blue-button select-button" (click)="saveWallet()" [disabled]="!restoreForm.valid" *ngIf="!walletSaved">{{ 'RESTORE_WALLET.BUTTON_SELECT' | translate }}</button>
|
||||
<button type="button" class="blue-button select-button" (click)="saveWallet()" [disabled]="(!this.seedPhraseInfo?.syntax_correct || !this.seedPhraseInfo?.require_password || !this.seedPhraseInfo?.hash_sum_matched) && (!this.seedPhraseInfo?.syntax_correct || this.seedPhraseInfo?.require_password)" *ngIf="!walletSaved">{{ 'RESTORE_WALLET.BUTTON_SELECT' | translate }}</button>
|
||||
<button type="button" class="blue-button create-button" (click)="createWallet()" [disabled]="!walletSaved">{{ 'RESTORE_WALLET.BUTTON_CREATE' | translate }}</button>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,42 +1,57 @@
|
|||
import {Component, NgZone, OnInit} from '@angular/core';
|
||||
import {FormGroup, FormControl, Validators} from '@angular/forms';
|
||||
import {Router} from '@angular/router';
|
||||
import {BackendService} from '../_helpers/services/backend.service';
|
||||
import {VariablesService} from '../_helpers/services/variables.service';
|
||||
import {ModalService} from '../_helpers/services/modal.service';
|
||||
import {Wallet} from '../_helpers/models/wallet.model';
|
||||
import {TranslateService} from '@ngx-translate/core';
|
||||
import { Component, NgZone, OnDestroy, OnInit } from '@angular/core';
|
||||
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { BackendService } from '../_helpers/services/backend.service';
|
||||
import { VariablesService } from '../_helpers/services/variables.service';
|
||||
import { ModalService } from '../_helpers/services/modal.service';
|
||||
import { Wallet } from '../_helpers/models/wallet.model';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Subject } from 'rxjs/internal/Subject';
|
||||
import { debounceTime, distinctUntilChanged, pairwise, startWith, takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'app-restore-wallet',
|
||||
templateUrl: './restore-wallet.component.html',
|
||||
styleUrls: ['./restore-wallet.component.scss']
|
||||
styleUrls: ['./restore-wallet.component.scss'],
|
||||
})
|
||||
export class RestoreWalletComponent implements OnInit {
|
||||
|
||||
restoreForm = new FormGroup({
|
||||
name: new FormControl('', [Validators.required, (g: FormControl) => {
|
||||
for (let i = 0; i < this.variablesService.wallets.length; i++) {
|
||||
if (g.value === this.variablesService.wallets[i].name) {
|
||||
return {'duplicate': true};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}]),
|
||||
key: new FormControl('', Validators.required),
|
||||
password: new FormControl('', Validators.pattern(this.variablesService.pattern)),
|
||||
confirm: new FormControl('')
|
||||
}, function (g: FormGroup) {
|
||||
return g.get('password').value === g.get('confirm').value ? null : {'confirm_mismatch': true};
|
||||
});
|
||||
export class RestoreWalletComponent implements OnInit, OnDestroy {
|
||||
restoreForm = new FormGroup(
|
||||
{
|
||||
name: new FormControl('', [
|
||||
Validators.required,
|
||||
(g: FormControl) => {
|
||||
for (let i = 0; i < this.variablesService.wallets.length; i++) {
|
||||
if (g.value === this.variablesService.wallets[i].name) {
|
||||
return { duplicate: true };
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
]),
|
||||
key: new FormControl('', Validators.required),
|
||||
password: new FormControl(
|
||||
'',
|
||||
Validators.pattern(this.variablesService.pattern)
|
||||
),
|
||||
confirm: new FormControl(''),
|
||||
seedPassword: new FormControl('', Validators.pattern(this.variablesService.pattern)),
|
||||
},
|
||||
function (g: FormGroup) {
|
||||
return g.get('password').value === g.get('confirm').value
|
||||
? null
|
||||
: { confirm_mismatch: true };
|
||||
}
|
||||
);
|
||||
|
||||
wallet = {
|
||||
id: ''
|
||||
id: '',
|
||||
};
|
||||
|
||||
walletSaved = false;
|
||||
walletSavedName = '';
|
||||
progressWidth = '9rem';
|
||||
seedPhraseInfo = null;
|
||||
unsubscribeAll = new Subject<boolean>();
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
|
|
@ -47,7 +62,38 @@ export class RestoreWalletComponent implements OnInit {
|
|||
private translate: TranslateService
|
||||
) {}
|
||||
|
||||
ngOnInit() {}
|
||||
ngOnInit() {
|
||||
this.checkValidSeedPhrasePassword();
|
||||
this.changeDetectionSeedPhrasePassword();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unsubscribeAll.next(true);
|
||||
this.unsubscribeAll.complete();
|
||||
}
|
||||
|
||||
changeDetectionSeedPhrasePassword() {
|
||||
this.restoreForm.controls.seedPassword.valueChanges
|
||||
.pipe(startWith(null), pairwise(), takeUntil(this.unsubscribeAll))
|
||||
.subscribe(() => {
|
||||
this.checkValidSeedPhrasePassword();
|
||||
});
|
||||
this.restoreForm.controls.key.valueChanges
|
||||
.pipe(startWith(null), pairwise(), takeUntil(this.unsubscribeAll))
|
||||
.subscribe(() => {
|
||||
this.checkValidSeedPhrasePassword();
|
||||
});
|
||||
}
|
||||
|
||||
checkValidSeedPhrasePassword() {
|
||||
const seed_password = this.restoreForm.controls.seedPassword.value;
|
||||
const seed_phrase = this.restoreForm.controls.key.value;
|
||||
this.backend.getSeedPhraseInfo({seed_phrase, seed_password}, (status, data) => {
|
||||
this.ngZone.run(() => {
|
||||
this.seedPhraseInfo = data;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
createWallet() {
|
||||
this.ngZone.run(() => {
|
||||
|
|
@ -57,66 +103,133 @@ export class RestoreWalletComponent implements OnInit {
|
|||
}
|
||||
|
||||
saveWallet() {
|
||||
if (this.restoreForm.valid && this.restoreForm.get('name').value.length <= this.variablesService.maxWalletNameLength) {
|
||||
this.backend.isValidRestoreWalletText(this.restoreForm.get('key').value, (valid_status, valid_data) => {
|
||||
if (valid_data !== 'TRUE') {
|
||||
this.ngZone.run(() => {
|
||||
this.restoreForm.get('key').setErrors({key_not_valid: true});
|
||||
});
|
||||
} else {
|
||||
this.backend.saveFileDialog(this.translate.instant('RESTORE_WALLET.CHOOSE_PATH'), '*', this.variablesService.settings.default_path, (save_status, save_data) => {
|
||||
if (save_status) {
|
||||
this.variablesService.settings.default_path = save_data.path.substr(0, save_data.path.lastIndexOf('/'));
|
||||
this.walletSavedName = save_data.path.substr(save_data.path.lastIndexOf('/') + 1, save_data.path.length - 1);
|
||||
this.backend.restoreWallet(save_data.path, this.restoreForm.get('password').value, this.restoreForm.get('key').value, (restore_status, restore_data) => {
|
||||
if (restore_status) {
|
||||
this.wallet.id = restore_data.wallet_id;
|
||||
this.variablesService.opening_wallet = new Wallet(
|
||||
restore_data.wallet_id,
|
||||
this.restoreForm.get('name').value,
|
||||
this.restoreForm.get('password').value,
|
||||
restore_data['wi'].path,
|
||||
restore_data['wi'].address,
|
||||
restore_data['wi'].balance,
|
||||
restore_data['wi'].unlocked_balance,
|
||||
restore_data['wi'].mined_total,
|
||||
restore_data['wi'].tracking_hey
|
||||
if (
|
||||
this.restoreForm.valid &&
|
||||
this.restoreForm.get('name').value.length <=
|
||||
this.variablesService.maxWalletNameLength
|
||||
) {
|
||||
this.backend.isValidRestoreWalletText(
|
||||
{
|
||||
seed_phrase: this.restoreForm.get('key').value,
|
||||
seed_password: this.restoreForm.get('seedPassword').value,
|
||||
},
|
||||
(valid_status, valid_data) => {
|
||||
if (valid_data !== 'TRUE') {
|
||||
this.ngZone.run(() => {
|
||||
this.restoreForm.get('key').setErrors({ key_not_valid: true });
|
||||
});
|
||||
} else {
|
||||
this.backend.saveFileDialog(
|
||||
this.translate.instant('RESTORE_WALLET.CHOOSE_PATH'),
|
||||
'*',
|
||||
this.variablesService.settings.default_path,
|
||||
(save_status, save_data) => {
|
||||
if (save_status) {
|
||||
this.variablesService.settings.default_path = save_data.path.substr(
|
||||
0,
|
||||
save_data.path.lastIndexOf('/')
|
||||
);
|
||||
this.variablesService.opening_wallet.is_auditable = restore_data['wi'].is_auditable;
|
||||
this.variablesService.opening_wallet.is_watch_only = restore_data['wi'].is_watch_only;
|
||||
this.variablesService.opening_wallet.currentPage = 1;
|
||||
this.variablesService.opening_wallet.alias = this.backend.getWalletAlias(this.variablesService.opening_wallet.address);
|
||||
this.variablesService.opening_wallet.pages = new Array(1).fill(1);
|
||||
this.variablesService.opening_wallet.totalPages = 1;
|
||||
this.variablesService.opening_wallet.currentPage = 1;
|
||||
this.variablesService.opening_wallet.total_history_item = 0;
|
||||
this.variablesService.opening_wallet.restore = true;
|
||||
if (restore_data.recent_history && restore_data.recent_history.history) {
|
||||
this.variablesService.opening_wallet.totalPages = Math.ceil( restore_data.recent_history.total_history_items / this.variablesService.count);
|
||||
this.variablesService.opening_wallet.totalPages > this.variablesService.maxPages
|
||||
? this.variablesService.opening_wallet.pages = new Array(5).fill(1).map((value, index) => value + index)
|
||||
: this.variablesService.opening_wallet.pages = new Array(this.variablesService.opening_wallet.totalPages).fill(1).map((value, index) => value + index);
|
||||
this.variablesService.opening_wallet.prepareHistory(restore_data.recent_history.history);
|
||||
}
|
||||
this.backend.getContracts(this.variablesService.opening_wallet.wallet_id, (contracts_status, contracts_data) => {
|
||||
if (contracts_status && contracts_data.hasOwnProperty('contracts')) {
|
||||
this.ngZone.run(() => {
|
||||
this.variablesService.opening_wallet.prepareContractsAfterOpen(contracts_data.contracts, this.variablesService.exp_med_ts, this.variablesService.height_app, this.variablesService.settings.viewedContracts, this.variablesService.settings.notViewedContracts);
|
||||
});
|
||||
this.walletSavedName = save_data.path.substr(
|
||||
save_data.path.lastIndexOf('/') + 1,
|
||||
save_data.path.length - 1
|
||||
);
|
||||
this.backend.restoreWallet(
|
||||
save_data.path,
|
||||
this.restoreForm.get('password').value,
|
||||
this.restoreForm.get('key').value,
|
||||
this.restoreForm.get('seedPassword').value,
|
||||
(restore_status, restore_data) => {
|
||||
if (restore_status) {
|
||||
this.wallet.id = restore_data.wallet_id;
|
||||
this.variablesService.opening_wallet = new Wallet(
|
||||
restore_data.wallet_id,
|
||||
this.restoreForm.get('name').value,
|
||||
this.restoreForm.get('password').value,
|
||||
restore_data['wi'].path,
|
||||
restore_data['wi'].address,
|
||||
restore_data['wi'].balance,
|
||||
restore_data['wi'].unlocked_balance,
|
||||
restore_data['wi'].mined_total,
|
||||
restore_data['wi'].tracking_hey
|
||||
);
|
||||
this.variablesService.opening_wallet.is_auditable =
|
||||
restore_data['wi'].is_auditable;
|
||||
this.variablesService.opening_wallet.is_watch_only =
|
||||
restore_data['wi'].is_watch_only;
|
||||
this.variablesService.opening_wallet.currentPage = 1;
|
||||
this.variablesService.opening_wallet.alias = this.backend.getWalletAlias(
|
||||
this.variablesService.opening_wallet.address
|
||||
);
|
||||
this.variablesService.opening_wallet.pages = new Array(
|
||||
1
|
||||
).fill(1);
|
||||
this.variablesService.opening_wallet.totalPages = 1;
|
||||
this.variablesService.opening_wallet.currentPage = 1;
|
||||
this.variablesService.opening_wallet.total_history_item = 0;
|
||||
this.variablesService.opening_wallet.restore = true;
|
||||
if (
|
||||
restore_data.recent_history &&
|
||||
restore_data.recent_history.history
|
||||
) {
|
||||
this.variablesService.opening_wallet.totalPages = Math.ceil(
|
||||
restore_data.recent_history.total_history_items /
|
||||
this.variablesService.count
|
||||
);
|
||||
this.variablesService.opening_wallet.totalPages >
|
||||
this.variablesService.maxPages
|
||||
? (this.variablesService.opening_wallet.pages = new Array(
|
||||
5
|
||||
)
|
||||
.fill(1)
|
||||
.map((value, index) => value + index))
|
||||
: (this.variablesService.opening_wallet.pages = new Array(
|
||||
this.variablesService.opening_wallet.totalPages
|
||||
)
|
||||
.fill(1)
|
||||
.map((value, index) => value + index));
|
||||
this.variablesService.opening_wallet.prepareHistory(
|
||||
restore_data.recent_history.history
|
||||
);
|
||||
}
|
||||
this.backend.getContracts(
|
||||
this.variablesService.opening_wallet.wallet_id,
|
||||
(contracts_status, contracts_data) => {
|
||||
if (
|
||||
contracts_status &&
|
||||
contracts_data.hasOwnProperty('contracts')
|
||||
) {
|
||||
this.ngZone.run(() => {
|
||||
this.variablesService.opening_wallet.prepareContractsAfterOpen(
|
||||
contracts_data.contracts,
|
||||
this.variablesService.exp_med_ts,
|
||||
this.variablesService.height_app,
|
||||
this.variablesService.settings
|
||||
.viewedContracts,
|
||||
this.variablesService.settings
|
||||
.notViewedContracts
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
this.ngZone.run(() => {
|
||||
this.walletSaved = true;
|
||||
this.progressWidth = '50%';
|
||||
});
|
||||
} else {
|
||||
this.modalService.prepareModal(
|
||||
'error',
|
||||
'RESTORE_WALLET.NOT_CORRECT_FILE_OR_PASSWORD'
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.ngZone.run(() => {
|
||||
this.walletSaved = true;
|
||||
this.progressWidth = '50%';
|
||||
});
|
||||
} else {
|
||||
this.modalService.prepareModal('error', 'RESTORE_WALLET.NOT_CORRECT_FILE_OR_PASSWORD');
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -132,7 +245,9 @@ export class RestoreWalletComponent implements OnInit {
|
|||
if (!exists) {
|
||||
this.backend.runWallet(this.wallet.id, (run_status, run_data) => {
|
||||
if (run_status) {
|
||||
this.variablesService.wallets.push(this.variablesService.opening_wallet);
|
||||
this.variablesService.wallets.push(
|
||||
this.variablesService.opening_wallet
|
||||
);
|
||||
if (this.variablesService.appPass) {
|
||||
this.backend.storeSecureAppData();
|
||||
}
|
||||
|
|
@ -145,7 +260,10 @@ export class RestoreWalletComponent implements OnInit {
|
|||
});
|
||||
} else {
|
||||
this.variablesService.opening_wallet = null;
|
||||
this.modalService.prepareModal('error', 'OPEN_WALLET.WITH_ADDRESS_ALREADY_OPEN');
|
||||
this.modalService.prepareModal(
|
||||
'error',
|
||||
'OPEN_WALLET.WITH_ADDRESS_ALREADY_OPEN'
|
||||
);
|
||||
this.backend.closeWallet(this.wallet.id, () => {
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/']);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<div class="content">
|
||||
|
||||
<!-- breadcrumbs -->
|
||||
<div class="head">
|
||||
<div class="breadcrumbs">
|
||||
<span [routerLink]="['/main']">{{ 'BREADCRUMBS.ADD_WALLET' | translate }}</span>
|
||||
|
|
@ -10,19 +10,103 @@
|
|||
<span>{{ 'COMMON.BACK' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- /breadcrumbs -->
|
||||
|
||||
<h3 class="seed-phrase-title">{{ 'SEED_PHRASE.TITLE' | translate }}</h3>
|
||||
<div class="scrolled-content">
|
||||
<!-- form detail -->
|
||||
<form class="form-details" [formGroup]="detailsForm">
|
||||
<div class="input-block">
|
||||
<label for="wallet-name">{{ 'WALLET_DETAILS.LABEL_NAME' | translate }}</label>
|
||||
<input type="text" id="wallet-name" formControlName="name" [maxLength]="variablesService.maxWalletNameLength"
|
||||
(contextmenu)="variablesService.onContextMenu($event)" readonly>
|
||||
<div class="error-block"
|
||||
*ngIf="detailsForm.controls['name'].invalid && (detailsForm.controls['name'].dirty || detailsForm.controls['name'].touched)">
|
||||
<div *ngIf="detailsForm.controls['name'].errors['required']">
|
||||
{{ 'WALLET_DETAILS.FORM_ERRORS.NAME_REQUIRED' | translate }}
|
||||
</div>
|
||||
<div *ngIf="detailsForm.controls['name'].errors['duplicate']">
|
||||
{{ 'WALLET_DETAILS.FORM_ERRORS.NAME_DUPLICATE' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="error-block" *ngIf="detailsForm.get('name').value.length >= variablesService.maxWalletNameLength">
|
||||
{{ 'WALLET_DETAILS.FORM_ERRORS.MAX_LENGTH' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="seed-phrase-content" (contextmenu)="variablesService.onContextMenuOnlyCopy($event, seedPhrase)">
|
||||
<ng-container *ngFor="let word of seedPhrase.split(' '); let index = index">
|
||||
<div class="word">{{(index + 1) + '. ' + word}}</div>
|
||||
<div class="input-block">
|
||||
<label for="wallet-location">{{ 'WALLET_DETAILS.LABEL_FILE_LOCATION' | translate }}</label>
|
||||
<input type="text" id="wallet-location" formControlName="path" readonly>
|
||||
</div>
|
||||
</form>
|
||||
<!-- /from detail -->
|
||||
|
||||
<!-- form seed pasword -->
|
||||
<ng-container *ngIf="!showSeed else seedPhraseContent">
|
||||
<form class="form-seed mt-2" [formGroup]="seedPhraseForm" (ngSubmit)="onSubmitSeed()">
|
||||
<label>{{ 'WALLET_DETAILS.LABEL_SEED_PHRASE' | translate }}</label>
|
||||
<div class="form-content">
|
||||
<div class="seed-phrase-form">
|
||||
<div class="input-block">
|
||||
<label for="create-password">{{ 'WALLET_DETAILS.CREATE_PASSWORD_SECURE' | translate }} (<a
|
||||
class="text-coral">{{ 'WALLET_DETAILS.INFO' | translate }}</a>)</label>
|
||||
<input type="password" id="create-password" formControlName="password">
|
||||
</div>
|
||||
<div class="input-block">
|
||||
<label for="confirm-password">{{ 'WALLET_DETAILS.FORM.CONFIRM_PASSWORD' | translate }}</label>
|
||||
<input type="password" id="confirm-password" formControlName="confirmPassword">
|
||||
</div>
|
||||
<span class="error-message" *ngIf="!seedPhraseForm.valid">
|
||||
{{ 'WALLET_DETAILS.FORM_ERRORS.PASSWORDS_DONT_MATCH' | translate }}
|
||||
</span>
|
||||
|
||||
<button type="submit" class="blue-button" [disabled]="!seedPhraseForm.valid"><i class="icon safety"></i>
|
||||
{{ 'WALLET_DETAILS.FORM.GENERATE_SECURE_SEED' | translate }}</button>
|
||||
|
||||
<a class="secured-seed"><i
|
||||
class="icon info"></i>{{ 'WALLET_DETAILS.FORM.SECURED_SEED_WILL_REQUIRE' | translate }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</ng-container>
|
||||
</div>
|
||||
<!-- /form seed pasword -->
|
||||
|
||||
<div class="wrap-buttons">
|
||||
<button type="button" class="blue-button seed-phrase-button" (click)="runWallet()">{{ 'SEED_PHRASE.BUTTON_CREATE_ACCOUNT' | translate }}</button>
|
||||
<button type="button" class="blue-button copy-button" (click)="copySeedPhrase()">{{ 'SEED_PHRASE.BUTTON_COPY' | translate }}</button>
|
||||
<!-- seed phrase -->
|
||||
<ng-template #seedPhraseContent>
|
||||
<div class="seed-phrase mt-2">
|
||||
<div class="seed-phrase-title">
|
||||
<span>{{ 'WALLET_DETAILS.LABEL_SEED_PHRASE' | translate }}</span>
|
||||
<p class="right-part">
|
||||
<span
|
||||
*ngIf="seedPhraseForm.controls.password.value.length == 0">{{ 'WALLET_DETAILS.SEED_IS_UNSECURED' | translate }}
|
||||
<i class="icon unsecured"></i></span>
|
||||
<span
|
||||
*ngIf="seedPhraseForm.controls.password.value.length > 0">{{ 'WALLET_DETAILS.SEED_IS_SECURED' | translate }}
|
||||
<i class="icon secured"></i></span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="seed-phrase-content" (contextmenu)="variablesService.onContextMenuOnlyCopy($event, seedPhrase)">
|
||||
<ng-container *ngFor="let word of seedPhrase.split(' '); let index = index">
|
||||
<div class="item"
|
||||
[class.dark]="(index + 1) >= 1 && (index + 1) <= 7 || (index + 1) >= 15 && (index + 1) <= 21">
|
||||
{{(index + 1) + '. ' + word}}</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="seed-phrase-footer" *ngIf="seedPhraseForm.controls.password.value.length > 0">
|
||||
<span class="title">{{ 'WALLET_DETAILS.REMEMBER_YOU_WILL_REQUIRE' | translate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
<!-- /seed phrase -->
|
||||
|
||||
<div class="wrap-buttons" *ngIf="showSeed">
|
||||
<button type="button" class="blue-button seed-phrase-button"
|
||||
(click)="runWallet()">{{ 'SEED_PHRASE.BUTTON_CREATE_ACCOUNT' | translate }}</button>
|
||||
<button type="button" class="blue-button copy-button"
|
||||
(click)="copySeedPhrase()">{{ 'SEED_PHRASE.BUTTON_COPY' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<app-progress-container [width]="'100%'" [labels]="['PROGRESS.ADD_WALLET', 'PROGRESS.SELECT_LOCATION', 'PROGRESS.CREATE_WALLET']"></app-progress-container>
|
||||
<app-progress-container [width]="progressWidth"
|
||||
[labels]="['PROGRESS.ADD_WALLET', 'PROGRESS.SELECT_LOCATION', 'Seed Phrase', 'PROGRESS.CREATE_WALLET']">
|
||||
</app-progress-container>
|
||||
|
|
@ -2,38 +2,15 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.seed-phrase-title {
|
||||
line-height: 2.2rem;
|
||||
padding: 2.2rem 0;
|
||||
.content {
|
||||
padding: 3.2rem 3rem 3rem;
|
||||
}
|
||||
.scrolled-content, .content {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.seed-phrase-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
padding: 1.4rem;
|
||||
width: 100%;
|
||||
height: 12rem;
|
||||
|
||||
.word {
|
||||
line-height: 2.2rem;
|
||||
max-width: 13rem;
|
||||
}
|
||||
}
|
||||
|
||||
.wrap-buttons {
|
||||
display: flex;
|
||||
|
||||
.seed-phrase-button {
|
||||
margin: 2.8rem 0;
|
||||
width: 25%;
|
||||
min-width: 1.5rem;
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
margin: 2.8rem 1rem;
|
||||
width: 25%;
|
||||
min-width: 1.5rem;
|
||||
}
|
||||
.mt-2 {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import {BackendService} from '../_helpers/services/backend.service';
|
|||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {VariablesService} from '../_helpers/services/variables.service';
|
||||
import {ModalService} from '../_helpers/services/modal.service';
|
||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-seed-phrase',
|
||||
|
|
@ -14,8 +15,53 @@ export class SeedPhraseComponent implements OnInit, OnDestroy {
|
|||
|
||||
queryRouting;
|
||||
seedPhrase = '';
|
||||
showSeed = false;
|
||||
wallet_id: number;
|
||||
seedPhraseCopied = false;
|
||||
progressWidth = '66%';
|
||||
|
||||
detailsForm = new FormGroup({
|
||||
name: new FormControl('', [
|
||||
Validators.required,
|
||||
(g: FormControl) => {
|
||||
for (let i = 0; i < this.variablesService.wallets.length; i++) {
|
||||
if (g.value === this.variablesService.wallets[i].name) {
|
||||
if (
|
||||
this.variablesService.wallets[i].wallet_id ===
|
||||
this.variablesService.currentWallet.wallet_id
|
||||
) {
|
||||
return { same: true };
|
||||
} else {
|
||||
return { duplicate: true };
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
]),
|
||||
path: new FormControl(''),
|
||||
});
|
||||
|
||||
seedPhraseForm = new FormGroup(
|
||||
{
|
||||
password: new FormControl(
|
||||
'',
|
||||
Validators.pattern(this.variablesService.pattern)
|
||||
),
|
||||
confirmPassword: new FormControl(
|
||||
'',
|
||||
Validators.pattern(this.variablesService.pattern)
|
||||
),
|
||||
},
|
||||
{ validators: this.checkPasswords }
|
||||
);
|
||||
|
||||
checkPasswords(group: FormGroup) {
|
||||
const pass = group.controls.password.value;
|
||||
const confirmPass = group.controls.confirmPassword.value;
|
||||
|
||||
return pass === confirmPass ? null : { notSame: true };
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
|
|
@ -28,16 +74,24 @@ export class SeedPhraseComponent implements OnInit, OnDestroy {
|
|||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.showSeed = false;
|
||||
this.getWalletId();
|
||||
this.setWalletInfoNamePath();
|
||||
}
|
||||
|
||||
private setWalletInfoNamePath() {
|
||||
this.detailsForm
|
||||
.get('name')
|
||||
.setValue(this.variablesService.opening_wallet.name);
|
||||
this.detailsForm
|
||||
.get('path')
|
||||
.setValue(this.variablesService.opening_wallet.path);
|
||||
}
|
||||
|
||||
private getWalletId() {
|
||||
this.queryRouting = this.route.queryParams.subscribe(params => {
|
||||
if (params.wallet_id) {
|
||||
this.wallet_id = params.wallet_id;
|
||||
this.backend.getSmartWalletInfo(params.wallet_id, (status, data) => {
|
||||
if (data.hasOwnProperty('restore_key')) {
|
||||
this.ngZone.run(() => {
|
||||
this.seedPhrase = data['restore_key'].trim();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -86,8 +140,30 @@ export class SeedPhraseComponent implements OnInit, OnDestroy {
|
|||
this.location.back();
|
||||
}
|
||||
|
||||
showSeedPhrase() {
|
||||
this.showSeed = true;
|
||||
this.progressWidth = '100%';
|
||||
}
|
||||
|
||||
onSubmitSeed() {
|
||||
if (this.seedPhraseForm.valid) {
|
||||
this.showSeedPhrase();
|
||||
const wallet_id = this.wallet_id;
|
||||
const seed_password = this.seedPhraseForm.controls.password.value;
|
||||
this.backend.getSmartWalletInfo(
|
||||
{ wallet_id, seed_password },
|
||||
(status, data) => {
|
||||
if (data.hasOwnProperty('seed_phrase')) {
|
||||
this.ngZone.run(() => {
|
||||
this.seedPhrase = data['seed_phrase'].trim();
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.queryRouting.unsubscribe();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,10 @@
|
|||
|
||||
<div class="input-block">
|
||||
<label for="wallet-name">{{ 'WALLET_DETAILS.LABEL_NAME' | translate }}</label>
|
||||
<input type="text" id="wallet-name" formControlName="name" [maxLength]="variablesService.maxWalletNameLength" (contextmenu)="variablesService.onContextMenu($event)">
|
||||
<div class="error-block" *ngIf="detailsForm.controls['name'].invalid && (detailsForm.controls['name'].dirty || detailsForm.controls['name'].touched)">
|
||||
<input type="text" id="wallet-name" formControlName="name" [maxLength]="variablesService.maxWalletNameLength"
|
||||
(contextmenu)="variablesService.onContextMenu($event)">
|
||||
<div class="error-block"
|
||||
*ngIf="detailsForm.controls['name'].invalid && (detailsForm.controls['name'].dirty || detailsForm.controls['name'].touched)">
|
||||
<div *ngIf="detailsForm.controls['name'].errors['required']">
|
||||
{{ 'WALLET_DETAILS.FORM_ERRORS.NAME_REQUIRED' | translate }}
|
||||
</div>
|
||||
|
|
@ -33,24 +35,56 @@
|
|||
<label for="wallet-location">{{ 'WALLET_DETAILS.LABEL_FILE_LOCATION' | translate }}</label>
|
||||
<input type="text" id="wallet-location" formControlName="path" readonly>
|
||||
</div>
|
||||
|
||||
<div class="input-block textarea">
|
||||
<label for="seed-phrase">{{ 'WALLET_DETAILS.LABEL_SEED_PHRASE' | translate }}</label>
|
||||
<div class="seed-phrase" id="seed-phrase">
|
||||
<div class="seed-phrase-hint" (click)="showSeedPhrase()" *ngIf="!showSeed">{{ 'WALLET_DETAILS.SEED_PHRASE_HINT' | translate }}</div>
|
||||
<div class="seed-phrase-content" *ngIf="showSeed" (contextmenu)="variablesService.onContextMenuOnlyCopy($event, seedPhrase)">
|
||||
<ng-container *ngFor="let word of seedPhrase.split(' '); let index = index">
|
||||
<div class="word">{{(index + 1) + '. ' + word}}</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wallet-buttons">
|
||||
<button type="submit" class="blue-button" [disabled]="!detailsForm.valid">{{ 'WALLET_DETAILS.BUTTON_SAVE' | translate }}</button>
|
||||
<button type="button" class="blue-button" (click)="closeWallet()">{{ 'WALLET_DETAILS.BUTTON_REMOVE' | translate }}</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<ng-container *ngIf="!showSeed else seedPhraseContent">
|
||||
<form class="form-seed mt-2" [formGroup]="seedPhraseForm" (ngSubmit)="onSubmitSeed()">
|
||||
<label>{{ 'WALLET_DETAILS.LABEL_SEED_PHRASE' | translate }}</label>
|
||||
<div class="form-content">
|
||||
<div class="seed-phrase-form">
|
||||
<div class="input-block">
|
||||
<label for="create-password">{{ 'WALLET_DETAILS.CREATE_PASSWORD_SECURE' | translate }} (<a class="text-coral">{{ 'WALLET_DETAILS.INFO' | translate }}</a>)</label>
|
||||
<input type="password" id="create-password" formControlName="password">
|
||||
</div>
|
||||
<div class="input-block">
|
||||
<label for="confirm-password">{{ 'WALLET_DETAILS.FORM.CONFIRM_PASSWORD' | translate }}</label>
|
||||
<input type="password" id="confirm-password" formControlName="confirmPassword">
|
||||
</div>
|
||||
<span class="error-message" *ngIf="!seedPhraseForm.valid">
|
||||
{{ 'WALLET_DETAILS.FORM_ERRORS.PASSWORDS_DONT_MATCH' | translate }}
|
||||
</span>
|
||||
|
||||
<button type="submit" class="blue-button" [disabled]="!seedPhraseForm.valid"><i class="icon safety"></i>
|
||||
{{ 'WALLET_DETAILS.FORM.GENERATE_SECURE_SEED' | translate }}</button>
|
||||
|
||||
<a class="secured-seed"><i class="icon info"></i>{{ 'WALLET_DETAILS.FORM.SECURED_SEED_WILL_REQUIRE' | translate }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #seedPhraseContent>
|
||||
<div class="seed-phrase mt-2">
|
||||
<div class="seed-phrase-title">
|
||||
<span>{{ 'WALLET_DETAILS.LABEL_SEED_PHRASE' | translate }}</span>
|
||||
<p class="right-part">
|
||||
<span
|
||||
*ngIf="seedPhraseForm.controls.password.value.length == 0">{{ 'WALLET_DETAILS.SEED_IS_UNSECURED' | translate }} <i class="icon unsecured"></i></span>
|
||||
<span
|
||||
*ngIf="seedPhraseForm.controls.password.value.length > 0">{{ 'WALLET_DETAILS.SEED_IS_SECURED' | translate }} <i class="icon secured"></i></span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="seed-phrase-content" (contextmenu)="variablesService.onContextMenuOnlyCopy($event, seedPhrase)">
|
||||
<ng-container *ngFor="let word of seedPhrase.split(' '); let index = index">
|
||||
<div class="item"
|
||||
[class.dark]="(index + 1) >= 1 && (index + 1) <= 7 || (index + 1) >= 15 && (index + 1) <= 21">
|
||||
{{(index + 1) + '. ' + word}}</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="seed-phrase-footer"
|
||||
*ngIf="seedPhraseForm.controls.password.value.length > 0">
|
||||
<span class="title">{{ 'WALLET_DETAILS.REMEMBER_YOU_WILL_REQUIRE' | translate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
|
@ -8,32 +8,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.seed-phrase {
|
||||
display: flex;
|
||||
font-size: 1.4rem;
|
||||
line-height: 1.5rem;
|
||||
padding: 1.4rem;
|
||||
width: 100%;
|
||||
height: 8.8rem;
|
||||
|
||||
.seed-phrase-hint {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.seed-phrase-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.wallet-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -45,5 +19,8 @@
|
|||
max-width: 15rem;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.mt-2 {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +1,63 @@
|
|||
import {Component, NgZone, OnDestroy, OnInit} from '@angular/core';
|
||||
import {FormGroup, FormControl, Validators} from '@angular/forms';
|
||||
import {BackendService} from '../_helpers/services/backend.service';
|
||||
import {VariablesService} from '../_helpers/services/variables.service';
|
||||
import {Router} from '@angular/router';
|
||||
import {Location} from '@angular/common';
|
||||
import { Component, NgZone, OnDestroy, OnInit } from '@angular/core';
|
||||
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
||||
import { BackendService } from '../_helpers/services/backend.service';
|
||||
import { VariablesService } from '../_helpers/services/variables.service';
|
||||
import { Router } from '@angular/router';
|
||||
import { Location } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-wallet-details',
|
||||
templateUrl: './wallet-details.component.html',
|
||||
styleUrls: ['./wallet-details.component.scss']
|
||||
styleUrls: ['./wallet-details.component.scss'],
|
||||
})
|
||||
export class WalletDetailsComponent implements OnInit, OnDestroy {
|
||||
seedPhrase = '';
|
||||
showSeed = false;
|
||||
copyAnimation = false;
|
||||
|
||||
detailsForm = new FormGroup({
|
||||
name: new FormControl('', [Validators.required, (g: FormControl) => {
|
||||
for (let i = 0; i < this.variablesService.wallets.length; i++) {
|
||||
if (g.value === this.variablesService.wallets[i].name) {
|
||||
if (this.variablesService.wallets[i].wallet_id === this.variablesService.currentWallet.wallet_id) {
|
||||
return {'same': true};
|
||||
} else {
|
||||
return {'duplicate': true};
|
||||
name: new FormControl('', [
|
||||
Validators.required,
|
||||
(g: FormControl) => {
|
||||
for (let i = 0; i < this.variablesService.wallets.length; i++) {
|
||||
if (g.value === this.variablesService.wallets[i].name) {
|
||||
if (
|
||||
this.variablesService.wallets[i].wallet_id ===
|
||||
this.variablesService.currentWallet.wallet_id
|
||||
) {
|
||||
return { same: true };
|
||||
} else {
|
||||
return { duplicate: true };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}]),
|
||||
path: new FormControl('')
|
||||
return null;
|
||||
},
|
||||
]),
|
||||
path: new FormControl(''),
|
||||
});
|
||||
|
||||
seedPhraseForm = new FormGroup(
|
||||
{
|
||||
password: new FormControl(
|
||||
'',
|
||||
Validators.pattern(this.variablesService.pattern)
|
||||
),
|
||||
confirmPassword: new FormControl(
|
||||
'',
|
||||
Validators.pattern(this.variablesService.pattern)
|
||||
),
|
||||
},
|
||||
{ validators: this.checkPasswords }
|
||||
);
|
||||
|
||||
checkPasswords(group: FormGroup) {
|
||||
const pass = group.controls.password.value;
|
||||
const confirmPass = group.controls.confirmPassword.value;
|
||||
|
||||
return pass === confirmPass ? null : { notSame: true };
|
||||
}
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private backend: BackendService,
|
||||
|
|
@ -40,55 +68,83 @@ export class WalletDetailsComponent implements OnInit, OnDestroy {
|
|||
|
||||
ngOnInit() {
|
||||
this.showSeed = false;
|
||||
this.detailsForm.get('name').setValue(this.variablesService.currentWallet.name);
|
||||
this.detailsForm.get('path').setValue(this.variablesService.currentWallet.path);
|
||||
this.backend.getSmartWalletInfo(this.variablesService.currentWallet.wallet_id, (status, data) => {
|
||||
if (data.hasOwnProperty('restore_key')) {
|
||||
this.ngZone.run(() => {
|
||||
this.seedPhrase = data['restore_key'].trim();
|
||||
});
|
||||
}
|
||||
});
|
||||
this.detailsForm
|
||||
.get('name')
|
||||
.setValue(this.variablesService.currentWallet.name);
|
||||
this.detailsForm
|
||||
.get('path')
|
||||
.setValue(this.variablesService.currentWallet.path);
|
||||
}
|
||||
|
||||
showSeedPhrase() {
|
||||
this.showSeed = true;
|
||||
}
|
||||
|
||||
onSubmitSeed() {
|
||||
if (this.seedPhraseForm.valid) {
|
||||
this.showSeedPhrase();
|
||||
const wallet_id = this.variablesService.currentWallet.wallet_id;
|
||||
const seed_password = this.seedPhraseForm.controls.password.value;
|
||||
this.backend.getSmartWalletInfo(
|
||||
{ wallet_id, seed_password },
|
||||
(status, data) => {
|
||||
if (data.hasOwnProperty('seed_phrase')) {
|
||||
this.ngZone.run(() => {
|
||||
this.seedPhrase = data['seed_phrase'].trim();
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
onSubmitEdit() {
|
||||
if (this.detailsForm.value) {
|
||||
this.variablesService.currentWallet.name = this.detailsForm.get('name').value;
|
||||
this.variablesService.currentWallet.name = this.detailsForm.get(
|
||||
'name'
|
||||
).value;
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/wallet/' + this.variablesService.currentWallet.wallet_id]);
|
||||
this.router.navigate([
|
||||
'/wallet/' + this.variablesService.currentWallet.wallet_id,
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
closeWallet() {
|
||||
this.backend.closeWallet(this.variablesService.currentWallet.wallet_id, () => {
|
||||
for (let i = this.variablesService.wallets.length - 1; i >= 0; i--) {
|
||||
if (this.variablesService.wallets[i].wallet_id === this.variablesService.currentWallet.wallet_id) {
|
||||
this.variablesService.wallets.splice(i, 1);
|
||||
this.backend.closeWallet(
|
||||
this.variablesService.currentWallet.wallet_id,
|
||||
() => {
|
||||
for (let i = this.variablesService.wallets.length - 1; i >= 0; i--) {
|
||||
if (
|
||||
this.variablesService.wallets[i].wallet_id ===
|
||||
this.variablesService.currentWallet.wallet_id
|
||||
) {
|
||||
this.variablesService.wallets.splice(i, 1);
|
||||
}
|
||||
}
|
||||
this.ngZone.run(() => {
|
||||
if (this.variablesService.wallets.length) {
|
||||
this.variablesService.currentWallet = this.variablesService.wallets[0];
|
||||
this.router.navigate([
|
||||
'/wallet/' + this.variablesService.currentWallet.wallet_id,
|
||||
]);
|
||||
} else {
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
});
|
||||
if (this.variablesService.appPass) {
|
||||
this.backend.storeSecureAppData();
|
||||
}
|
||||
}
|
||||
this.ngZone.run(() => {
|
||||
if (this.variablesService.wallets.length) {
|
||||
this.variablesService.currentWallet = this.variablesService.wallets[0];
|
||||
this.router.navigate(['/wallet/' + this.variablesService.currentWallet.wallet_id]);
|
||||
} else {
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
});
|
||||
if (this.variablesService.appPass) {
|
||||
this.backend.storeSecureAppData();
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
back() {
|
||||
this.location.back();
|
||||
}
|
||||
|
||||
ngOnDestroy() {}
|
||||
ngOnDestroy() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button [routerLink]="['/details']" routerLinkActive="active" tooltip="{{ 'WALLET.TOOLTIPS.SETTINGS' | translate }}" placement="left" tooltipClass="table-tooltip account-tooltip" [delay]="500" [timeDelay]="500">
|
||||
<button [routerLink]="['/details']" routerLinkActive="active" tooltip="{{ 'WALLET.TOOLTIPS.SETTINGS' | translate }}" placement="left" tooltipClass="table-tooltip account-tooltip" [delay]="500" [timeDelay]="500" [disabled]="variablesService.daemon_state !== 2 || !walletLoaded">
|
||||
<i class="icon details"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,25 @@
|
|||
import { Component, OnInit, OnDestroy, NgZone, ViewChild, ElementRef } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
NgZone,
|
||||
ViewChild,
|
||||
ElementRef,
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute, Router, RoutesRecognized } from '@angular/router';
|
||||
import { VariablesService } from '../_helpers/services/variables.service';
|
||||
import { BackendService } from '../_helpers/services/backend.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { IntToMoneyPipe } from '../_helpers/pipes/int-to-money.pipe';
|
||||
import {Subscription} from 'rxjs';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { LOCKED_BALANCE_HELP_PAGE } from '../_shared/constants';
|
||||
|
||||
import icons from '../../assets/icons/icons.json';
|
||||
import {PaginationService} from '../_helpers/services/pagination.service';
|
||||
import {PaginationStore} from '../_helpers/services/pagination.store';
|
||||
import {Store, Sync} from 'store';
|
||||
import {Wallet} from '../_helpers/models/wallet.model';
|
||||
import {distinctUntilChanged, filter} from 'rxjs/operators';
|
||||
import { PaginationService } from '../_helpers/services/pagination.service';
|
||||
import { PaginationStore } from '../_helpers/services/pagination.store';
|
||||
import { Store, Sync } from 'store';
|
||||
import { Wallet } from '../_helpers/models/wallet.model';
|
||||
import { distinctUntilChanged, filter } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'app-wallet',
|
||||
|
|
@ -27,6 +34,7 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
copyAnimation = false;
|
||||
copyAnimationTimeout;
|
||||
balanceTooltip;
|
||||
walletLoaded;
|
||||
activeTab = 'history';
|
||||
public mining = false;
|
||||
public currentPage = 1;
|
||||
|
|
@ -44,7 +52,7 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
indicator: false,
|
||||
active: true,
|
||||
animated: icons.history,
|
||||
itemHovered: false
|
||||
itemHovered: false,
|
||||
},
|
||||
{
|
||||
title: 'WALLET.TABS.SEND',
|
||||
|
|
@ -53,7 +61,7 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
indicator: false,
|
||||
active: false,
|
||||
animated: icons.send,
|
||||
itemHovered: false
|
||||
itemHovered: false,
|
||||
},
|
||||
{
|
||||
title: 'WALLET.TABS.RECEIVE',
|
||||
|
|
@ -62,7 +70,7 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
indicator: false,
|
||||
active: false,
|
||||
animated: icons.receive,
|
||||
itemHovered: false
|
||||
itemHovered: false,
|
||||
},
|
||||
{
|
||||
title: 'WALLET.TABS.CONTRACTS',
|
||||
|
|
@ -71,7 +79,7 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
indicator: 1,
|
||||
active: false,
|
||||
animated: icons.contracts,
|
||||
itemHovered: false
|
||||
itemHovered: false,
|
||||
},
|
||||
/*{
|
||||
title: 'WALLET.TABS.MESSAGES',
|
||||
|
|
@ -89,8 +97,8 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
indicator: false,
|
||||
active: false,
|
||||
animated: icons.staking,
|
||||
itemHovered: false
|
||||
}
|
||||
itemHovered: false,
|
||||
},
|
||||
];
|
||||
aliasSubscription: Subscription;
|
||||
walletsSubscription: Subscription;
|
||||
|
|
@ -105,54 +113,71 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
private intToMoneyPipe: IntToMoneyPipe,
|
||||
private pagination: PaginationService,
|
||||
private paginationStore: PaginationStore,
|
||||
private store: Store,
|
||||
) { }
|
||||
private store: Store
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.subRouting1 = this.route.params.subscribe(params => {
|
||||
this.subRouting1 = this.route.params.subscribe((params) => {
|
||||
// set current wallet only by user click to avoid after sync show synchronized data
|
||||
this.walletID = +params['id'];
|
||||
this.walletLoaded = this.variablesService.getWallet(this.walletID).loaded;
|
||||
this.variablesService.setCurrentWallet(this.walletID);
|
||||
this.walletsSubscription = this.store.select('sync').pipe(
|
||||
filter(Boolean),
|
||||
distinctUntilChanged(),
|
||||
).subscribe(value => {
|
||||
const data = value.filter((item: Sync) => item.wallet_id === this.walletID)[0];
|
||||
if (data && !data.sync) {
|
||||
let in_progress;
|
||||
const values = this.store.value.sync;
|
||||
if (values && values.length) {
|
||||
in_progress = values.filter(item => item.sync);
|
||||
this.variablesService.sync_started = !!(in_progress && in_progress.length);
|
||||
if (!in_progress) {
|
||||
this.walletsSubscription = this.store
|
||||
.select('sync')
|
||||
.pipe(filter(Boolean), distinctUntilChanged())
|
||||
.subscribe((value) => {
|
||||
const data = value.filter(
|
||||
(item: Sync) => item.wallet_id === this.walletID
|
||||
)[0];
|
||||
if (data && !data.sync) {
|
||||
let in_progress;
|
||||
const values = this.store.value.sync;
|
||||
if (values && values.length) {
|
||||
in_progress = values.filter((item) => item.sync);
|
||||
this.variablesService.sync_started = !!(
|
||||
in_progress && in_progress.length
|
||||
);
|
||||
if (!in_progress) {
|
||||
this.variablesService.sync_started = false;
|
||||
}
|
||||
} else {
|
||||
this.variablesService.sync_started = false;
|
||||
}
|
||||
} else {
|
||||
this.variablesService.sync_started = false;
|
||||
}
|
||||
}
|
||||
let restore = false;
|
||||
if (this.variablesService.after_sync_request.hasOwnProperty(this.walletID)) {
|
||||
restore = this.variablesService.after_sync_request[this.walletID];
|
||||
}
|
||||
if (!this.variablesService.sync_started && restore && this.walletID === (data && data.wallet_id)) {
|
||||
this.wallet = this.variablesService.getNotLoadedWallet();
|
||||
if (this.wallet) {
|
||||
this.tick();
|
||||
let restore = false;
|
||||
if (
|
||||
this.variablesService.after_sync_request.hasOwnProperty(
|
||||
this.walletID
|
||||
)
|
||||
) {
|
||||
restore = this.variablesService.after_sync_request[this.walletID];
|
||||
}
|
||||
// if this is was restore wallet and it was selected on moment when sync completed
|
||||
this.getRecentTransfers();
|
||||
this.variablesService.after_sync_request[this.walletID] = false;
|
||||
}
|
||||
});
|
||||
let after_sync_request = false;
|
||||
if (this.variablesService.after_sync_request.hasOwnProperty(this.walletID)) {
|
||||
after_sync_request = this.variablesService.after_sync_request[this.walletID];
|
||||
}
|
||||
if (after_sync_request && !this.variablesService.sync_started) {
|
||||
// if user click on the wallet at the first time after restore.
|
||||
if (
|
||||
!this.variablesService.sync_started &&
|
||||
restore &&
|
||||
this.walletID === (data && data.wallet_id)
|
||||
) {
|
||||
this.wallet = this.variablesService.getNotLoadedWallet();
|
||||
if (this.wallet) {
|
||||
this.tick();
|
||||
}
|
||||
// if this is was restore wallet and it was selected on moment when sync completed
|
||||
this.getRecentTransfers();
|
||||
this.variablesService.after_sync_request[this.walletID] = false;
|
||||
}
|
||||
});
|
||||
let after_sync_request = false;
|
||||
if (
|
||||
this.variablesService.after_sync_request.hasOwnProperty(this.walletID)
|
||||
) {
|
||||
after_sync_request = this.variablesService.after_sync_request[
|
||||
this.walletID
|
||||
];
|
||||
}
|
||||
if (after_sync_request && !this.variablesService.sync_started) {
|
||||
// if user click on the wallet at the first time after restore.
|
||||
this.getRecentTransfers();
|
||||
}
|
||||
|
||||
if (this.variablesService.stop_paginate.hasOwnProperty(this.walletID)) {
|
||||
this.stop_paginate = this.variablesService.stop_paginate[this.walletID];
|
||||
|
|
@ -170,23 +195,27 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
this.copyAnimation = false;
|
||||
this.mining = this.variablesService.currentWallet.exclude_mining_txs;
|
||||
|
||||
|
||||
if (this.variablesService.wallets.length === 1) {
|
||||
this.walletID = +params['id'];
|
||||
this.variablesService.setCurrentWallet(this.walletID);
|
||||
}
|
||||
});
|
||||
this.subRouting2 = this.router.events.subscribe(val => {
|
||||
this.subRouting2 = this.router.events.subscribe((val) => {
|
||||
if (val instanceof RoutesRecognized) {
|
||||
this.activeTab = val.urlAfterRedirects.replace('?sidenav=true', '').split('/').pop();
|
||||
this.activeTab = val.urlAfterRedirects
|
||||
.replace('?sidenav=true', '')
|
||||
.split('/')
|
||||
.pop();
|
||||
if (val.state.root.firstChild && val.state.root.firstChild.firstChild) {
|
||||
for (let i = 0; i < this.tabs.length; i++) {
|
||||
this.tabs[i].active = (this.tabs[i].link === '/' + val.state.root.firstChild.firstChild.url[0].path);
|
||||
this.tabs[i].active =
|
||||
this.tabs[i].link ===
|
||||
'/' + val.state.root.firstChild.firstChild.url[0].path;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
this.queryRouting = this.route.queryParams.subscribe(params => {
|
||||
this.queryRouting = this.route.queryParams.subscribe((params) => {
|
||||
if (params.send) {
|
||||
this.tabs.forEach((tab, index) => {
|
||||
if (tab.link === '/send') {
|
||||
|
|
@ -198,32 +227,54 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
if (this.variablesService.currentWallet.alias.hasOwnProperty('name')) {
|
||||
this.variablesService.currentWallet.wakeAlias = false;
|
||||
}
|
||||
this.aliasSubscription = this.variablesService.getAliasChangedEvent.subscribe(() => {
|
||||
if (this.variablesService.currentWallet.alias.hasOwnProperty('name')) {
|
||||
this.variablesService.currentWallet.wakeAlias = false;
|
||||
this.aliasSubscription = this.variablesService.getAliasChangedEvent.subscribe(
|
||||
() => {
|
||||
if (this.variablesService.currentWallet.alias.hasOwnProperty('name')) {
|
||||
this.variablesService.currentWallet.wakeAlias = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
this.updateWalletStatus();
|
||||
}
|
||||
resetPaginationValues() {
|
||||
this.ngZone.run(() => {
|
||||
const total_history_item = this.variablesService.currentWallet.total_history_item;
|
||||
const total_history_item = this.variablesService.currentWallet
|
||||
.total_history_item;
|
||||
const count = this.variablesService.count;
|
||||
this.variablesService.currentWallet.totalPages = Math.ceil( total_history_item / count);
|
||||
this.variablesService.currentWallet.totalPages = Math.ceil(
|
||||
total_history_item / count
|
||||
);
|
||||
this.variablesService.currentWallet.exclude_mining_txs = this.mining;
|
||||
this.variablesService.currentWallet.currentPage = 1;
|
||||
|
||||
if (!this.variablesService.currentWallet.totalPages) {
|
||||
this.variablesService.currentWallet.totalPages = 1;
|
||||
}
|
||||
this.variablesService.currentWallet.totalPages > this.variablesService.maxPages
|
||||
? this.variablesService.currentWallet.pages = new Array(5).fill(1).map((value, index) => value + index)
|
||||
: this.variablesService.currentWallet.pages = new Array(this.variablesService.currentWallet.totalPages).fill(1).map((value, index) => value + index);
|
||||
})
|
||||
this.variablesService.currentWallet.totalPages >
|
||||
this.variablesService.maxPages
|
||||
? (this.variablesService.currentWallet.pages = new Array(5)
|
||||
.fill(1)
|
||||
.map((value, index) => value + index))
|
||||
: (this.variablesService.currentWallet.pages = new Array(
|
||||
this.variablesService.currentWallet.totalPages
|
||||
)
|
||||
.fill(1)
|
||||
.map((value, index) => value + index));
|
||||
});
|
||||
}
|
||||
|
||||
changeTab(index) {
|
||||
if (((this.tabs[index].link === '/send' || this.tabs[index].link === '/contracts' || this.tabs[index].link === '/staking') && (this.variablesService.daemon_state !== 2 || !this.variablesService.currentWallet.loaded))
|
||||
|| ((this.tabs[index].link === '/send' || this.tabs[index].link === '/contracts') && this.variablesService.currentWallet.is_watch_only && this.variablesService.currentWallet.is_auditable)) {
|
||||
if (
|
||||
((this.tabs[index].link === '/send' ||
|
||||
this.tabs[index].link === '/contracts' ||
|
||||
this.tabs[index].link === '/staking') &&
|
||||
(this.variablesService.daemon_state !== 2 ||
|
||||
!this.variablesService.currentWallet.loaded)) ||
|
||||
((this.tabs[index].link === '/send' ||
|
||||
this.tabs[index].link === '/contracts') &&
|
||||
this.variablesService.currentWallet.is_watch_only &&
|
||||
this.variablesService.currentWallet.is_auditable)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.tabs.forEach((tab) => {
|
||||
|
|
@ -252,11 +303,23 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
this.balanceTooltip = document.createElement('div');
|
||||
const available = document.createElement('span');
|
||||
available.setAttribute('class', 'available');
|
||||
available.innerHTML = this.translate.instant('WALLET.AVAILABLE_BALANCE', { available: this.intToMoneyPipe.transform(this.variablesService.currentWallet.unlocked_balance), currency: this.variablesService.defaultCurrency });
|
||||
available.innerHTML = this.translate.instant('WALLET.AVAILABLE_BALANCE', {
|
||||
available: this.intToMoneyPipe.transform(
|
||||
this.variablesService.currentWallet.unlocked_balance
|
||||
),
|
||||
currency: this.variablesService.defaultCurrency,
|
||||
});
|
||||
this.balanceTooltip.appendChild(available);
|
||||
const locked = document.createElement('span');
|
||||
locked.setAttribute('class', 'locked');
|
||||
locked.innerHTML = this.translate.instant('WALLET.LOCKED_BALANCE', { locked: this.intToMoneyPipe.transform(this.variablesService.currentWallet.balance.minus(this.variablesService.currentWallet.unlocked_balance)), currency: this.variablesService.defaultCurrency });
|
||||
locked.innerHTML = this.translate.instant('WALLET.LOCKED_BALANCE', {
|
||||
locked: this.intToMoneyPipe.transform(
|
||||
this.variablesService.currentWallet.balance.minus(
|
||||
this.variablesService.currentWallet.unlocked_balance
|
||||
)
|
||||
),
|
||||
currency: this.variablesService.defaultCurrency,
|
||||
});
|
||||
this.balanceTooltip.appendChild(locked);
|
||||
const link = document.createElement('span');
|
||||
link.setAttribute('class', 'link');
|
||||
|
|
@ -278,7 +341,10 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
|
||||
public setPage(pageNumber: number) {
|
||||
// this is will allow pagination for wallets that was open from existed wallets'
|
||||
if (this.variablesService.currentWallet.open_from_exist && !this.variablesService.currentWallet.updated) {
|
||||
if (
|
||||
this.variablesService.currentWallet.open_from_exist &&
|
||||
!this.variablesService.currentWallet.updated
|
||||
) {
|
||||
this.variablesService.get_recent_transfers = false;
|
||||
this.variablesService.currentWallet.updated = true;
|
||||
}
|
||||
|
|
@ -300,7 +366,7 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
if (!value) {
|
||||
this.paginationStore.setPage(1, 0, this.walletID); // add back page for the first page
|
||||
} else {
|
||||
const pages = value.filter(item => item.walletID === this.walletID);
|
||||
const pages = value.filter((item) => item.walletID === this.walletID);
|
||||
if (!pages.length) {
|
||||
this.paginationStore.setPage(1, 0, this.walletID); // add back page for the first page
|
||||
}
|
||||
|
|
@ -320,27 +386,44 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
}, 1000);
|
||||
}
|
||||
|
||||
getRecentTransfers () {
|
||||
getRecentTransfers() {
|
||||
const offset = this.pagination.getOffset(this.walletID);
|
||||
const value = this.paginationStore.value;
|
||||
const pages = value ? value.filter(item => item.walletID === this.walletID) : [];
|
||||
const pages = value
|
||||
? value.filter((item) => item.walletID === this.walletID)
|
||||
: [];
|
||||
|
||||
this.backend.getRecentTransfers(
|
||||
this.walletID,
|
||||
offset,
|
||||
this.variablesService.count, this.variablesService.currentWallet.exclude_mining_txs, (status, data) => {
|
||||
const isForward = this.paginationStore.isForward(pages, this.variablesService.currentWallet.currentPage);
|
||||
this.variablesService.count,
|
||||
this.variablesService.currentWallet.exclude_mining_txs,
|
||||
(status, data) => {
|
||||
const isForward = this.paginationStore.isForward(
|
||||
pages,
|
||||
this.variablesService.currentWallet.currentPage
|
||||
);
|
||||
if (this.mining && isForward && pages && pages.length === 1) {
|
||||
this.variablesService.currentWallet.currentPage = 1; // set init page after navigation back
|
||||
}
|
||||
|
||||
const history = (data && data.history);
|
||||
this.variablesService.stop_paginate[this.walletID] = history && history.length < this.variablesService.count || !history;
|
||||
const history = data && data.history;
|
||||
this.variablesService.stop_paginate[this.walletID] =
|
||||
(history && history.length < this.variablesService.count) || !history;
|
||||
this.stop_paginate = this.variablesService.stop_paginate[this.walletID];
|
||||
if (!this.variablesService.stop_paginate[this.walletID]) {
|
||||
const page = this.variablesService.currentWallet.currentPage + 1;
|
||||
if (isForward && this.mining && history && history.length === this.variablesService.count) {
|
||||
this.paginationStore.setPage(page, data.last_item_index, this.walletID); // add back page for current page
|
||||
if (
|
||||
isForward &&
|
||||
this.mining &&
|
||||
history &&
|
||||
history.length === this.variablesService.count
|
||||
) {
|
||||
this.paginationStore.setPage(
|
||||
page,
|
||||
data.last_item_index,
|
||||
this.walletID
|
||||
); // add back page for current page
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -349,13 +432,18 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
|
||||
this.ngZone.run(() => {
|
||||
this.variablesService.get_recent_transfers = false;
|
||||
if (this.variablesService.after_sync_request.hasOwnProperty(this.walletID)) {
|
||||
if (
|
||||
this.variablesService.after_sync_request.hasOwnProperty(
|
||||
this.walletID
|
||||
)
|
||||
) {
|
||||
// this is will complete get_recent_transfers request
|
||||
// this will switch of
|
||||
this.variablesService.after_sync_request[this.walletID] = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
|
|
@ -369,4 +457,29 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
clearTimeout(this.copyAnimationTimeout);
|
||||
}
|
||||
|
||||
updateWalletStatus() {
|
||||
this.backend.eventSubscribe('wallet_sync_progress', (data) => {
|
||||
const wallet_id = data.wallet_id;
|
||||
if (wallet_id === this.walletID) {
|
||||
this.ngZone.run(() => {
|
||||
this.walletLoaded = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
this.backend.eventSubscribe('update_wallet_status', (data) => {
|
||||
const wallet_state = data.wallet_state;
|
||||
const wallet_id = data.wallet_id;
|
||||
this.ngZone.run(() => {
|
||||
if (wallet_state === 2 && wallet_id === this.walletID) {
|
||||
this.walletLoaded =
|
||||
this.variablesService.getWallet(this.walletID) !== null &&
|
||||
this.variablesService.getWallet(this.walletID).loaded
|
||||
? true
|
||||
: false;
|
||||
} else {
|
||||
this.walletLoaded = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,13 +120,16 @@
|
|||
"BUTTON_CREATE": "Create wallet",
|
||||
"NOT_CORRECT_FILE_OR_PASSWORD": "Invalid wallet file or password does not match",
|
||||
"CHOOSE_PATH": "Please choose a path",
|
||||
"SEED_PASSWORD": "Seed password",
|
||||
"OK": "OK",
|
||||
"FORM_ERRORS": {
|
||||
"NAME_REQUIRED": "Name is required",
|
||||
"NAME_DUPLICATE": "Name is duplicate",
|
||||
"MAX_LENGTH": "Maximum name length reached",
|
||||
"CONFIRM_NOT_MATCH": "Confirm password not match",
|
||||
"KEY_REQUIRED": "Key is required",
|
||||
"KEY_NOT_VALID": "Key not valid"
|
||||
"KEY_NOT_VALID": "Key not valid",
|
||||
"INCORRECT_PASSWORD": "Incorrect password"
|
||||
}
|
||||
},
|
||||
"SEED_PHRASE": {
|
||||
|
|
@ -214,10 +217,21 @@
|
|||
"SEED_PHRASE_HINT": "Click to reveal the seed phrase",
|
||||
"BUTTON_SAVE": "Save",
|
||||
"BUTTON_REMOVE": "Close wallet",
|
||||
"CREATE_PASSWORD_SECURE": "Create a password to secure your seed",
|
||||
"INFO": "info",
|
||||
"SEED_IS_UNSECURED": "Seed is unsecured",
|
||||
"SEED_IS_SECURED": "Seed is secured",
|
||||
"REMEMBER_YOU_WILL_REQUIRE": "Remember, you will require the password to restore it.",
|
||||
"FORM": {
|
||||
"CONFIRM_PASSWORD": "Confirm password",
|
||||
"GENERATE_SECURE_SEED": "Generate Secure Seed",
|
||||
"SECURED_SEED_WILL_REQUIRE": "Secured seed will require this password to restore."
|
||||
},
|
||||
"FORM_ERRORS": {
|
||||
"NAME_REQUIRED": "Name is required",
|
||||
"NAME_DUPLICATE": "Name is duplicate",
|
||||
"MAX_LENGTH": "Maximum name length reached"
|
||||
"MAX_LENGTH": "Maximum name length reached",
|
||||
"PASSWORDS_DONT_MATCH": "Passwords don't match"
|
||||
}
|
||||
},
|
||||
"ASSIGN_ALIAS": {
|
||||
|
|
|
|||
1
src/gui/qt-daemon/html_source/src/assets/icons/info.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 384"><defs><style>.cls-1{fill:#fff;}</style></defs><title>info</title><path class="cls-1" d="M192,42.05476A149.94522,149.94522,0,0,1,298.02728,298.02728,149.94522,149.94522,0,1,1,85.97271,85.97271,148.96374,148.96374,0,0,1,192,42.05476M192,0C85.96132,0,0,85.96132,0,192S85.96132,384,192,384s192-85.96132,192-192S298.03868,0,192,0Z"/><rect class="cls-1" x="171" y="247.94524" width="42" height="42"/><rect class="cls-1" x="171" y="94.05476" width="42" height="120"/></svg>
|
||||
|
After Width: | Height: | Size: 561 B |
21
src/gui/qt-daemon/html_source/src/assets/icons/safety.svg
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Слой_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 320 384" style="enable-background:new 0 0 320 384;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{clip-path:url(#SVGID_2_);}
|
||||
.st1{clip-path:url(#SVGID_2_);fill:none;stroke:#000000;stroke-width:42;stroke-miterlimit:10;}
|
||||
</style>
|
||||
<g>
|
||||
<defs>
|
||||
<rect id="SVGID_1_" width="320" height="384"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_2_">
|
||||
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>
|
||||
</clipPath>
|
||||
<path class="st0" d="M159.9,44.5L278,85.8V232c0,0.9-0.4,9.2-14.7,26c-11,13-26.9,27.1-47.3,42c-20.6,15.1-41.6,27.8-56.1,36.1
|
||||
c-14.5-8.3-35.4-21-56-36.1c-20.3-14.9-36.2-29-47.2-42C42.4,241.2,42,232.9,42,232V85.8L159.9,44.5 M159.9,0L0,56v176
|
||||
c0,70.7,159.9,152,159.9,152S320,302.7,320,232V56L159.9,0z"/>
|
||||
<polyline class="st1" points="100.1,182.2 142.3,218.5 220.3,145.1 "/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1 KiB |
10
src/gui/qt-daemon/html_source/src/assets/icons/secured.svg
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 32 32" style="enable-background:new 0 0 32 32;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path class="st0" d="M26,15v-5c0-5.5-4.5-10-10-10h-0.1c-5.5,0-10,4.5-10,10v5H3v17h12.9H16h13V15H26z M9.9,10c0-3.3,2.7-6,6-6H16
|
||||
c3.3,0,6,2.7,6,6v5H9.9V10z M14,27v-7h4v7H14z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 582 B |
10
src/gui/qt-daemon/html_source/src/assets/icons/unsecured.svg
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 32 32" style="enable-background:new 0 0 32 32;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path class="st0" d="M22,15h-3.4H9.9v-5c0-3.3,2.7-6,6-6H16c3,0,5.4,2.2,5.9,5h4c-0.5-5-4.8-9-9.9-9h-0.1c-5.5,0-10,4.5-10,10v5H3
|
||||
v17h12.9H16h13V15h-3H22z M18,27h-4v-7h4V27z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 581 B |
|
|
@ -205,6 +205,16 @@ button {
|
|||
color: themed(redTextColor);
|
||||
}
|
||||
}
|
||||
.success-block {
|
||||
font-size: 1rem;
|
||||
line-height: 1.4rem;
|
||||
align-self: flex-end;
|
||||
text-align: right;
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(greenTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.error-text {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ $themes: (
|
|||
accountBackgroundColor: rgba(43, 54, 68, 0.5),
|
||||
accountHoverBackgroundColor: rgba(58, 69, 85, 0.5),
|
||||
accountMainTextColor: #e0e0e0,
|
||||
securedSeed: #e0e0e0,
|
||||
seedItemText: #e0e0e0,
|
||||
seedItemBackgroundColor: #18202a,
|
||||
accountOptionalTextColor: #556576,
|
||||
accountIndicatorTextColor: #111921,
|
||||
accountSwitchBackgroundColor: #000000,
|
||||
|
|
@ -90,6 +93,9 @@ $themes: (
|
|||
accountBackgroundColor: rgba(37, 40, 43, 0.5),
|
||||
accountHoverBackgroundColor: rgba(58, 62, 66, 0.5),
|
||||
accountMainTextColor: #e0e0e0,
|
||||
securedSeed: #e0e0e0,
|
||||
seedItemText: #e0e0e0,
|
||||
seedItemBackgroundColor: #292d31,
|
||||
accountOptionalTextColor: #565c62,
|
||||
accountIndicatorTextColor: #1a1a1a,
|
||||
accountSwitchBackgroundColor: #000000,
|
||||
|
|
@ -147,6 +153,9 @@ $themes: (
|
|||
accountBackgroundColor: rgba(30, 136, 229, 1),
|
||||
accountHoverBackgroundColor: rgba(240, 240, 240, 0.5),
|
||||
accountMainTextColor: #ffffff,
|
||||
securedSeed: #a0a5ab,
|
||||
seedItemText: #43454b,
|
||||
seedItemBackgroundColor: #e6e6e6,
|
||||
accountOptionalTextColor: #91baf1,
|
||||
accountIndicatorTextColor: #43454b,
|
||||
accountSwitchBackgroundColor: #ffffff,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,258 @@
|
|||
.form-details {
|
||||
margin-top: 1.8rem;
|
||||
|
||||
.input-block {
|
||||
|
||||
&:first-child {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.wallet-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
button {
|
||||
margin: 2.9rem 0;
|
||||
width: 100%;
|
||||
max-width: 15rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-seed {
|
||||
|
||||
label {
|
||||
@include themify($themes) {
|
||||
color: themed(optionalTextColor);
|
||||
}
|
||||
|
||||
font-size: 1.3rem;
|
||||
line-height: 2.4rem;
|
||||
}
|
||||
|
||||
.form-content {
|
||||
@include themify($themes) {
|
||||
border: 2px solid themed(transparentButtonBorderColor);
|
||||
}
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 3rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.text-coral {
|
||||
@include themify($themes) {
|
||||
color: themed(blueTextColor);
|
||||
}
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.seed-phrase-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
max-width: 38rem;
|
||||
width: 100%;
|
||||
|
||||
.input-block,
|
||||
button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
margin-top: 1rem;
|
||||
@include themify($themes) {
|
||||
color: themed(orangeTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
.secured-seed {
|
||||
@include themify($themes) {
|
||||
color: themed(securedSeed);
|
||||
}
|
||||
font-size: 1.2rem;
|
||||
line-height: 2.4rem;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
|
||||
.icon {
|
||||
margin-right: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 3rem;
|
||||
margin-bottom: 2rem;
|
||||
|
||||
.icon {
|
||||
margin-right: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.seed-phrase {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
background-color: transparent !important;
|
||||
|
||||
&-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
@include themify($themes) {
|
||||
color: themed(optionalTextColor);
|
||||
}
|
||||
.right-part {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
.icon {
|
||||
cursor: pointer;
|
||||
width: 1.7rem;
|
||||
height: 1.7rem;
|
||||
|
||||
&.copy {
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
margin-right: 1.2rem;
|
||||
mask: url(~src/assets/icons/copy.svg) no-repeat center;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.75;
|
||||
}
|
||||
}
|
||||
|
||||
&.copied {
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
margin-right: 1.2rem;
|
||||
mask: url(~src/assets/icons/complete-testwallet.svg) no-repeat center;
|
||||
}
|
||||
|
||||
&.secured,
|
||||
&.unsecured {
|
||||
margin-left: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 1.3rem;
|
||||
line-height: 2.4rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
.icon {
|
||||
margin-left: 1.2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-content {
|
||||
@include themify($themes) {
|
||||
border-top: 2px solid themed(transparentButtonBorderColor);
|
||||
border-bottom: 2px solid themed(transparentButtonBorderColor);
|
||||
}
|
||||
padding: 1rem 0 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
.item {
|
||||
@include themify($themes) {
|
||||
color: themed(seedItemText);
|
||||
}
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 2rem;
|
||||
width: calc(100% / 7);
|
||||
min-height: 35px;
|
||||
font-size: 1.3rem;
|
||||
|
||||
&.dark {
|
||||
@include themify($themes) {
|
||||
background-color: themed(seedItemBackgroundColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-footer {
|
||||
text-align: center;
|
||||
|
||||
.title {
|
||||
@include themify($themes) {
|
||||
color: themed(seedItemText);
|
||||
}
|
||||
font-size: 1.3rem;
|
||||
line-height: 2.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: inline-flex;
|
||||
width: 1.6rem;
|
||||
height: 1.6rem;
|
||||
|
||||
&.secured {
|
||||
@include themify($themes) {
|
||||
background-color: themed(greenTextColor);
|
||||
}
|
||||
mask: url(~src/assets/icons/secured.svg) no-repeat center;
|
||||
}
|
||||
|
||||
&.info {
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
mask: url(~src/assets/icons/info.svg) no-repeat center;
|
||||
}
|
||||
|
||||
&.unsecured {
|
||||
@include themify($themes) {
|
||||
background-color: themed(orangeTextColor);
|
||||
}
|
||||
mask: url(~src/assets/icons/unsecured.svg) no-repeat center;
|
||||
}
|
||||
|
||||
&.safety {
|
||||
@include themify($themes) {
|
||||
background-color: themed(alternativeTextColor);
|
||||
}
|
||||
mask: url(~src/assets/icons/safety.svg) no-repeat center;
|
||||
}
|
||||
}
|
||||
|
||||
.wrap-buttons {
|
||||
display: flex;
|
||||
|
||||
.seed-phrase-button {
|
||||
margin: 2.8rem 0;
|
||||
width: 25%;
|
||||
min-width: 1.5rem;
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
margin: 2.8rem 1rem;
|
||||
width: 25%;
|
||||
min-width: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,14 @@ app-wallet {
|
|||
background-color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
&:disabled {
|
||||
background-color: transparent !important;
|
||||
.icon {
|
||||
@include themify($themes) {
|
||||
background-color: themed(accountOptionalTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.alias {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
@import 'assets/scss/layout/status';
|
||||
@import 'assets/scss/layout/wallet';
|
||||
@import 'assets/scss/layout/contact';
|
||||
@import 'assets/scss/layout/seed-phrase';
|
||||
|
||||
// MODULES
|
||||
@import 'assets/scss/modules/head';
|
||||
|
|
|
|||
|
|
@ -8,16 +8,11 @@
|
|||
#include "application/mainwindow.h"
|
||||
#include "qdebug.h"
|
||||
#include <thread>
|
||||
#include <math.h>
|
||||
//#include "qtlogger.h"
|
||||
#include "include_base_utils.h"
|
||||
#include "currency_core/currency_config.h"
|
||||
#include <math.h>
|
||||
|
||||
// class MyApplication : public QApplication
|
||||
// {
|
||||
//
|
||||
//
|
||||
// }
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ namespace
|
|||
const command_line::arg_descriptor<std::string> arg_password = {"password", "Wallet password", "", true};
|
||||
const command_line::arg_descriptor<bool> arg_dont_refresh = { "no-refresh", "Do not refresh after load", false, true };
|
||||
const command_line::arg_descriptor<bool> arg_dont_set_date = { "no-set-creation-date", "Do not set wallet creation date", false, false };
|
||||
const command_line::arg_descriptor<bool> arg_print_brain_wallet = { "print-brain-wallet", "Print to conosole brain wallet", false, false };
|
||||
const command_line::arg_descriptor<int> arg_daemon_port = {"daemon-port", "Use daemon instance at port <arg> instead of default", 0};
|
||||
const command_line::arg_descriptor<uint32_t> arg_log_level = {"set-log", "", 0, true};
|
||||
const command_line::arg_descriptor<bool> arg_do_pos_mining = { "do-pos-mining", "Do PoS mining", false, false };
|
||||
|
|
@ -180,7 +179,6 @@ bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<st
|
|||
|
||||
simple_wallet::simple_wallet()
|
||||
: m_daemon_port(0),
|
||||
m_print_brain_wallet(false),
|
||||
m_do_refresh_after_load(false),
|
||||
m_do_not_set_date(false),
|
||||
m_do_pos_mining(false),
|
||||
|
|
@ -309,10 +307,6 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
|
|||
m_do_refresh_after_load = false;
|
||||
}
|
||||
|
||||
if (command_line::has_arg(vm, arg_print_brain_wallet))
|
||||
{
|
||||
m_print_brain_wallet = true;
|
||||
}
|
||||
|
||||
if (!m_generate_new.empty())
|
||||
{
|
||||
|
|
@ -338,9 +332,26 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
|
|||
fail_msg_writer() << "failed to read seed phrase";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool looks_like_tracking_seed = restore_seed_container.password().find(':') != std::string::npos;
|
||||
bool r = restore_wallet(m_restore_wallet, restore_seed_container.password(), pwd_container.password(), looks_like_tracking_seed);
|
||||
tools::password_container seed_password_container;
|
||||
|
||||
if (!looks_like_tracking_seed)
|
||||
{
|
||||
bool is_password_protected = false;
|
||||
bool sr = account_base::is_seed_password_protected(restore_seed_container.password(), is_password_protected);
|
||||
if (!sr)
|
||||
{
|
||||
fail_msg_writer() << "failed to parse seed phrase";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_password_protected && !seed_password_container.read_password("This seed is secured, to use it please enter the password:\n"))
|
||||
{
|
||||
fail_msg_writer() << "failed to read seed phrase";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool r = restore_wallet(m_restore_wallet, restore_seed_container.password(), pwd_container.password(), looks_like_tracking_seed, seed_password_container.password());
|
||||
CHECK_AND_ASSERT_MES(r, false, "wallet restoring failed");
|
||||
}
|
||||
else
|
||||
|
|
@ -402,10 +413,6 @@ bool simple_wallet::new_wallet(const string &wallet_file, const std::string& pas
|
|||
if (m_do_not_set_date)
|
||||
m_wallet->reset_creation_time(0);
|
||||
|
||||
if (m_print_brain_wallet)
|
||||
{
|
||||
std::cout << "Seed phrase (keep it in secret): " << m_wallet->get_account().get_seed_phrase() << std::endl << std::flush;
|
||||
}
|
||||
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
|
|
@ -424,7 +431,7 @@ bool simple_wallet::new_wallet(const string &wallet_file, const std::string& pas
|
|||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::string& seed_or_tracking_seed, const std::string& password, bool tracking_wallet)
|
||||
bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::string& seed_or_tracking_seed, const std::string& password, bool tracking_wallet, const std::string& seed_password)
|
||||
{
|
||||
m_wallet_file = wallet_file;
|
||||
|
||||
|
|
@ -436,13 +443,13 @@ bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::st
|
|||
if (tracking_wallet)
|
||||
{
|
||||
// auditable watch-only aka tracking wallet
|
||||
m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_tracking_seed, true);
|
||||
m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_tracking_seed, true, "");
|
||||
message_writer(epee::log_space::console_color_white, true) << "Tracking wallet restored: " << m_wallet->get_account().get_public_address_str();
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal or auditable wallet
|
||||
m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_tracking_seed, false);
|
||||
m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_tracking_seed, false, seed_password);
|
||||
message_writer(epee::log_space::console_color_white, true) << (m_wallet->is_auditable() ? "Auditable wallet" : "Wallet") << " restored: " << m_wallet->get_account().get_public_address_str();
|
||||
std::cout << "view key: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().view_secret_key) << std::endl << std::flush;
|
||||
if (m_wallet->is_auditable())
|
||||
|
|
@ -456,7 +463,11 @@ bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::st
|
|||
fail_msg_writer() << "failed to restore wallet, check your " << (tracking_wallet ? "tracking seed!" : "seed phrase!") << ENDL << e.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
catch (...)
|
||||
{
|
||||
fail_msg_writer() << "failed to restore wallet, check your " << (tracking_wallet ? "tracking seed!" : "seed phrase!") << ENDL;
|
||||
return false;
|
||||
}
|
||||
m_wallet->init(m_daemon_address);
|
||||
|
||||
success_msg_writer() <<
|
||||
|
|
@ -484,9 +495,6 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa
|
|||
m_wallet->load(epee::string_encoding::utf8_to_wstring(m_wallet_file), password);
|
||||
message_writer(epee::log_space::console_color_white, true) << "Opened" << (m_wallet->is_auditable() ? " auditable" : "") << (m_wallet->is_watch_only() ? " watch-only" : "") << " wallet: " << m_wallet->get_account().get_public_address_str();
|
||||
|
||||
if (m_print_brain_wallet)
|
||||
std::cout << "Seed phrase (keep it in secret): " << m_wallet->get_account().get_seed_phrase() << std::endl << std::flush;
|
||||
|
||||
break;
|
||||
}
|
||||
catch (const tools::error::wallet_load_notice_wallet_restored& /*e*/)
|
||||
|
|
@ -1361,9 +1369,24 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::show_seed(const std::vector<std::string> &args)
|
||||
{
|
||||
success_msg_writer() << "Here's your wallet's seed phrase. Write it down and keep in a safe place.";
|
||||
success_msg_writer(true) << "Anyone who knows the following 26 words can access your wallet:";
|
||||
std::cout << m_wallet->get_account().get_seed_phrase() << std::endl << std::flush;
|
||||
success_msg_writer() << "Please enter a password to secure this seed. Securing your seed is HIGHLY recommended. Leave password blank to stay unsecured.";
|
||||
success_msg_writer(true) << "Remember, restoring a wallet from Secured Seed can only be done if you know its password.";
|
||||
|
||||
tools::password_container seed_password_container1;
|
||||
if (!seed_password_container1.read_password("Enter seed password: "))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
tools::password_container seed_password_container2;
|
||||
if (!seed_password_container2.read_password("Confirm seed password: "))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(seed_password_container1.password() != seed_password_container2.password())
|
||||
{
|
||||
std::cout << "Error: password mismatch. Please make sure you entered the correct password and confirmed it" << std::endl << std::flush;
|
||||
}
|
||||
std::cout << m_wallet->get_account().get_seed_phrase(seed_password_container2.password()) << std::endl << std::flush;
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -1868,7 +1891,6 @@ int main(int argc, char* argv[])
|
|||
command_line::add_arg(desc_params, arg_log_level);
|
||||
command_line::add_arg(desc_params, arg_dont_refresh);
|
||||
command_line::add_arg(desc_params, arg_dont_set_date);
|
||||
command_line::add_arg(desc_params, arg_print_brain_wallet);
|
||||
command_line::add_arg(desc_params, arg_do_pos_mining);
|
||||
command_line::add_arg(desc_params, arg_pos_mining_reward_address);
|
||||
command_line::add_arg(desc_params, arg_restore_wallet);
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ namespace currency
|
|||
|
||||
bool new_wallet(const std::string &wallet_file, const std::string& password, bool create_auditable_wallet);
|
||||
bool open_wallet(const std::string &wallet_file, const std::string& password);
|
||||
bool restore_wallet(const std::string& wallet_file, const std::string& seed_or_tracking_seed, const std::string& password, bool tracking_wallet);
|
||||
bool restore_wallet(const std::string& wallet_file, const std::string& seed_or_tracking_seed, const std::string& password, bool tracking_wallet, const std::string& seed_password);
|
||||
bool close_wallet();
|
||||
|
||||
bool help(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
|
|
@ -163,7 +163,6 @@ namespace currency
|
|||
int m_daemon_port;
|
||||
bool m_do_refresh_after_load;
|
||||
bool m_do_not_set_date;
|
||||
bool m_print_brain_wallet;
|
||||
bool m_do_pos_mining;
|
||||
bool m_offline_mode;
|
||||
std::string m_restore_wallet;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,6 @@
|
|||
#define PROJECT_REVISION "7"
|
||||
#define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION
|
||||
|
||||
#define PROJECT_VERSION_BUILD_NO 112
|
||||
#define PROJECT_VERSION_BUILD_NO 114
|
||||
#define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO)
|
||||
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]"
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include "common/base58.h"
|
||||
#include "common/config_encrypt_helper.h"
|
||||
#include "static_helpers.h"
|
||||
#include "wallet_helpers.h"
|
||||
|
||||
|
||||
#define ANDROID_PACKAGE_NAME "com.zano_mobile"
|
||||
|
|
@ -400,13 +401,13 @@ namespace plain_wallet
|
|||
return epee::serialization::store_t_to_json(err_result);
|
||||
}
|
||||
|
||||
std::string restore(const std::string& seed, const std::string& path, const std::string& password)
|
||||
std::string restore(const std::string& seed, const std::string& path, const std::string& password, const std::string& seed_password)
|
||||
{
|
||||
GET_INSTANCE_PTR(inst_ptr);
|
||||
|
||||
std::string full_path = get_wallets_folder() + path;
|
||||
epee::json_rpc::response<view::open_wallet_response, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
|
||||
std::string rsp = inst_ptr->gwm.restore_wallet(epee::string_encoding::convert_to_unicode(full_path), password, seed, ok_response.result);
|
||||
std::string rsp = inst_ptr->gwm.restore_wallet(epee::string_encoding::convert_to_unicode(full_path), password, seed, seed_password, ok_response.result);
|
||||
if (rsp == API_RETURN_CODE_OK || rsp == API_RETURN_CODE_FILE_RESTORED)
|
||||
{
|
||||
if (rsp == API_RETURN_CODE_FILE_RESTORED)
|
||||
|
|
@ -484,21 +485,35 @@ namespace plain_wallet
|
|||
LOG_PRINT_L2("[ASYNC_CALL]: Finished(result put), job id: " << job_id);
|
||||
}
|
||||
|
||||
|
||||
std::string async_call(const std::string& method_name, uint64_t instance_id, const std::string& params)
|
||||
{
|
||||
GET_INSTANCE_PTR(inst_ptr);
|
||||
std::function<void()> async_callback;
|
||||
|
||||
uint64_t job_id = inst_ptr->gjobs_counter++;
|
||||
async_callback = [job_id, instance_id, method_name, params]()
|
||||
{
|
||||
std::string res_str = sync_call(method_name, instance_id, params);
|
||||
put_result(job_id, res_str);
|
||||
};
|
||||
|
||||
std::thread t([async_callback]() {async_callback(); });
|
||||
t.detach();
|
||||
LOG_PRINT_L2("[ASYNC_CALL]: started " << method_name << ", job id: " << job_id);
|
||||
return std::string("{ \"job_id\": ") + std::to_string(job_id) + "}";
|
||||
}
|
||||
|
||||
|
||||
std::string sync_call(const std::string& method_name, uint64_t instance_id, const std::string& params)
|
||||
{
|
||||
std::string res;
|
||||
if (method_name == "close")
|
||||
{
|
||||
async_callback = [job_id, instance_id]()
|
||||
{
|
||||
close_wallet(instance_id);
|
||||
view::api_responce_return_code rc = AUTO_VAL_INIT(rc);
|
||||
rc.return_code = API_RETURN_CODE_OK;
|
||||
put_result(job_id, epee::serialization::store_t_to_json(rc));
|
||||
};
|
||||
res = epee::serialization::store_t_to_json(rc);
|
||||
}
|
||||
else if (method_name == "open")
|
||||
{
|
||||
|
|
@ -507,13 +522,11 @@ namespace plain_wallet
|
|||
{
|
||||
view::api_response ar = AUTO_VAL_INIT(ar);
|
||||
ar.error_code = "Wrong parameter";
|
||||
put_result(job_id, epee::serialization::store_t_to_json(ar));
|
||||
}
|
||||
async_callback = [job_id, owr]()
|
||||
res = epee::serialization::store_t_to_json(ar);
|
||||
}else
|
||||
{
|
||||
std::string res = open(owr.path, owr.pass);
|
||||
put_result(job_id, res);
|
||||
};
|
||||
res = open(owr.path, owr.pass);
|
||||
}
|
||||
}
|
||||
else if (method_name == "restore")
|
||||
{
|
||||
|
|
@ -522,46 +535,49 @@ namespace plain_wallet
|
|||
{
|
||||
view::api_response ar = AUTO_VAL_INIT(ar);
|
||||
ar.error_code = "Wrong parameter";
|
||||
put_result(job_id, epee::serialization::store_t_to_json(ar));
|
||||
res = epee::serialization::store_t_to_json(ar);
|
||||
}
|
||||
async_callback = [job_id, rwr]()
|
||||
else
|
||||
{
|
||||
std::string res = restore(rwr.restore_key, rwr.path, rwr.pass);
|
||||
put_result(job_id, res);
|
||||
};
|
||||
res = restore(rwr.seed_phrase, rwr.path, rwr.pass, rwr.seed_pass);
|
||||
}
|
||||
}
|
||||
else if (method_name == "get_seed_phrase_info")
|
||||
{
|
||||
view::seed_info_param sip = AUTO_VAL_INIT(sip);
|
||||
if (!epee::serialization::load_t_from_json(sip, params))
|
||||
{
|
||||
view::api_response ar = AUTO_VAL_INIT(ar);
|
||||
ar.error_code = "Wrong parameter";
|
||||
res = epee::serialization::store_t_to_json(ar);
|
||||
}
|
||||
else
|
||||
{
|
||||
view::api_response_t<view::seed_phrase_info> rsp = AUTO_VAL_INIT(rsp);
|
||||
rsp.error_code = tools::get_seed_phrase_info(sip.seed_phrase, sip.seed_password, rsp.response_data);
|
||||
res = epee::serialization::store_t_to_json(rsp);
|
||||
}
|
||||
}
|
||||
else if (method_name == "invoke")
|
||||
{
|
||||
std::string local_params = params;
|
||||
async_callback = [job_id, local_params, instance_id]()
|
||||
{
|
||||
std::string res = invoke(instance_id, local_params);
|
||||
put_result(job_id, res);
|
||||
};
|
||||
res = invoke(instance_id, params);
|
||||
}
|
||||
else if (method_name == "get_wallet_status")
|
||||
{
|
||||
std::string local_params = params;
|
||||
async_callback = [job_id, local_params, instance_id]()
|
||||
{
|
||||
std::string res = get_wallet_status(instance_id);
|
||||
put_result(job_id, res);
|
||||
};
|
||||
}else
|
||||
res = get_wallet_status(instance_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
view::api_response ar = AUTO_VAL_INIT(ar);
|
||||
ar.error_code = "UNKNOWN METHOD";
|
||||
put_result(job_id, epee::serialization::store_t_to_json(ar));
|
||||
return std::string("{ \"job_id\": ") + std::to_string(job_id) + "}";;
|
||||
res = epee::serialization::store_t_to_json(ar);
|
||||
}
|
||||
|
||||
|
||||
std::thread t([async_callback]() {async_callback(); });
|
||||
t.detach();
|
||||
LOG_PRINT_L2("[ASYNC_CALL]: started " << method_name << ", job id: " << job_id);
|
||||
return std::string("{ \"job_id\": ") + std::to_string(job_id) + "}";
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
std::string try_pull_result(uint64_t job_id)
|
||||
{
|
||||
auto inst_ptr = std::atomic_load(&ginstance_ptr);
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace plain_wallet
|
|||
std::string get_connectivity_status();
|
||||
|
||||
std::string open(const std::string& path, const std::string& password);
|
||||
std::string restore(const std::string& seed, const std::string& path, const std::string& password);
|
||||
std::string restore(const std::string& seed, const std::string& path, const std::string& password, const std::string& seed_password);
|
||||
std::string generate(const std::string& path, const std::string& password);
|
||||
std::string get_opened_wallets();
|
||||
|
||||
|
|
@ -38,4 +38,5 @@ namespace plain_wallet
|
|||
//async api
|
||||
std::string async_call(const std::string& method_name, uint64_t instance_id, const std::string& params);
|
||||
std::string try_pull_result(uint64_t);
|
||||
std::string sync_call(const std::string& method_name, uint64_t instance_id, const std::string& params);
|
||||
}
|
||||
|
|
@ -272,6 +272,19 @@ public:
|
|||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
||||
struct request_get_smart_wallet_info
|
||||
{
|
||||
uint64_t wallet_id;
|
||||
std::string seed_password;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(wallet_id)
|
||||
KV_SERIALIZE(seed_password)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
||||
struct response_mining_estimate
|
||||
{
|
||||
uint64_t final_amount;
|
||||
|
|
@ -429,16 +442,19 @@ public:
|
|||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
||||
struct restore_wallet_request
|
||||
{
|
||||
std::string pass;
|
||||
std::string seed_pass;
|
||||
std::string path;
|
||||
std::string restore_key;
|
||||
std::string seed_phrase;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(pass)
|
||||
KV_SERIALIZE(path)
|
||||
KV_SERIALIZE(restore_key)
|
||||
KV_SERIALIZE(seed_pass)
|
||||
KV_SERIALIZE(seed_phrase)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
|
@ -548,6 +564,8 @@ public:
|
|||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
typedef tools::wallet_public::seed_info_param seed_info_param;
|
||||
typedef tools::wallet_public::seed_phrase_info seed_phrase_info;
|
||||
|
||||
struct start_backend_params
|
||||
{
|
||||
|
|
@ -587,12 +605,10 @@ public:
|
|||
|
||||
struct get_restore_info_response
|
||||
{
|
||||
std::string restore_key;
|
||||
std::string error_code;
|
||||
std::string seed_phrase;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(restore_key)
|
||||
KV_SERIALIZE(error_code)
|
||||
KV_SERIALIZE(seed_phrase)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2347,7 +2347,7 @@ void wallet2::generate(const std::wstring& path, const std::string& pass, bool a
|
|||
store();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::restore(const std::wstring& path, const std::string& pass, const std::string& seed_or_tracking_seed, bool tracking_wallet)
|
||||
void wallet2::restore(const std::wstring& path, const std::string& pass, const std::string& seed_or_tracking_seed, bool tracking_wallet, const std::string& seed_password)
|
||||
{
|
||||
bool r = false;
|
||||
clear();
|
||||
|
|
@ -2363,7 +2363,7 @@ void wallet2::restore(const std::wstring& path, const std::string& pass, const s
|
|||
}
|
||||
else
|
||||
{
|
||||
r = m_account.restore_from_seed_phrase(seed_or_tracking_seed);
|
||||
r = m_account.restore_from_seed_phrase(seed_or_tracking_seed, seed_password);
|
||||
init_log_prefix();
|
||||
THROW_IF_FALSE_WALLET_EX(r, error::wallet_wrong_seed_error, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -470,7 +470,7 @@ namespace tools
|
|||
|
||||
void assign_account(const currency::account_base& acc);
|
||||
void generate(const std::wstring& path, const std::string& password, bool auditable_wallet);
|
||||
void restore(const std::wstring& path, const std::string& pass, const std::string& seed_or_tracking_seed, bool tracking_wallet);
|
||||
void restore(const std::wstring& path, const std::string& pass, const std::string& seed_or_tracking_seed, bool tracking_wallet, const std::string& seed_password);
|
||||
void load(const std::wstring& path, const std::string& password);
|
||||
void store();
|
||||
void store(const std::wstring& path);
|
||||
|
|
|
|||
|
|
@ -23,4 +23,43 @@ namespace tools
|
|||
wi.is_watch_only = w.is_watch_only();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline std::string get_seed_phrase_info(const std::string& seed_phrase, const std::string& seed_password, view::seed_phrase_info& result)
|
||||
{
|
||||
//cut the last timestamp word from restore_dats
|
||||
try
|
||||
{
|
||||
//restore_from_tracking_seed
|
||||
bool is_tracking = currency::account_base::is_seed_tracking(seed_phrase);
|
||||
if (is_tracking)
|
||||
{
|
||||
currency::account_base acc;
|
||||
result.require_password = false;
|
||||
result.hash_sum_matched = false;
|
||||
result.syntax_correct = acc.restore_from_tracking_seed(seed_phrase);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.syntax_correct = currency::account_base::is_seed_password_protected(seed_phrase, result.require_password);
|
||||
if (result.syntax_correct && result.require_password)
|
||||
{
|
||||
if (seed_password.size())
|
||||
{
|
||||
currency::account_base acc;
|
||||
result.hash_sum_matched = acc.restore_from_seed_phrase(seed_phrase, seed_password);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.hash_sum_matched = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return API_RETURN_CODE_OK;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
result.syntax_correct = false;
|
||||
return API_RETURN_CODE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -168,6 +168,29 @@ namespace wallet_public
|
|||
};
|
||||
|
||||
|
||||
struct seed_info_param
|
||||
{
|
||||
std::string seed_phrase;
|
||||
std::string seed_password;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(seed_phrase)
|
||||
KV_SERIALIZE(seed_password)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct seed_phrase_info
|
||||
{
|
||||
bool syntax_correct;
|
||||
bool require_password;
|
||||
bool hash_sum_matched;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(syntax_correct)
|
||||
KV_SERIALIZE(require_password)
|
||||
KV_SERIALIZE(hash_sum_matched)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct COMMAND_RPC_GET_BALANCE
|
||||
{
|
||||
|
|
@ -221,7 +244,6 @@ namespace wallet_public
|
|||
{
|
||||
std::string address;
|
||||
std::string path;
|
||||
std::string seed;
|
||||
uint64_t transfers_count;
|
||||
uint64_t transfer_entries_count;
|
||||
bool is_whatch_only;
|
||||
|
|
@ -230,7 +252,6 @@ namespace wallet_public
|
|||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(address)
|
||||
KV_SERIALIZE(path)
|
||||
KV_SERIALIZE(seed)
|
||||
KV_SERIALIZE(transfers_count)
|
||||
KV_SERIALIZE(transfer_entries_count)
|
||||
KV_SERIALIZE(is_whatch_only)
|
||||
|
|
@ -239,6 +260,32 @@ namespace wallet_public
|
|||
};
|
||||
};
|
||||
|
||||
struct COMMAND_RPC_GET_WALLET_RESTORE_INFO
|
||||
{
|
||||
struct request
|
||||
{
|
||||
std::string seed_password;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(seed_password)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
std::string seed_phrase;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(seed_phrase)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
struct COMMAND_RPC_GET_SEED_PHRASE_INFO
|
||||
{
|
||||
typedef seed_info_param request;
|
||||
typedef seed_phrase_info response;
|
||||
};
|
||||
|
||||
struct wallet_provision_info
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ using namespace epee;
|
|||
#include "misc_language.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "wallet_rpc_server_error_codes.h"
|
||||
#include "wallet_helpers.h"
|
||||
|
||||
#define WALLET_RPC_BEGIN_TRY_ENTRY() try {
|
||||
#define WALLET_RPC_CATCH_TRY_ENTRY() } \
|
||||
|
|
@ -196,7 +197,6 @@ namespace tools
|
|||
res.path = epee::string_encoding::convert_to_ansii(m_wallet.get_wallet_path());
|
||||
res.transfers_count = m_wallet.get_recent_transfers_total_count();
|
||||
res.transfer_entries_count = m_wallet.get_transfer_entries_count();
|
||||
res.seed = m_wallet.get_account().get_seed_phrase();
|
||||
std::map<uint64_t, uint64_t> distribution;
|
||||
m_wallet.get_utxo_distribution(distribution);
|
||||
for (const auto& ent : distribution)
|
||||
|
|
@ -211,6 +211,25 @@ namespace tools
|
|||
return false;
|
||||
}
|
||||
}
|
||||
bool wallet_rpc_server::on_getwallet_restore_info(const wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO::request& req, wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
{
|
||||
try
|
||||
{
|
||||
res.seed_phrase = m_wallet.get_account().get_seed_phrase(req.seed_password);
|
||||
return true;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
||||
er.message = e.what();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool wallet_rpc_server::on_get_seed_phrase_info(const wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO::request& req, wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
{
|
||||
tools::get_seed_phrase_info(req.seed_phrase, req.seed_password, res);
|
||||
return true;
|
||||
}
|
||||
bool wallet_rpc_server::on_get_recent_txs_and_info(const wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::request& req, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
{
|
||||
try
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ namespace tools
|
|||
MAP_JON_RPC_WE("sign_transfer", on_sign_transfer, wallet_public::COMMAND_SIGN_TRANSFER)
|
||||
MAP_JON_RPC_WE("submit_transfer", on_submit_transfer, wallet_public::COMMAND_SUBMIT_TRANSFER)
|
||||
MAP_JON_RPC_WE("search_for_transactions", on_search_for_transactions, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS)
|
||||
MAP_JON_RPC_WE("get_restore_info", on_getwallet_restore_info, wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO)
|
||||
MAP_JON_RPC_WE("get_seed_phrase_info", on_get_seed_phrase_info, wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO)
|
||||
//contracts API
|
||||
MAP_JON_RPC_WE("contracts_send_proposal", on_contracts_send_proposal, wallet_public::COMMAND_CONTRACTS_SEND_PROPOSAL)
|
||||
MAP_JON_RPC_WE("contracts_accept_proposal", on_contracts_accept_proposal, wallet_public::COMMAND_CONTRACTS_ACCEPT_PROPOSAL)
|
||||
|
|
@ -70,6 +72,8 @@ namespace tools
|
|||
bool on_getbalance(const wallet_public::COMMAND_RPC_GET_BALANCE::request& req, wallet_public::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_getaddress(const wallet_public::COMMAND_RPC_GET_ADDRESS::request& req, wallet_public::COMMAND_RPC_GET_ADDRESS::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_getwallet_info(const wallet_public::COMMAND_RPC_GET_WALLET_INFO::request& req, wallet_public::COMMAND_RPC_GET_WALLET_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_getwallet_restore_info(const wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO::request& req, wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_get_seed_phrase_info(const wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO::request& req, wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_get_recent_txs_and_info(const wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::request& req, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_transfer(const wallet_public::COMMAND_RPC_TRANSFER::request& req, wallet_public::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_store(const wallet_public::COMMAND_RPC_STORE::request& req, wallet_public::COMMAND_RPC_STORE::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
|
|
|
|||
|
|
@ -911,7 +911,7 @@ std::string wallets_manager::open_wallet(const std::wstring& path, const std::st
|
|||
w->get_unconfirmed_transfers(owr.recent_history.history, exclude_mining_txs);
|
||||
owr.wallet_local_bc_size = w->get_blockchain_current_size();
|
||||
//workaround for missed fee
|
||||
owr.seed = w->get_account().get_seed_phrase();
|
||||
//owr.seed = w->get_account().get_seed_phrase();
|
||||
break;
|
||||
}
|
||||
catch (const tools::error::file_not_found& /**/)
|
||||
|
|
@ -1015,7 +1015,7 @@ std::string wallets_manager::generate_wallet(const std::wstring& path, const std
|
|||
{
|
||||
w->generate(path, password, false);
|
||||
w->set_minimum_height(m_last_daemon_height);
|
||||
owr.seed = w->get_account().get_seed_phrase();
|
||||
//owr.seed = w->get_account().get_seed_phrase();
|
||||
}
|
||||
catch (const tools::error::file_exists&)
|
||||
{
|
||||
|
|
@ -1058,18 +1058,24 @@ std::string wallets_manager::is_pos_allowed()
|
|||
else
|
||||
return API_RETURN_CODE_FALSE;
|
||||
}
|
||||
std::string wallets_manager::is_valid_brain_restore_data(const std::string& seed_phrase)
|
||||
std::string wallets_manager::is_valid_brain_restore_data(const std::string& seed_phrase, const std::string& seed_password)
|
||||
{
|
||||
|
||||
currency::account_base acc;
|
||||
if (acc.restore_from_seed_phrase(seed_phrase))
|
||||
return API_RETURN_CODE_TRUE;
|
||||
|
||||
currency::account_public_address addr;
|
||||
crypto::secret_key view_sec_key;
|
||||
uint64_t ts;
|
||||
if (currency::parse_tracking_seed(seed_phrase, addr, view_sec_key, ts))
|
||||
return API_RETURN_CODE_TRUE;
|
||||
if (!currency::account_base::is_seed_tracking(seed_phrase))
|
||||
{
|
||||
if (acc.restore_from_seed_phrase(seed_phrase, seed_password))
|
||||
return API_RETURN_CODE_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
currency::account_public_address addr = AUTO_VAL_INIT(addr);
|
||||
crypto::secret_key view_sec_key = AUTO_VAL_INIT(view_sec_key);
|
||||
uint64_t ts = 0;
|
||||
if (currency::parse_tracking_seed(seed_phrase, addr, view_sec_key, ts))
|
||||
return API_RETURN_CODE_TRUE;
|
||||
|
||||
}
|
||||
return API_RETURN_CODE_FALSE;
|
||||
}
|
||||
#ifndef MOBILE_WALLET_BUILD
|
||||
|
|
@ -1081,11 +1087,18 @@ void wallets_manager::subscribe_to_core_events(currency::i_core_event_handler* p
|
|||
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string wallets_manager::get_seed_phrase_info(const std::string& seed_phrase, const std::string& seed_password, view::seed_phrase_info& result)
|
||||
{
|
||||
return tools::get_seed_phrase_info(seed_phrase, seed_password, result);
|
||||
}
|
||||
|
||||
|
||||
void wallets_manager::get_gui_options(view::gui_options& opt)
|
||||
{
|
||||
opt = m_ui_opt;
|
||||
}
|
||||
std::string wallets_manager::restore_wallet(const std::wstring& path, const std::string& password, const std::string& restore_key, view::open_wallet_response& owr)
|
||||
std::string wallets_manager::restore_wallet(const std::wstring& path, const std::string& password, const std::string& seed_phrase, const std::string& seed_password, view::open_wallet_response& owr)
|
||||
{
|
||||
std::shared_ptr<tools::wallet2> w(new tools::wallet2());
|
||||
w->set_use_deffered_global_outputs(m_use_deffered_global_outputs);
|
||||
|
|
@ -1108,9 +1121,9 @@ std::string wallets_manager::restore_wallet(const std::wstring& path, const std:
|
|||
currency::account_base acc;
|
||||
try
|
||||
{
|
||||
bool auditable_watch_only = restore_key.find(':') != std::string::npos;
|
||||
w->restore(path, password, restore_key, auditable_watch_only);
|
||||
owr.seed = w->get_account().get_seed_phrase();
|
||||
bool is_tracking = currency::account_base::is_seed_tracking(seed_phrase);
|
||||
w->restore(path, password, seed_phrase, is_tracking, seed_password);
|
||||
//owr.seed = w->get_account().get_seed_phrase();
|
||||
}
|
||||
catch (const tools::error::file_exists&)
|
||||
{
|
||||
|
|
@ -1625,14 +1638,14 @@ std::string wallets_manager::get_mining_history(uint64_t wallet_id, tools::walle
|
|||
wo.w->get()->get_mining_history(mh);
|
||||
return API_RETURN_CODE_OK;
|
||||
}
|
||||
std::string wallets_manager::get_wallet_restore_info(uint64_t wallet_id, std::string& restore_key)
|
||||
std::string wallets_manager::get_wallet_restore_info(uint64_t wallet_id, std::string& seed_phrase, const std::string& seed_password)
|
||||
{
|
||||
GET_WALLET_OPT_BY_ID(wallet_id, wo);
|
||||
|
||||
if (wo.wallet_state != view::wallet_status_info::wallet_state_ready || wo.long_refresh_in_progress)
|
||||
return API_RETURN_CODE_CORE_BUSY;
|
||||
|
||||
restore_key = wo.w->get()->get_account().get_seed_phrase();
|
||||
seed_phrase = wo.w->get()->get_account().get_seed_phrase(seed_password);
|
||||
|
||||
return API_RETURN_CODE_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ public:
|
|||
bool get_opened_wallets(std::list<view::open_wallet_response>& result);
|
||||
std::string open_wallet(const std::wstring& path, const std::string& password, uint64_t txs_to_return, view::open_wallet_response& owr, bool exclude_mining_txs = false);
|
||||
std::string generate_wallet(const std::wstring& path, const std::string& password, view::open_wallet_response& owr);
|
||||
std::string restore_wallet(const std::wstring& path, const std::string& password, const std::string& restore_key, view::open_wallet_response& owr);
|
||||
std::string restore_wallet(const std::wstring& path, const std::string& password, const std::string& seed_phrase, const std::string& seed_password, view::open_wallet_response& owr);
|
||||
std::string invoke(uint64_t wallet_id, std::string params);
|
||||
std::string get_wallet_status(uint64_t wallet_id);
|
||||
std::string run_wallet(uint64_t wallet_id);
|
||||
|
|
@ -132,7 +132,7 @@ public:
|
|||
std::string stop_pos_mining(uint64_t wallet_id);
|
||||
std::string check_available_sources(uint64_t wallet_id, std::list<uint64_t>& amounts);
|
||||
std::string get_mining_history(uint64_t wallet_id, tools::wallet_public::mining_history& wrpc);
|
||||
std::string get_wallet_restore_info(uint64_t wallet_id, std::string& restore_key);
|
||||
std::string get_wallet_restore_info(uint64_t wallet_id, std::string& seed_phrase, const std::string& seed_password);
|
||||
std::string backup_wallet(uint64_t wallet_id, const std::wstring& path);
|
||||
std::string reset_wallet_password(uint64_t wallet_id, const std::string& pass);
|
||||
std::string is_wallet_password_valid(uint64_t wallet_id, const std::string& pass);
|
||||
|
|
@ -149,7 +149,8 @@ public:
|
|||
void toggle_pos_mining();
|
||||
std::string transfer(size_t wallet_id, const view::transfer_params& tp, currency::transaction& res_tx);
|
||||
std::string get_config_folder();
|
||||
std::string is_valid_brain_restore_data(const std::string& seed_phrase);
|
||||
std::string is_valid_brain_restore_data(const std::string& seed_phrase, const std::string& seed_password);
|
||||
std::string get_seed_phrase_info(const std::string& seed_phrase, const std::string& seed_password, view::seed_phrase_info& result);
|
||||
#ifndef MOBILE_WALLET_BUILD
|
||||
void subscribe_to_core_events(currency::i_core_event_handler* pevents_handler);
|
||||
//void unsubscribe_to_core_events();
|
||||
|
|
|
|||
|
|
@ -612,7 +612,7 @@ gen_no_attchments_in_coinbase::gen_no_attchments_in_coinbase()
|
|||
// NOTE: This test is made deterministic to be able to correctly set up checkpoint.
|
||||
random_state_test_restorer::reset_random(); // random generator's state was previously stored, will be restore on dtor (see also m_random_state_test_restorer)
|
||||
|
||||
bool r = m_miner_acc.restore_from_seed_phrase("battle harsh arrow gain best doubt nose raw protect salty apart tell distant final yeah stubborn true stop shoulder breathe throne problem everyone stranger only");
|
||||
bool r = m_miner_acc.restore_from_seed_phrase("battle harsh arrow gain best doubt nose raw protect salty apart tell distant final yeah stubborn true stop shoulder breathe throne problem everyone stranger only", "");
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "gen_no_attchments_in_coinbase: Can't restore account from seed phrase");
|
||||
|
||||
REGISTER_CALLBACK_METHOD(gen_no_attchments_in_coinbase, c1);
|
||||
|
|
|
|||
|
|
@ -1042,7 +1042,7 @@ bool hard_fork_2_awo_wallets_basic_test<before_hf_2>::c1(currency::core& c, size
|
|||
|
||||
boost::filesystem::remove(bob_wo_restored_filename, ec);
|
||||
|
||||
bob_wlt_awo_restored->restore(bob_wo_restored_filename, "", bob_tracking_seed, true);
|
||||
bob_wlt_awo_restored->restore(bob_wo_restored_filename, "", bob_tracking_seed, true, "");
|
||||
bob_wlt_awo_restored->set_core_runtime_config(c.get_blockchain_storage().get_core_runtime_config());
|
||||
bob_wlt_awo_restored->set_core_proxy(m_core_proxy);
|
||||
|
||||
|
|
@ -1073,14 +1073,14 @@ bool hard_fork_2_awo_wallets_basic_test<before_hf_2>::c1(currency::core& c, size
|
|||
// Restore Bob wallet as non-auditable and spend mix_attr!=1 output => make sure other auditable Bob's wallets remain intact
|
||||
//
|
||||
|
||||
std::string bob_seed = bob_wlt->get_account().get_seed_phrase();
|
||||
std::string bob_seed = bob_wlt->get_account().get_seed_phrase("");
|
||||
bob_seed.erase(bob_seed.find_last_of(" ")); // remove the last word (with flags and checksum) to make seed old-format 25-words non-auditable with the same keys
|
||||
|
||||
std::shared_ptr<tools::wallet2> bob_wlt_non_auditable = std::make_shared<tools::wallet2>();
|
||||
|
||||
boost::filesystem::remove(bob_non_auditable_filename, ec);
|
||||
|
||||
bob_wlt_non_auditable->restore(bob_non_auditable_filename, "", bob_seed, false);
|
||||
bob_wlt_non_auditable->restore(bob_non_auditable_filename, "", bob_seed, false, "");
|
||||
bob_wlt_non_auditable->set_core_runtime_config(c.get_blockchain_storage().get_core_runtime_config());
|
||||
bob_wlt_non_auditable->set_core_proxy(m_core_proxy);
|
||||
|
||||
|
|
|
|||
803
tests/unit_tests/crypto_tests.cpp
Normal file
|
|
@ -0,0 +1,803 @@
|
|||
// Copyright (c) 2020 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#define USE_INSECURE_RANDOM_RPNG_ROUTINES // turns on random manupulation for tests
|
||||
#include "gtest/gtest.h"
|
||||
#include "crypto/crypto.h"
|
||||
|
||||
extern "C" {
|
||||
#include "crypto/crypto-ops.h"
|
||||
void fe_reduce(fe u, const fe h)
|
||||
{
|
||||
/* From fe_frombytes.c */
|
||||
|
||||
// loading changed
|
||||
|
||||
int64_t h0 = h[0];
|
||||
int64_t h1 = h[1];
|
||||
int64_t h2 = h[2];
|
||||
int64_t h3 = h[3];
|
||||
int64_t h4 = h[4];
|
||||
int64_t h5 = h[5];
|
||||
int64_t h6 = h[6];
|
||||
int64_t h7 = h[7];
|
||||
int64_t h8 = h[8];
|
||||
int64_t h9 = h[9];
|
||||
int64_t carry0;
|
||||
int64_t carry1;
|
||||
int64_t carry2;
|
||||
int64_t carry3;
|
||||
int64_t carry4;
|
||||
int64_t carry5;
|
||||
int64_t carry6;
|
||||
int64_t carry7;
|
||||
int64_t carry8;
|
||||
int64_t carry9;
|
||||
|
||||
carry9 = (h9 + (int64_t)(1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
|
||||
carry1 = (h1 + (int64_t)(1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
|
||||
carry3 = (h3 + (int64_t)(1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
|
||||
carry5 = (h5 + (int64_t)(1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
|
||||
carry7 = (h7 + (int64_t)(1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
|
||||
|
||||
carry0 = (h0 + (int64_t)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
|
||||
carry2 = (h2 + (int64_t)(1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
|
||||
carry4 = (h4 + (int64_t)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
|
||||
carry6 = (h6 + (int64_t)(1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
|
||||
carry8 = (h8 + (int64_t)(1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
|
||||
|
||||
u[0] = h0;
|
||||
u[1] = h1;
|
||||
u[2] = h2;
|
||||
u[3] = h3;
|
||||
u[4] = h4;
|
||||
u[5] = h5;
|
||||
u[6] = h6;
|
||||
u[7] = h7;
|
||||
u[8] = h8;
|
||||
u[9] = h9;
|
||||
|
||||
/* End fe_frombytes.c */
|
||||
|
||||
}
|
||||
|
||||
|
||||
void sc_mul(unsigned char *s, const unsigned char *a, const unsigned char *b)
|
||||
{
|
||||
unsigned char c[32];
|
||||
unsigned char neg_a[32];
|
||||
sc_0(c);
|
||||
sc_sub(neg_a, c, a);
|
||||
// s = c - ab
|
||||
sc_mulsub(s, neg_a, b, c);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
|
||||
unsigned char Lm2[32] = { 0xeb, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10 };
|
||||
|
||||
// out = z ^ s (mod l)
|
||||
void sc_exp(unsigned char* out, const unsigned char* z, const unsigned char* s)
|
||||
{
|
||||
sc_0(out);
|
||||
out[0] = 1;
|
||||
if (sc_isnonzero(s) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// calc position of the most significant bit of s
|
||||
size_t msb_s = 0;
|
||||
for (size_t i = 31; i != SIZE_MAX; --i)
|
||||
{
|
||||
if (s[i] != 0)
|
||||
{
|
||||
msb_s = 8 * i;
|
||||
uint8_t t = s[i] >> 1;
|
||||
while (t)
|
||||
{
|
||||
t >>= 1;
|
||||
++msb_s;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//memcpy(out, z, sizeof(crypto::ec_scalar));
|
||||
|
||||
for (size_t i = msb_s; i != SIZE_MAX; --i)
|
||||
{
|
||||
sc_mul(out, out, out);
|
||||
std::cout << "sc_mul(out, out, out);" << std::endl;
|
||||
uint8_t bit = (s[i / 8] >> (i % 8)) & 1;
|
||||
if (bit)
|
||||
{
|
||||
sc_mul(out, out, z);
|
||||
std::cout << "sc_mul(out, out, z);" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sc_invert(unsigned char* out, const unsigned char* z)
|
||||
{
|
||||
memcpy(out, z, sizeof(crypto::ec_scalar));
|
||||
for(size_t i = 0; i < 128; ++i)
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
sc_mul(out, out, out);
|
||||
sc_mul(out, out, z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<class pod_t>
|
||||
std::string pod_to_hex_big_endian(const pod_t &h)
|
||||
{
|
||||
constexpr char hexmap[] = "0123456789abcdef";
|
||||
const char* data = reinterpret_cast<const char*>(&h);
|
||||
size_t len = sizeof h;
|
||||
|
||||
std::string s(len * 2, ' ');
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
s[2 * i] = hexmap[(data[len - 1 - i] & 0xF0) >> 4];
|
||||
s[2 * i + 1] = hexmap[(data[len - 1 - i] & 0x0F)];
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
int fe_cmp(const fe a, const fe b)
|
||||
{
|
||||
for (size_t i = 9; i != SIZE_MAX; --i)
|
||||
{
|
||||
if (reinterpret_cast<const uint32_t&>(a[i]) < reinterpret_cast<const uint32_t&>(b[i])) return -1;
|
||||
if (reinterpret_cast<const uint32_t&>(a[i]) > reinterpret_cast<const uint32_t&>(b[i])) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const fe scalar_L_fe = { 16110573, 10012311, -6632702, 16062397, 5471207, 0, 0, 0, 0, 4194304 };
|
||||
|
||||
|
||||
__declspec(align(32))
|
||||
struct scalar_t
|
||||
{
|
||||
//fe m_fe; // 40 bytes, array 10 * 4, optimized form
|
||||
union
|
||||
{
|
||||
uint64_t m_u64[4];
|
||||
unsigned char m_s[32];
|
||||
};
|
||||
// DONE! consider 1) change to aligned array of unsigned chars
|
||||
// consider 2) add 32 byte after to speed up sc_reduce by decreasing num of copy operations
|
||||
|
||||
scalar_t()
|
||||
{}
|
||||
|
||||
scalar_t(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3)
|
||||
{
|
||||
m_u64[0] = a0;
|
||||
m_u64[1] = a1;
|
||||
m_u64[2] = a2;
|
||||
m_u64[3] = a3;
|
||||
}
|
||||
|
||||
scalar_t(int64_t v)
|
||||
{
|
||||
zero();
|
||||
if (v == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//unsigned char bytes[32] = {0};
|
||||
reinterpret_cast<int64_t&>(m_s) = v;
|
||||
//fe_frombytes(m_fe, bytes);
|
||||
// do not need to call reduce as 2^64 < L
|
||||
}
|
||||
|
||||
unsigned char* data()
|
||||
{
|
||||
return &m_s[0];
|
||||
}
|
||||
|
||||
const unsigned char* data() const
|
||||
{
|
||||
return &m_s[0];
|
||||
}
|
||||
|
||||
operator crypto::secret_key() const
|
||||
{
|
||||
crypto::secret_key result;
|
||||
memcpy(result.data, &m_s, sizeof result.data);
|
||||
//fe_tobytes(reinterpret_cast<unsigned char*>(&result), m_fe);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool from_secret_key(const crypto::secret_key& sk)
|
||||
{
|
||||
//fe_frombytes(m_fe, reinterpret_cast<const unsigned char*>(&sk));
|
||||
return false;
|
||||
}
|
||||
|
||||
void zero()
|
||||
{
|
||||
//fe_0(m_fe);
|
||||
m_u64[0] = 0;
|
||||
m_u64[1] = 0;
|
||||
m_u64[2] = 0;
|
||||
m_u64[3] = 0;
|
||||
//memset(&m_s, 0, sizeof m_s);
|
||||
}
|
||||
|
||||
void make_random()
|
||||
{
|
||||
unsigned char tmp[64];
|
||||
crypto::generate_random_bytes(64, tmp);
|
||||
sc_reduce(tmp);
|
||||
memcpy(&m_s, tmp, 32);
|
||||
}
|
||||
|
||||
bool is_zero() const
|
||||
{
|
||||
return sc_isnonzero(&m_s[0]) == 0;
|
||||
}
|
||||
|
||||
scalar_t operator+(const scalar_t& v) const
|
||||
{
|
||||
scalar_t result;
|
||||
sc_add(reinterpret_cast<unsigned char*>(&result), reinterpret_cast<const unsigned char*>(&m_s), reinterpret_cast<const unsigned char*>(&v));
|
||||
return result;
|
||||
}
|
||||
|
||||
scalar_t operator-(const scalar_t& v) const
|
||||
{
|
||||
scalar_t result;
|
||||
sc_sub(reinterpret_cast<unsigned char*>(&result), reinterpret_cast<const unsigned char*>(&m_s), reinterpret_cast<const unsigned char*>(&v));
|
||||
return result;
|
||||
}
|
||||
|
||||
scalar_t operator*(const scalar_t& v) const
|
||||
{
|
||||
scalar_t result;
|
||||
sc_mul(reinterpret_cast<unsigned char*>(&result), reinterpret_cast<const unsigned char*>(&m_s), reinterpret_cast<const unsigned char*>(&v));
|
||||
return result;
|
||||
}
|
||||
|
||||
scalar_t reciprocal() const
|
||||
{
|
||||
/*unsigned char bytes[32] = {2};
|
||||
fe t;
|
||||
fe_frombytes(t, (unsigned char*)&bytes);
|
||||
fe r;
|
||||
fe_invert(r, t);
|
||||
fe m;
|
||||
fe_mul(m, r, t);
|
||||
|
||||
|
||||
fe r2;
|
||||
my_fe_invert(r2, t);
|
||||
fe m2;
|
||||
fe_mul(m2, r2, t);
|
||||
|
||||
scalar_t result;
|
||||
fe v_f;
|
||||
fe result_f;
|
||||
fe_frombytes(v_f, reinterpret_cast<const unsigned char*>(&m_s));
|
||||
my_fe_invert(result_f, v_f);
|
||||
fe_tobytes(reinterpret_cast<unsigned char*>(&result), result_f);
|
||||
//sc_reduce(reinterpret_cast<unsigned char*>(&result));
|
||||
fe result_check;
|
||||
fe_frombytes(result_check, reinterpret_cast<unsigned char*>(&result));
|
||||
fe v_check;
|
||||
fe_invert(v_check, result_check);
|
||||
//sc_reduce(reinterpret_cast<unsigned char*>(&result));
|
||||
return result;*/
|
||||
|
||||
scalar_t result;
|
||||
fe v_f;
|
||||
fe result_f;
|
||||
fe_frombytes(v_f, reinterpret_cast<const unsigned char*>(&m_s));
|
||||
fe_invert(result_f, v_f);
|
||||
|
||||
/*fe x2;
|
||||
fe_mul(x2, result_f, v_f);
|
||||
|
||||
fe_reduce(result_f, result_f);
|
||||
if (fe_cmp(result_f, scalar_L_fe) > 0)
|
||||
{
|
||||
// result_f > L
|
||||
fe_sub(result_f, result_f, scalar_L_fe);
|
||||
if (fe_cmp(result_f, scalar_L_fe) >= 0)
|
||||
return false; // fail
|
||||
}*/
|
||||
unsigned char tmp[64] = { 0 };
|
||||
fe_tobytes(reinterpret_cast<unsigned char*>(&tmp), result_f);
|
||||
sc_reduce(tmp);
|
||||
memcpy(&result, &tmp, sizeof result);
|
||||
return result;
|
||||
}
|
||||
|
||||
scalar_t operator/(const scalar_t& v) const
|
||||
{
|
||||
return operator*(v.reciprocal());
|
||||
}
|
||||
|
||||
bool operator==(const scalar_t& rhs) const
|
||||
{
|
||||
return
|
||||
m_u64[0] == rhs.m_u64[0] &&
|
||||
m_u64[1] == rhs.m_u64[1] &&
|
||||
m_u64[2] == rhs.m_u64[2] &&
|
||||
m_u64[3] == rhs.m_u64[3];
|
||||
}
|
||||
|
||||
bool operator<(const scalar_t& rhs) const
|
||||
{
|
||||
if (m_u64[3] < rhs.m_u64[3]) return true;
|
||||
if (m_u64[3] > rhs.m_u64[3]) return false;
|
||||
if (m_u64[2] < rhs.m_u64[2]) return true;
|
||||
if (m_u64[2] > rhs.m_u64[2]) return false;
|
||||
if (m_u64[1] < rhs.m_u64[1]) return true;
|
||||
if (m_u64[1] > rhs.m_u64[1]) return false;
|
||||
if (m_u64[0] < rhs.m_u64[0]) return true;
|
||||
if (m_u64[0] > rhs.m_u64[0]) return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator>(const scalar_t& rhs) const
|
||||
{
|
||||
if (m_u64[3] < rhs.m_u64[3]) return false;
|
||||
if (m_u64[3] > rhs.m_u64[3]) return true;
|
||||
if (m_u64[2] < rhs.m_u64[2]) return false;
|
||||
if (m_u64[2] > rhs.m_u64[2]) return true;
|
||||
if (m_u64[1] < rhs.m_u64[1]) return false;
|
||||
if (m_u64[1] > rhs.m_u64[1]) return true;
|
||||
if (m_u64[0] < rhs.m_u64[0]) return false;
|
||||
if (m_u64[0] > rhs.m_u64[0]) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& ss, const scalar_t &v)
|
||||
{
|
||||
return ss << "0x" << pod_to_hex_big_endian(v);
|
||||
}
|
||||
|
||||
}; // struct scalar_t
|
||||
|
||||
//__declspec(align(32))
|
||||
struct point_t
|
||||
{
|
||||
// A point(x, y) is represented in extended homogeneous coordinates (X, Y, Z, T)
|
||||
// with x = X / Z, y = Y / Z, x * y = T / Z.
|
||||
ge_p3 m_p3;
|
||||
|
||||
point_t()
|
||||
{
|
||||
}
|
||||
|
||||
void zero()
|
||||
{
|
||||
ge_p3_0(&m_p3);
|
||||
}
|
||||
|
||||
bool from_public_key(const crypto::public_key& pk)
|
||||
{
|
||||
return ge_frombytes_vartime(&m_p3, reinterpret_cast<const unsigned char*>(&pk)) == 0;
|
||||
}
|
||||
|
||||
operator crypto::public_key()
|
||||
{
|
||||
crypto::public_key result;
|
||||
ge_p3_tobytes((unsigned char*)&result, &m_p3);
|
||||
return result;
|
||||
}
|
||||
|
||||
point_t operator+(const point_t& rhs)
|
||||
{
|
||||
point_t result;
|
||||
ge_cached rhs_c;
|
||||
ge_p1p1 t;
|
||||
ge_p3_to_cached(&rhs_c, &rhs.m_p3);
|
||||
ge_add(&t, &m_p3, &rhs_c);
|
||||
ge_p1p1_to_p3(&result.m_p3, &t);
|
||||
return result;
|
||||
}
|
||||
|
||||
point_t operator-(const point_t& rhs)
|
||||
{
|
||||
point_t result;
|
||||
ge_cached rhs_c;
|
||||
ge_p1p1 t;
|
||||
ge_p3_to_cached(&rhs_c, &rhs.m_p3);
|
||||
ge_sub(&t, &m_p3, &rhs_c);
|
||||
ge_p1p1_to_p3(&result.m_p3, &t);
|
||||
return result;
|
||||
}
|
||||
|
||||
friend point_t operator*(const scalar_t& lhs, const point_t& rhs)
|
||||
{
|
||||
point_t result;
|
||||
ge_scalarmult_p3(&result.m_p3, reinterpret_cast<const unsigned char*>(&lhs), &rhs.m_p3);
|
||||
return result;
|
||||
}
|
||||
|
||||
friend bool operator==(const point_t& lhs, const point_t& rhs)
|
||||
{
|
||||
// convert to xy form, then compare components (because (z, y, z, t) representation is not unique)
|
||||
fe lrecip, lx, ly;
|
||||
fe rrecip, rx, ry;
|
||||
|
||||
fe_invert(lrecip, lhs.m_p3.Z);
|
||||
fe_invert(rrecip, rhs.m_p3.Z);
|
||||
|
||||
fe_mul(lx, lhs.m_p3.X, lrecip);
|
||||
fe_mul(rx, rhs.m_p3.X, rrecip);
|
||||
if (memcmp(&lx, &rx, sizeof lx) != 0)
|
||||
return false;
|
||||
|
||||
fe_mul(ly, lhs.m_p3.Y, lrecip);
|
||||
fe_mul(ry, rhs.m_p3.Y, rrecip);
|
||||
if (memcmp(&ly, &ry, sizeof ly) != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
}; // struct point_t
|
||||
|
||||
struct point_g_t : public point_t
|
||||
{
|
||||
point_g_t()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
friend point_t operator*(const scalar_t& lhs, const point_g_t&)
|
||||
{
|
||||
point_t result;
|
||||
ge_scalarmult_base(&result.m_p3, reinterpret_cast<const unsigned char*>(&lhs));
|
||||
return result;
|
||||
}
|
||||
|
||||
/*friend point_t operator*(const int64_t lhs, const point_g_t& rhs)
|
||||
{
|
||||
return operator*(scalar_t)
|
||||
}*/
|
||||
|
||||
static_assert(sizeof(crypto::public_key) == 32, "size error");
|
||||
|
||||
}; // struct point_g_t
|
||||
|
||||
static const point_g_t point_G;
|
||||
|
||||
static const scalar_t scalar_L = { 0x5812631a5cf5d3ed, 0x14def9dea2f79cd6, 0x0, 0x1000000000000000 };
|
||||
static const scalar_t scalar_Lm1 = { 0x5812631a5cf5d3ec, 0x14def9dea2f79cd6, 0x0, 0x1000000000000000 };
|
||||
static const scalar_t scalar_P = { 0xffffffffffffffed, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff };
|
||||
static const scalar_t scalar_Pm1 = { 0xffffffffffffffec, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff };
|
||||
static const scalar_t scalar_256m1 = { 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff };
|
||||
|
||||
|
||||
/* temporary disable in order not to break the compilation
|
||||
TEST(crypto, scalar_basics)
|
||||
{
|
||||
scalar_t zero = 0;
|
||||
ASSERT_TRUE(zero.is_zero());
|
||||
scalar_t one = 1;
|
||||
ASSERT_FALSE(one.is_zero());
|
||||
ASSERT_TRUE(one > zero);
|
||||
scalar_t z = 0;
|
||||
for (size_t j = 0; j < 1000; ++j)
|
||||
{
|
||||
z.make_random();
|
||||
ASSERT_FALSE(z.is_zero());
|
||||
ASSERT_GT(z, z - 1);
|
||||
ASSERT_LT(z, z + 1);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(scalar_L > 0 && !(scalar_L < 0));
|
||||
ASSERT_TRUE(scalar_Lm1 > 0 && !(scalar_Lm1 < 0));
|
||||
ASSERT_TRUE(scalar_Lm1 < scalar_L);
|
||||
ASSERT_FALSE(scalar_Lm1 > scalar_L);
|
||||
ASSERT_TRUE(scalar_P > scalar_Pm1);
|
||||
ASSERT_FALSE(scalar_P < scalar_Pm1);
|
||||
|
||||
std::cout << "0 = " << zero << std::endl;
|
||||
std::cout << "1 = " << one << std::endl;
|
||||
std::cout << "L = " << scalar_L << std::endl;
|
||||
std::cout << "Lm1 = " << scalar_Lm1 << std::endl;
|
||||
std::cout << "P = " << scalar_P << std::endl;
|
||||
std::cout << "Pm1 = " << scalar_Pm1 << std::endl;
|
||||
|
||||
// check rolling over L for scalars arithmetics
|
||||
ASSERT_EQ(scalar_Lm1 + 1, 0);
|
||||
ASSERT_EQ(scalar_t(0) - 1, scalar_Lm1);
|
||||
ASSERT_EQ(scalar_Lm1 * 2, scalar_Lm1 - 1); // (L - 1) * 2 = L + L - 2 = (L - 1) - 1 (mod L)
|
||||
ASSERT_EQ(scalar_Lm1 * 100, scalar_Lm1 - 99);
|
||||
ASSERT_EQ(scalar_Lm1 * scalar_Lm1, 1); // (L - 1) * (L - 1) = L*L - 2L + 1 = 1 (mod L)
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
|
||||
|
||||
fe L_fe;
|
||||
fe_frombytes(L_fe, &scalar_L.m_s[0]);
|
||||
|
||||
fe Pm1_fe;
|
||||
fe_frombytes(Pm1_fe, &scalar_Pm1.m_s[0]);
|
||||
|
||||
fe r;
|
||||
fe f_1 = { 1 };
|
||||
fe_add(r, Pm1_fe, f_1);
|
||||
|
||||
|
||||
|
||||
while(true)
|
||||
{
|
||||
static int ti = 2;
|
||||
static int pi = 3;
|
||||
scalar_t t = ti;
|
||||
scalar_t p = pi;
|
||||
scalar_t r = 0;
|
||||
//sc_exp(r.data(), t.data(), Lm2);
|
||||
|
||||
sc_invert(r.data(), t.data());
|
||||
|
||||
std::cout << ti << " ^ L-2" << " = " << r << std::endl;
|
||||
|
||||
r = r * 6;
|
||||
std::cout << r << std::endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
scalar_t a = 2;
|
||||
a = a / 2;
|
||||
std::cout << "2 / 2 = " << a << std::endl;
|
||||
a = scalar_Lm1 / 2;
|
||||
std::cout << "L-1 / 2 = " << a << std::endl;
|
||||
a = a * 2;
|
||||
std::cout << "L-1 / 2 * 2 = " << a << std::endl;
|
||||
|
||||
}
|
||||
|
||||
TEST(crypto, point_basics)
|
||||
{
|
||||
scalar_t s = 4;
|
||||
point_t E = s * point_G;
|
||||
point_t X = 4 * E;
|
||||
point_t K = 193847 * point_G;
|
||||
point_t C = E + K;
|
||||
|
||||
ASSERT_TRUE(X == 16 * point_G);
|
||||
ASSERT_TRUE(C - K == E);
|
||||
ASSERT_TRUE(C - E == K);
|
||||
ASSERT_TRUE(C == 193851 * point_G);
|
||||
}
|
||||
|
||||
TEST(crypto, scalar_reciprocal)
|
||||
{
|
||||
int64_t test_nums[] = {1, 2, 10};
|
||||
|
||||
for (size_t i = 0; i < sizeof test_nums / sizeof test_nums[0]; ++i)
|
||||
{
|
||||
scalar_t s = test_nums[i];
|
||||
scalar_t z = s - s;
|
||||
ASSERT_TRUE(z.is_zero());
|
||||
}
|
||||
|
||||
scalar_t s = 20;
|
||||
scalar_t d = 5;
|
||||
scalar_t e = s / d;
|
||||
scalar_t m = e * d;
|
||||
|
||||
ASSERT_TRUE(m == s);
|
||||
}
|
||||
|
||||
|
||||
TEST(crypto, scalars)
|
||||
{
|
||||
scalar_t s = 20;
|
||||
scalar_t d = 5;
|
||||
scalar_t e = s / d;
|
||||
scalar_t m = e * d;
|
||||
|
||||
ASSERT_TRUE(m == s);
|
||||
}
|
||||
|
||||
*/
|
||||
|
|
@ -842,7 +842,7 @@ namespace db_test
|
|||
ptr = db_array[4];
|
||||
ASSERT_EQ(ptr->v, "X");
|
||||
|
||||
ASSERT_TRUE(db_array.clear());
|
||||
ASSERT_TRUE((db_array.clear()? true: false));
|
||||
|
||||
db_array.commit_transaction();
|
||||
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ TEST(wallet_seed, store_restore_test)
|
|||
{
|
||||
currency::account_base acc;
|
||||
acc.generate();
|
||||
auto seed_phrase = acc.get_seed_phrase();
|
||||
auto seed_phrase = acc.get_seed_phrase("");
|
||||
|
||||
currency::account_base acc2;
|
||||
bool r = acc2.restore_from_seed_phrase(seed_phrase);
|
||||
bool r = acc2.restore_from_seed_phrase(seed_phrase, "");
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
if (memcmp(&acc2.get_keys(), &acc.get_keys(), sizeof(currency::account_keys)))
|
||||
|
|
@ -29,10 +29,10 @@ TEST(wallet_seed, store_restore_test)
|
|||
{
|
||||
currency::account_base acc;
|
||||
acc.generate();
|
||||
auto seed_phrase = acc.get_seed_phrase();
|
||||
auto seed_phrase = acc.get_seed_phrase("");
|
||||
|
||||
currency::account_base acc2;
|
||||
bool r = acc2.restore_from_seed_phrase(seed_phrase);
|
||||
bool r = acc2.restore_from_seed_phrase(seed_phrase, "");
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
if (memcmp(&acc2.get_keys(), &acc.get_keys(), sizeof(currency::account_keys)))
|
||||
|
|
@ -57,7 +57,7 @@ wallet_seed_entry wallet_seed_entries[] =
|
|||
{
|
||||
{
|
||||
// legacy 24-word seed phrase -- invalid
|
||||
"dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew",
|
||||
"dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew god",
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
|
|
@ -66,7 +66,7 @@ wallet_seed_entry wallet_seed_entries[] =
|
|||
},
|
||||
{
|
||||
// old-style 25-word seed phrase -- valid
|
||||
"dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew",
|
||||
"dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew god",
|
||||
"5e051454d7226b5734ebd64f754b57db4c655ecda00bd324f1b241d0b6381c0f",
|
||||
"7dde5590fdf430568c00556ac2accf09da6cde9a29a4bc7d1cb6fd267130f006",
|
||||
0,
|
||||
|
|
@ -148,7 +148,41 @@ TEST(wallet_seed, basic_test)
|
|||
bool r = false;
|
||||
try
|
||||
{
|
||||
r = acc.restore_from_seed_phrase(wse.seed_phrase);
|
||||
r = acc.restore_from_seed_phrase(wse.seed_phrase, "");
|
||||
if (r)
|
||||
{
|
||||
for (size_t j = 0; j != 100; j++)
|
||||
{
|
||||
//generate random password
|
||||
std::string pass = epee::string_tools::pod_to_hex(crypto::cn_fast_hash(&j, sizeof(j)));
|
||||
if (j!= 0 && j < 64)
|
||||
{
|
||||
pass.resize(j);
|
||||
}
|
||||
//get secured seed
|
||||
std::string secured_seed = acc.get_seed_phrase(pass);
|
||||
|
||||
//try to restore it without password(should fail)
|
||||
currency::account_base acc2;
|
||||
bool r_fail = acc2.restore_from_seed_phrase(secured_seed, "");
|
||||
ASSERT_EQ(r_fail, false);
|
||||
|
||||
//try to restore it with wrong password
|
||||
bool r_fake_pass = acc2.restore_from_seed_phrase(secured_seed, "fake_password");
|
||||
if (r_fake_pass)
|
||||
{
|
||||
//accidentally checksumm matched(quite possible)
|
||||
ASSERT_EQ(false, acc2.get_keys() == acc.get_keys());
|
||||
}
|
||||
|
||||
//try to restore it from right password
|
||||
currency::account_base acc3;
|
||||
bool r_true_res = acc3.restore_from_seed_phrase(secured_seed, pass);
|
||||
ASSERT_EQ(true, r_true_res);
|
||||
ASSERT_EQ(true, acc3.get_keys() == acc.get_keys());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
|
|
|||