updated std ops
This commit is contained in:
parent
cca538ddf5
commit
2e753968b8
@ -850,6 +850,7 @@ ol li::before {
|
|||||||
|
|
||||||
.password-field label {
|
.password-field label {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.password-field label input:checked ~ .visible {
|
.password-field label input:checked ~ .visible {
|
||||||
display: none;
|
display: none;
|
||||||
@ -1781,6 +1782,6 @@ ol li::before {
|
|||||||
overflow: overlay;
|
overflow: overlay;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.hide {
|
.hidden {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -783,6 +783,7 @@ ol {
|
|||||||
.password-field {
|
.password-field {
|
||||||
label {
|
label {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
input:checked ~ .visible {
|
input:checked ~ .visible {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@ -1672,6 +1673,6 @@ ol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.hide {
|
.hidden {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|||||||
107
index.html
107
index.html
@ -27,7 +27,7 @@
|
|||||||
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous" defer></script>
|
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous" defer></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body onload="onLoadStartUp()" class="hide">
|
<body onload="onLoadStartUp()" class="hidden">
|
||||||
<sm-notifications id="notification_drawer"></sm-notifications>
|
<sm-notifications id="notification_drawer"></sm-notifications>
|
||||||
<sm-popup id="confirmation_popup">
|
<sm-popup id="confirmation_popup">
|
||||||
<h4 id="confirm_title"></h4>
|
<h4 id="confirm_title"></h4>
|
||||||
@ -48,7 +48,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</sm-form>
|
</sm-form>
|
||||||
</sm-popup>
|
</sm-popup>
|
||||||
<div id="secondary_pages" class="page hide">
|
<div id="secondary_pages" class="page hidden">
|
||||||
<header class="flex align-center gap-1">
|
<header class="flex align-center gap-1">
|
||||||
<div class="flex align-center flex-1">
|
<div class="flex align-center flex-1">
|
||||||
<svg class="icon flo-icon" width="64" height="64" viewBox="0 0 64 64" fill="none"
|
<svg class="icon flo-icon" width="64" height="64" viewBox="0 0 64 64" fill="none"
|
||||||
@ -68,7 +68,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<theme-toggle></theme-toggle>
|
<theme-toggle></theme-toggle>
|
||||||
</header>
|
</header>
|
||||||
<article id="landing" class="inner-page hide">
|
<article id="landing" class="inner-page hidden">
|
||||||
<section class="grid justify-center gap-1">
|
<section class="grid justify-center gap-1">
|
||||||
<h1 class="h1">Send.request</h1>
|
<h1 class="h1">Send.request</h1>
|
||||||
<div class="flex gap-0-5">
|
<div class="flex gap-0-5">
|
||||||
@ -77,7 +77,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</article>
|
||||||
<article id="sign_in" class="inner-page hide">
|
<article id="sign_in" class="inner-page hidden">
|
||||||
<svg class="illustration" width="673" height="417" viewBox="0 0 673 417" fill="none"
|
<svg class="illustration" width="673" height="417" viewBox="0 0 673 417" fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
<g clip-path="url(#clip0_2_41)">
|
<g clip-path="url(#clip0_2_41)">
|
||||||
@ -161,7 +161,26 @@
|
|||||||
<p>Welcome back, glad to see you again</p>
|
<p>Welcome back, glad to see you again</p>
|
||||||
<sm-form id="sign_in_form">
|
<sm-form id="sign_in_form">
|
||||||
<sm-input id="private_key_field" type="password" placeholder="FLO private key"
|
<sm-input id="private_key_field" type="password" placeholder="FLO private key"
|
||||||
error-text="Private key is invalid" data-private-key required></sm-input>
|
class="password-field" error-text="Private key is invalid" data-private-key required>
|
||||||
|
<label slot="right" class="interact">
|
||||||
|
<input type="checkbox" class="hidden" autocomplete="off" readonly
|
||||||
|
onchange="togglePrivateKeyVisibility(this)">
|
||||||
|
<svg class="icon invisible" xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||||
|
viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
|
<title>Hide password</title>
|
||||||
|
<path d="M0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0z" fill="none" />
|
||||||
|
<path
|
||||||
|
d="M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z" />
|
||||||
|
</svg>
|
||||||
|
<svg class="icon visible" xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||||
|
viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
|
<title>Show password</title>
|
||||||
|
<path d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path
|
||||||
|
d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z" />
|
||||||
|
</svg>
|
||||||
|
</label>
|
||||||
|
</sm-input>
|
||||||
<sm-button id="sign_in_button" variant="primary" disabled>Sign In</sm-button>
|
<sm-button id="sign_in_button" variant="primary" disabled>Sign In</sm-button>
|
||||||
</sm-form>
|
</sm-form>
|
||||||
<p>
|
<p>
|
||||||
@ -169,7 +188,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</article>
|
||||||
<article id="sign_up" class="inner-page hide">
|
<article id="sign_up" class="inner-page hidden">
|
||||||
<section class="grid">
|
<section class="grid">
|
||||||
<div id="flo_id_warning" class="grid justify-center gap-0-5">
|
<div id="flo_id_warning" class="grid justify-center gap-0-5">
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
||||||
@ -203,7 +222,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="main_card" class="page hide">
|
<div id="main_card" class="page hidden">
|
||||||
<header id="main_header">
|
<header id="main_header">
|
||||||
<div class="flex align-center flex-1 app-name">
|
<div class="flex align-center flex-1 app-name">
|
||||||
<svg class="icon flo-icon" width="64" height="64" viewBox="0 0 64 64" fill="none"
|
<svg class="icon flo-icon" width="64" height="64" viewBox="0 0 64 64" fill="none"
|
||||||
@ -223,7 +242,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<theme-toggle style="margin-left: -1rem;"></theme-toggle>
|
<theme-toggle style="margin-left: -1rem;"></theme-toggle>
|
||||||
</header>
|
</header>
|
||||||
<section id="home" class="inner-page hide">
|
<section id="home" class="inner-page hidden">
|
||||||
<div id="wallet_section" class="grid gap-1 margin-bottom-2">
|
<div id="wallet_section" class="grid gap-1 margin-bottom-2">
|
||||||
<div class="flex align-center space-between">
|
<div class="flex align-center space-between">
|
||||||
<h4>My crypto holdings</h4>
|
<h4>My crypto holdings</h4>
|
||||||
@ -447,7 +466,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="hide">
|
<div class="hidden">
|
||||||
<h4 class="margin-bottom-1">Convert assets</h4>
|
<h4 class="margin-bottom-1">Convert assets</h4>
|
||||||
<div class="card user-element" style="width: min(26rem, 100%);">
|
<div class="card user-element" style="width: min(26rem, 100%);">
|
||||||
<sm-form>
|
<sm-form>
|
||||||
@ -527,7 +546,7 @@
|
|||||||
</sm-form>
|
</sm-form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<section id="cashier" class=" grid gap-1 hide admin-element">
|
<section id="cashier" class=" grid gap-1 hidden admin-element">
|
||||||
<div class="flex align-center space-between">
|
<div class="flex align-center space-between">
|
||||||
<h4>Requests</h4>
|
<h4>Requests</h4>
|
||||||
<strip-select id="cashier_requests_selector">
|
<strip-select id="cashier_requests_selector">
|
||||||
@ -542,7 +561,7 @@
|
|||||||
<p>No requests to process</p>
|
<p>No requests to process</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="hide">
|
<div class="hidden">
|
||||||
<ul id="cashier_processed_request_list" class="observe-empty-state"></ul>
|
<ul id="cashier_processed_request_list" class="observe-empty-state"></ul>
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<p>No requests to process</p>
|
<p>No requests to process</p>
|
||||||
@ -551,7 +570,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<section id="history" class="inner-page hide">
|
<section id="history" class="inner-page hidden">
|
||||||
<div class="flex sticky top-0" style="background-color: rgba(var(--background-color),1); z-index: 1;">
|
<div class="flex sticky top-0" style="background-color: rgba(var(--background-color),1); z-index: 1;">
|
||||||
<a href="#/home" class="button icon-only margin-right-0-5">
|
<a href="#/home" class="button icon-only margin-right-0-5">
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
||||||
@ -575,7 +594,7 @@
|
|||||||
Filters
|
Filters
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="history_applied_filters_wrapper" class="flex align-center hide gap-1">
|
<div id="history_applied_filters_wrapper" class="flex align-center hidden gap-1">
|
||||||
<h5>Applied filters</h5>
|
<h5>Applied filters</h5>
|
||||||
<div id="history_applied_filters" class="flex gap-0-5"></div>
|
<div id="history_applied_filters" class="flex gap-0-5"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -584,7 +603,7 @@
|
|||||||
<p>No transactions</p>
|
<p>No transactions</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section id="wallet" class="inner-page hide">
|
<section id="wallet" class="inner-page hidden">
|
||||||
<div class="flex sticky top-0" style="background-color: rgba(var(--background-color),1); z-index: 1;">
|
<div class="flex sticky top-0" style="background-color: rgba(var(--background-color),1); z-index: 1;">
|
||||||
<a href="#/home" class="button icon-only margin-right-0-5">
|
<a href="#/home" class="button icon-only margin-right-0-5">
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
||||||
@ -601,7 +620,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="wallet_history_wrapper" class="grid gap-1-5">
|
<div id="wallet_history_wrapper" class="grid gap-1-5">
|
||||||
<div class="hide grid gap-1">
|
<div class="hidden grid gap-1">
|
||||||
<h4>Pending</h4>
|
<h4>Pending</h4>
|
||||||
<ul id="pending_wallet_transactions" class="grid gap-0-5"></ul>
|
<ul id="pending_wallet_transactions" class="grid gap-0-5"></ul>
|
||||||
</div>
|
</div>
|
||||||
@ -614,7 +633,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section id="contacts" class="inner-page hide flex flex-direction-column">
|
<section id="contacts" class="inner-page hidden flex flex-direction-column">
|
||||||
<div class="page__header">
|
<div class="page__header">
|
||||||
<div class="grid gap-0-5 w-100">
|
<div class="grid gap-0-5 w-100">
|
||||||
<div class="flex align-center space-between">
|
<div class="flex align-center space-between">
|
||||||
@ -688,7 +707,7 @@
|
|||||||
<span>Tap on saved IDs to see transaction history</span>
|
<span>Tap on saved IDs to see transaction history</span>
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="contact" class="inner-page hide">
|
<section id="contact" class="inner-page hidden">
|
||||||
<div class="flex align-center">
|
<div class="flex align-center">
|
||||||
<a href="#/contacts" class="button icon-only margin-right-0-5">
|
<a href="#/contacts" class="button icon-only margin-right-0-5">
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
||||||
@ -708,7 +727,7 @@
|
|||||||
<button class="button" onclick="showTokenTransfer('send')">Pay</button>
|
<button class="button" onclick="showTokenTransfer('send')">Pay</button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section id="requests" class="inner-page hide">
|
<section id="requests" class="inner-page hidden">
|
||||||
<div class="page__header">
|
<div class="page__header">
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<h4>Payment</h4>
|
<h4>Payment</h4>
|
||||||
@ -716,7 +735,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="requests_history_wrapper" class="grid gap-1-5">
|
<div id="requests_history_wrapper" class="grid gap-1-5">
|
||||||
<div class="hide grid gap-1">
|
<div class="hidden grid gap-1">
|
||||||
<h4>Pending requests</h4>
|
<h4>Pending requests</h4>
|
||||||
<ul id="pending_payment_requests" class="grid gap-0-5"></ul>
|
<ul id="pending_payment_requests" class="grid gap-0-5"></ul>
|
||||||
</div>
|
</div>
|
||||||
@ -729,7 +748,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<div id="transaction" class="inner-page hide grid gap-2">
|
<div id="transaction" class="inner-page hidden grid gap-2">
|
||||||
<div class="grid gap-1 justify-start">
|
<div class="grid gap-1 justify-start">
|
||||||
<button class="button icon-only margin-right-0-5" onclick="history.back()">
|
<button class="button icon-only margin-right-0-5" onclick="history.back()">
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
||||||
@ -742,7 +761,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="transaction_details" class="grid gap-2"></div>
|
<div id="transaction_details" class="grid gap-2"></div>
|
||||||
</div>
|
</div>
|
||||||
<section id="settings" class="inner-page hide">
|
<section id="settings" class="inner-page hidden">
|
||||||
<div class="page__header">
|
<div class="page__header">
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<h1>Settings</h1>
|
<h1>Settings</h1>
|
||||||
@ -795,7 +814,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<nav id="main_navbar" class="hide nav-hidden">
|
<nav id="main_navbar" class="hidden nav-hidden">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<a href="#/home" class="nav-item interact">
|
<a href="#/home" class="nav-item interact">
|
||||||
@ -807,7 +826,7 @@
|
|||||||
<span class="nav-item__title">Home</span>
|
<span class="nav-item__title">Home</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="user-element hide">
|
<li class="user-element hidden">
|
||||||
<a href="#/contacts" class="nav-item interact" title='View payment requests'>
|
<a href="#/contacts" class="nav-item interact" title='View payment requests'>
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
||||||
width="24px" fill="#000000">
|
width="24px" fill="#000000">
|
||||||
@ -818,7 +837,7 @@
|
|||||||
<span class="nav-item__title">Contacts</span>
|
<span class="nav-item__title">Contacts</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="user-element hide">
|
<li class="user-element hidden">
|
||||||
<a id="requests_page_button" href="#/requests" class="nav-item interact"
|
<a id="requests_page_button" href="#/requests" class="nav-item interact"
|
||||||
title='View payment requests'>
|
title='View payment requests'>
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
||||||
@ -1062,11 +1081,11 @@
|
|||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</sm-input>
|
</sm-input>
|
||||||
<strong id="low_user_flo_warning" class="hide warning"></strong>
|
<strong id="low_user_flo_warning" class="hidden warning"></strong>
|
||||||
<button class="button button--primary cta" onclick="continueWalletTopup()"
|
<button class="button button--primary cta" onclick="continueWalletTopup()"
|
||||||
type="submit">Continue</button>
|
type="submit">Continue</button>
|
||||||
</sm-form>
|
</sm-form>
|
||||||
<sm-form id="confirm_topup_form" class="hide">
|
<sm-form id="confirm_topup_form" class="hidden">
|
||||||
<h4>Transfer money</h4>
|
<h4>Transfer money</h4>
|
||||||
<ol id="topup_steps" type="1">
|
<ol id="topup_steps" type="1">
|
||||||
<li>
|
<li>
|
||||||
@ -1109,7 +1128,7 @@
|
|||||||
type="submit">Confirm</button>
|
type="submit">Confirm</button>
|
||||||
</div>
|
</div>
|
||||||
</sm-form>
|
</sm-form>
|
||||||
<div class="grid gap-0-5 hide justify-center text-center">
|
<div class="grid gap-0-5 hidden justify-center text-center">
|
||||||
<svg class="icon user-action-result__icon success" xmlns="http://www.w3.org/2000/svg" height="24px"
|
<svg class="icon user-action-result__icon success" xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||||
viewBox="0 0 24 24" width="24px" fill="#000000">
|
viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||||
@ -1118,7 +1137,7 @@
|
|||||||
<h4>Sent top-up request</h4>
|
<h4>Sent top-up request</h4>
|
||||||
<p>This may take upto 30 mins to complete</p>
|
<p>This may take upto 30 mins to complete</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid gap-0-5 hide justify-center text-center">
|
<div class="grid gap-0-5 hidden justify-center text-center">
|
||||||
<svg class="icon user-action-result__icon failed" xmlns="http://www.w3.org/2000/svg" height="24px"
|
<svg class="icon user-action-result__icon failed" xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||||
viewBox="0 0 24 24" width="24px" fill="#000000">
|
viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
<path d="M0 0h24v24H0z" fill="none" />
|
<path d="M0 0h24v24H0z" fill="none" />
|
||||||
@ -1129,7 +1148,7 @@
|
|||||||
<p id="topup_failed_reason"></p>
|
<p id="topup_failed_reason"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="cashier-status hide flex align-center">
|
<div class="cashier-status hidden flex align-center">
|
||||||
<svg class="icon margin-right-0-5" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
<svg class="icon margin-right-0-5" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
||||||
width="24px" fill="#000000">
|
width="24px" fill="#000000">
|
||||||
<path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" />
|
<path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" />
|
||||||
@ -1170,7 +1189,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</sm-input>
|
</sm-input>
|
||||||
<div class="grid gap-1">
|
<div class="grid gap-1">
|
||||||
<div class="grid gap-0-5 hide">
|
<div class="grid gap-0-5 hidden">
|
||||||
<p>
|
<p>
|
||||||
<b>Select UPI ID to receive money</b>
|
<b>Select UPI ID to receive money</b>
|
||||||
</p>
|
</p>
|
||||||
@ -1190,7 +1209,7 @@
|
|||||||
onclick="withdrawMoneyFromWallet()" type="submit">Withdraw</button>
|
onclick="withdrawMoneyFromWallet()" type="submit">Withdraw</button>
|
||||||
</div>
|
</div>
|
||||||
</sm-form>
|
</sm-form>
|
||||||
<div class="grid gap-0-5 hide justify-center text-center">
|
<div class="grid gap-0-5 hidden justify-center text-center">
|
||||||
<svg class="icon user-action-result__icon success" xmlns="http://www.w3.org/2000/svg" height="24px"
|
<svg class="icon user-action-result__icon success" xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||||
viewBox="0 0 24 24" width="24px" fill="#000000">
|
viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||||
@ -1198,10 +1217,10 @@
|
|||||||
</svg>
|
</svg>
|
||||||
<h4>Sent transfer to bank request</h4>
|
<h4>Sent transfer to bank request</h4>
|
||||||
<p>This may take upto 30 mins to complete</p>
|
<p>This may take upto 30 mins to complete</p>
|
||||||
<a href="" class="hide" target="_blank" id="withdrawal_blockchain_link">Check transaction on
|
<a href="" class="hidden" target="_blank" id="withdrawal_blockchain_link">Check transaction on
|
||||||
blockchain</a>
|
blockchain</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid gap-0-5 hide justify-center text-center">
|
<div class="grid gap-0-5 hidden justify-center text-center">
|
||||||
<svg class="icon user-action-result__icon failed" xmlns="http://www.w3.org/2000/svg" height="24px"
|
<svg class="icon user-action-result__icon failed" xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||||
viewBox="0 0 24 24" width="24px" fill="#000000">
|
viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
<path d="M0 0h24v24H0z" fill="none" />
|
<path d="M0 0h24v24H0z" fill="none" />
|
||||||
@ -1212,7 +1231,7 @@
|
|||||||
<p id="withdrawal_failed_reason"></p>
|
<p id="withdrawal_failed_reason"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="cashier-status hide flex align-center">
|
<div class="cashier-status hidden flex align-center">
|
||||||
<svg class="icon margin-right-0-5" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
<svg class="icon margin-right-0-5" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
||||||
width="24px" fill="#000000">
|
width="24px" fill="#000000">
|
||||||
<path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" />
|
<path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" />
|
||||||
@ -1394,7 +1413,7 @@
|
|||||||
onclick="transferToExchange()" type="submit">Send</button>
|
onclick="transferToExchange()" type="submit">Send</button>
|
||||||
</div>
|
</div>
|
||||||
</sm-form>
|
</sm-form>
|
||||||
<div class="grid gap-0-5 hide justify-center text-center">
|
<div class="grid gap-0-5 hidden justify-center text-center">
|
||||||
<svg class="icon user-action-result__icon success" xmlns="http://www.w3.org/2000/svg" height="24px"
|
<svg class="icon user-action-result__icon success" xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||||
viewBox="0 0 24 24" width="24px" fill="#000000">
|
viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||||
@ -1403,7 +1422,7 @@
|
|||||||
<b id="exchange_transfer__success_message">Sent rupee tokens</b>
|
<b id="exchange_transfer__success_message">Sent rupee tokens</b>
|
||||||
<p>Amount may take upto 30 mins to show up in exchange</p>
|
<p>Amount may take upto 30 mins to show up in exchange</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid gap-0-5 hide justify-center text-center">
|
<div class="grid gap-0-5 hidden justify-center text-center">
|
||||||
<svg class="icon user-action-result__icon failed" xmlns="http://www.w3.org/2000/svg" height="24px"
|
<svg class="icon user-action-result__icon failed" xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||||
viewBox="0 0 24 24" width="24px" fill="#000000">
|
viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
<path d="M0 0h24v24H0z" fill="none" />
|
<path d="M0 0h24v24H0z" fill="none" />
|
||||||
@ -1457,7 +1476,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-direction-column gap-1-5 hide" style="height: 24rem;">
|
<div class="flex flex-direction-column gap-1-5 hidden" style="height: 24rem;">
|
||||||
<div class="grid gap-0-3">
|
<div class="grid gap-0-3">
|
||||||
<p>Select reason</p>
|
<p>Select reason</p>
|
||||||
<sm-select id="top_up__reason_selector">
|
<sm-select id="top_up__reason_selector">
|
||||||
@ -1467,7 +1486,7 @@
|
|||||||
<sm-option value="other">Other</sm-option>
|
<sm-option value="other">Other</sm-option>
|
||||||
</sm-select>
|
</sm-select>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid gap-0-3 hide">
|
<div class="grid gap-0-3 hidden">
|
||||||
<p>Describe reason</p>
|
<p>Describe reason</p>
|
||||||
<sm-textarea id="top_up__specified_reason" rows="4"></sm-textarea>
|
<sm-textarea id="top_up__specified_reason" rows="4"></sm-textarea>
|
||||||
</div>
|
</div>
|
||||||
@ -1630,14 +1649,14 @@
|
|||||||
cashierUI.renderRequests(Cashier.Requests);
|
cashierUI.renderRequests(Cashier.Requests);
|
||||||
Cashier.init().then(result => {
|
Cashier.init().then(result => {
|
||||||
console.log(result);
|
console.log(result);
|
||||||
document.querySelectorAll('.admin-element').forEach(elem => elem.classList.remove('hide'))
|
document.querySelectorAll('.admin-element').forEach(elem => elem.classList.remove('hidden'))
|
||||||
document.querySelectorAll('.user-element').forEach(elem => elem.classList.add('hide'))
|
document.querySelectorAll('.user-element').forEach(elem => elem.classList.add('hidden'))
|
||||||
if (cashierUPI[myFloID]) {
|
if (cashierUPI[myFloID]) {
|
||||||
getRef('my_upi_id').classList.remove('hide')
|
getRef('my_upi_id').classList.remove('hidden')
|
||||||
getRef('my_upi_id').value = cashierUPI[myFloID];
|
getRef('my_upi_id').value = cashierUPI[myFloID];
|
||||||
getRef('change_upi_button').textContent = 'Change UPI ID';
|
getRef('change_upi_button').textContent = 'Change UPI ID';
|
||||||
} else {
|
} else {
|
||||||
getRef('my_upi_id').classList.add('hide')
|
getRef('my_upi_id').classList.add('hidden')
|
||||||
getRef('change_upi_button').textContent = 'Add UPI ID';
|
getRef('change_upi_button').textContent = 'Add UPI ID';
|
||||||
}
|
}
|
||||||
showPage(window.location.hash, { firstLoad: true })
|
showPage(window.location.hash, { firstLoad: true })
|
||||||
@ -1649,8 +1668,8 @@
|
|||||||
User.init().then(result => {
|
User.init().then(result => {
|
||||||
console.log(result);
|
console.log(result);
|
||||||
console.log("Cashiers:", cashierUPI);
|
console.log("Cashiers:", cashierUPI);
|
||||||
document.querySelectorAll('.admin-element').forEach(elem => elem.classList.add('hide'))
|
document.querySelectorAll('.admin-element').forEach(elem => elem.classList.add('hidden'))
|
||||||
document.querySelectorAll('.user-element').forEach(elem => elem.classList.remove('hide'))
|
document.querySelectorAll('.user-element').forEach(elem => elem.classList.remove('hidden'))
|
||||||
showPage(window.location.hash, { firstLoad: true })
|
showPage(window.location.hash, { firstLoad: true })
|
||||||
floGlobals.loaded = true
|
floGlobals.loaded = true
|
||||||
}).catch(error => console.error(error))
|
}).catch(error => console.error(error))
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
(function(EXPORTS) { //floBlockchainAPI v2.3.2a
|
(function(EXPORTS) { //floBlockchainAPI v2.3.3a
|
||||||
/* FLO Blockchain Operator to send/receive data from blockchain using API calls*/
|
/* FLO Blockchain Operator to send/receive data from blockchain using API calls*/
|
||||||
'use strict';
|
'use strict';
|
||||||
const floBlockchainAPI = EXPORTS;
|
const floBlockchainAPI = EXPORTS;
|
||||||
@ -46,7 +46,9 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const serverList = Array.from(floGlobals.apiURL && floGlobals.apiURL[DEFAULT.blockchain] ? floGlobals.apiURL[DEFAULT.blockchain] : DEFAULT.apiURL[DEFAULT.blockchain]);
|
const allServerList = new Set(floGlobals.apiURL && floGlobals.apiURL[DEFAULT.blockchain] ? floGlobals.apiURL[DEFAULT.blockchain] : DEFAULT.apiURL[DEFAULT.blockchain]);
|
||||||
|
|
||||||
|
var serverList = Array.from(allServerList);
|
||||||
var curPos = floCrypto.randInt(0, serverList - 1);
|
var curPos = floCrypto.randInt(0, serverList - 1);
|
||||||
|
|
||||||
function fetch_retry(apicall, rm_flosight) {
|
function fetch_retry(apicall, rm_flosight) {
|
||||||
@ -54,17 +56,24 @@
|
|||||||
let i = serverList.indexOf(rm_flosight)
|
let i = serverList.indexOf(rm_flosight)
|
||||||
if (i != -1) serverList.splice(i, 1);
|
if (i != -1) serverList.splice(i, 1);
|
||||||
curPos = floCrypto.randInt(0, serverList.length - 1);
|
curPos = floCrypto.randInt(0, serverList.length - 1);
|
||||||
fetch_api(apicall)
|
fetch_api(apicall, false)
|
||||||
.then(result => resolve(result))
|
.then(result => resolve(result))
|
||||||
.catch(error => reject(error));
|
.catch(error => reject(error));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetch_api(apicall) {
|
function fetch_api(apicall, ic = true) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (serverList.length === 0)
|
if (serverList.length === 0) {
|
||||||
reject("No floSight server working");
|
if (ic) {
|
||||||
else {
|
serverList = Array.from(allServerList);
|
||||||
|
curPos = floCrypto.randInt(0, serverList.length - 1);
|
||||||
|
fetch_api(apicall, false)
|
||||||
|
.then(result => resolve(result))
|
||||||
|
.catch(error => reject(error));
|
||||||
|
} else
|
||||||
|
reject("No floSight server working");
|
||||||
|
} else {
|
||||||
let flosight = serverList[curPos];
|
let flosight = serverList[curPos];
|
||||||
fetch(flosight + apicall).then(response => {
|
fetch(flosight + apicall).then(response => {
|
||||||
if (response.ok)
|
if (response.ok)
|
||||||
@ -116,9 +125,9 @@
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!floCrypto.validateASCII(floData))
|
if (!floCrypto.validateASCII(floData))
|
||||||
return reject("Invalid FLO_Data: only printable ASCII characters are allowed");
|
return reject("Invalid FLO_Data: only printable ASCII characters are allowed");
|
||||||
else if (!floCrypto.validateAddr(senderAddr))
|
else if (!floCrypto.validateFloID(senderAddr))
|
||||||
return reject(`Invalid address : ${senderAddr}`);
|
return reject(`Invalid address : ${senderAddr}`);
|
||||||
else if (!floCrypto.validateAddr(receiverAddr))
|
else if (!floCrypto.validateFloID(receiverAddr))
|
||||||
return reject(`Invalid address : ${receiverAddr}`);
|
return reject(`Invalid address : ${receiverAddr}`);
|
||||||
else if (privKey.length < 1 || !floCrypto.verifyPrivKey(privKey, senderAddr))
|
else if (privKey.length < 1 || !floCrypto.verifyPrivKey(privKey, senderAddr))
|
||||||
return reject("Invalid Private key!");
|
return reject("Invalid Private key!");
|
||||||
@ -193,7 +202,7 @@
|
|||||||
//merge all UTXOs of a given floID into a single UTXO
|
//merge all UTXOs of a given floID into a single UTXO
|
||||||
floBlockchainAPI.mergeUTXOs = function(floID, privKey, floData = '') {
|
floBlockchainAPI.mergeUTXOs = function(floID, privKey, floData = '') {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!floCrypto.validateAddr(floID))
|
if (!floCrypto.validateFloID(floID))
|
||||||
return reject(`Invalid floID`);
|
return reject(`Invalid floID`);
|
||||||
if (!floCrypto.verifyPrivKey(privKey, floID))
|
if (!floCrypto.verifyPrivKey(privKey, floID))
|
||||||
return reject("Invalid Private Key");
|
return reject("Invalid Private Key");
|
||||||
@ -317,7 +326,7 @@
|
|||||||
}
|
}
|
||||||
//Validate the receiver IDs and receive amount
|
//Validate the receiver IDs and receive amount
|
||||||
for (let floID in receivers) {
|
for (let floID in receivers) {
|
||||||
if (!floCrypto.validateAddr(floID))
|
if (!floCrypto.validateFloID(floID))
|
||||||
invalids.InvalidReceiverIDs.push(floID);
|
invalids.InvalidReceiverIDs.push(floID);
|
||||||
if (typeof receivers[floID] !== 'number' || receivers[floID] <= 0)
|
if (typeof receivers[floID] !== 'number' || receivers[floID] <= 0)
|
||||||
invalids.InvalidReceiveAmountFor.push(floID);
|
invalids.InvalidReceiveAmountFor.push(floID);
|
||||||
|
|||||||
@ -1,14 +1,59 @@
|
|||||||
(function(EXPORTS) { //floCloudAPI v2.3.0
|
(function(EXPORTS) { //floCloudAPI v2.4.2b
|
||||||
/* FLO Cloud operations to send/request application data*/
|
/* FLO Cloud operations to send/request application data*/
|
||||||
'use strict';
|
'use strict';
|
||||||
const floCloudAPI = EXPORTS;
|
const floCloudAPI = EXPORTS;
|
||||||
|
|
||||||
const DEFAULT = {
|
const DEFAULT = {
|
||||||
|
blockchainPrefix: 0x23, //Prefix version for FLO blockchain
|
||||||
SNStorageID: floGlobals.SNStorageID || "FNaN9McoBAEFUjkRmNQRYLmBF8SpS7Tgfk",
|
SNStorageID: floGlobals.SNStorageID || "FNaN9McoBAEFUjkRmNQRYLmBF8SpS7Tgfk",
|
||||||
adminID: floGlobals.adminID,
|
adminID: floGlobals.adminID,
|
||||||
application: floGlobals.application
|
application: floGlobals.application,
|
||||||
|
callback: (d, e) => console.debug(d, e)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var user_id, user_public, user_private, aes_key;
|
||||||
|
|
||||||
|
function user(id, priv) {
|
||||||
|
if (!priv || !id)
|
||||||
|
return user.clear();
|
||||||
|
let pub = floCrypto.getPubKeyHex(priv);
|
||||||
|
if (!pub || !floCrypto.verifyPubKey(pub, id))
|
||||||
|
return user.clear();
|
||||||
|
let n = floCrypto.randInt(12, 20);
|
||||||
|
aes_key = floCrypto.randString(n);
|
||||||
|
user_private = Crypto.AES.encrypt(priv, aes_key);
|
||||||
|
user_public = pub;
|
||||||
|
user_id = id;
|
||||||
|
return user_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperties(user, {
|
||||||
|
id: {
|
||||||
|
get: () => {
|
||||||
|
if (!user_id)
|
||||||
|
throw "User not set";
|
||||||
|
return user_id;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
public: {
|
||||||
|
get: () => {
|
||||||
|
if (!user_public)
|
||||||
|
throw "User not set";
|
||||||
|
return user_public;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sign: {
|
||||||
|
value: msg => {
|
||||||
|
if (!user_private)
|
||||||
|
throw "User not set";
|
||||||
|
return floCrypto.signData(msg, Crypto.AES.decrypt(user_private, aes_key));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clear: {
|
||||||
|
value: () => user_id = user_public = user_private = aes_key = undefined
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
Object.defineProperties(floCloudAPI, {
|
Object.defineProperties(floCloudAPI, {
|
||||||
SNStorageID: {
|
SNStorageID: {
|
||||||
get: () => DEFAULT.SNStorageID
|
get: () => DEFAULT.SNStorageID
|
||||||
@ -18,6 +63,9 @@
|
|||||||
},
|
},
|
||||||
application: {
|
application: {
|
||||||
get: () => DEFAULT.application
|
get: () => DEFAULT.application
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
get: () => user
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -175,7 +223,7 @@
|
|||||||
if (_inactive.size === kBucket.list.length)
|
if (_inactive.size === kBucket.list.length)
|
||||||
return reject('Cloud offline');
|
return reject('Cloud offline');
|
||||||
if (!(snID in supernodes))
|
if (!(snID in supernodes))
|
||||||
snID = kBucket.closestNode(snID);
|
snID = kBucket.closestNode(proxyID(snID));
|
||||||
ws_connect(snID)
|
ws_connect(snID)
|
||||||
.then(node => resolve(node))
|
.then(node => resolve(node))
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
@ -213,7 +261,7 @@
|
|||||||
if (_inactive.size === kBucket.list.length)
|
if (_inactive.size === kBucket.list.length)
|
||||||
return reject('Cloud offline');
|
return reject('Cloud offline');
|
||||||
if (!(snID in supernodes))
|
if (!(snID in supernodes))
|
||||||
snID = kBucket.closestNode(snID);
|
snID = kBucket.closestNode(proxyID(snID));
|
||||||
fetch_API(snID, data)
|
fetch_API(snID, data)
|
||||||
.then(result => resolve(result))
|
.then(result => resolve(result))
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
@ -332,6 +380,50 @@
|
|||||||
'|' + (options.application || DEFAULT.application);
|
'|' + (options.application || DEFAULT.application);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const proxyID = util.proxyID = function(address) {
|
||||||
|
if (!address)
|
||||||
|
return;
|
||||||
|
var bytes;
|
||||||
|
if (address.length == 34) { //legacy encoding
|
||||||
|
let decode = bitjs.Base58.decode(address);
|
||||||
|
bytes = decode.slice(0, decode.length - 4);
|
||||||
|
let checksum = decode.slice(decode.length - 4),
|
||||||
|
hash = Crypto.SHA256(Crypto.SHA256(bytes, {
|
||||||
|
asBytes: true
|
||||||
|
}), {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
hash[0] != checksum[0] || hash[1] != checksum[1] || hash[2] != checksum[2] || hash[3] != checksum[3] ?
|
||||||
|
bytes = undefined : bytes.shift();
|
||||||
|
} else if (address.length == 42 || address.length == 62) { //bech encoding
|
||||||
|
if (typeof coinjs !== 'function')
|
||||||
|
throw "library missing (lib_btc.js)";
|
||||||
|
let decode = coinjs.bech32_decode(address);
|
||||||
|
if (decode) {
|
||||||
|
bytes = decode.data;
|
||||||
|
bytes.shift();
|
||||||
|
bytes = coinjs.bech32_convert(bytes, 5, 8, false);
|
||||||
|
if (address.length == 62) //for long bech, aggregate once more to get 160 bit
|
||||||
|
bytes = coinjs.bech32_convert(bytes, 5, 8, false);
|
||||||
|
}
|
||||||
|
} else if (address.length == 66) { //public key hex
|
||||||
|
bytes = ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(address), {
|
||||||
|
asBytes: true
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if (!bytes)
|
||||||
|
throw "Invalid address: " + address;
|
||||||
|
else {
|
||||||
|
bytes.unshift(DEFAULT.blockchainPrefix);
|
||||||
|
let hash = Crypto.SHA256(Crypto.SHA256(bytes, {
|
||||||
|
asBytes: true
|
||||||
|
}), {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
return bitjs.Base58.encode(bytes.concat(hash.slice(0, 4)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const lastCommit = {};
|
const lastCommit = {};
|
||||||
Object.defineProperty(lastCommit, 'get', {
|
Object.defineProperty(lastCommit, 'get', {
|
||||||
value: objName => JSON.parse(lastCommit[objName])
|
value: objName => JSON.parse(lastCommit[objName])
|
||||||
@ -392,19 +484,19 @@
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
//set status as online for myFloID
|
//set status as online for user_id
|
||||||
floCloudAPI.setStatus = function(options = {}) {
|
floCloudAPI.setStatus = function(options = {}) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let callback = options.callback instanceof Function ? options.callback : (d, e) => console.debug(d, e);
|
let callback = options.callback instanceof Function ? options.callback : DEFAULT.callback;
|
||||||
var request = {
|
var request = {
|
||||||
floID: myFloID,
|
floID: user.id,
|
||||||
application: options.application || DEFAULT.application,
|
application: options.application || DEFAULT.application,
|
||||||
time: Date.now(),
|
time: Date.now(),
|
||||||
status: true,
|
status: true,
|
||||||
pubKey: myPubKey
|
pubKey: user.public
|
||||||
}
|
}
|
||||||
let hashcontent = ["time", "application", "floID"].map(d => request[d]).join("|");
|
let hashcontent = ["time", "application", "floID"].map(d => request[d]).join("|");
|
||||||
request.sign = floCrypto.signData(hashcontent, myPrivKey);
|
request.sign = user.sign(hashcontent);
|
||||||
liveRequest(options.refID || DEFAULT.adminID, request, callback)
|
liveRequest(options.refID || DEFAULT.adminID, request, callback)
|
||||||
.then(result => resolve(result))
|
.then(result => resolve(result))
|
||||||
.catch(error => reject(error))
|
.catch(error => reject(error))
|
||||||
@ -416,7 +508,7 @@
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!Array.isArray(trackList))
|
if (!Array.isArray(trackList))
|
||||||
trackList = [trackList];
|
trackList = [trackList];
|
||||||
let callback = options.callback instanceof Function ? options.callback : (d, e) => console.debug(d, e);
|
let callback = options.callback instanceof Function ? options.callback : DEFAULT.callback;
|
||||||
let request = {
|
let request = {
|
||||||
status: false,
|
status: false,
|
||||||
application: options.application || DEFAULT.application,
|
application: options.application || DEFAULT.application,
|
||||||
@ -432,9 +524,9 @@
|
|||||||
const sendApplicationData = floCloudAPI.sendApplicationData = function(message, type, options = {}) {
|
const sendApplicationData = floCloudAPI.sendApplicationData = function(message, type, options = {}) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
var data = {
|
var data = {
|
||||||
senderID: myFloID,
|
senderID: user.id,
|
||||||
receiverID: options.receiverID || DEFAULT.adminID,
|
receiverID: options.receiverID || DEFAULT.adminID,
|
||||||
pubKey: myPubKey,
|
pubKey: user.public,
|
||||||
message: encodeMessage(message),
|
message: encodeMessage(message),
|
||||||
time: Date.now(),
|
time: Date.now(),
|
||||||
application: options.application || DEFAULT.application,
|
application: options.application || DEFAULT.application,
|
||||||
@ -443,7 +535,7 @@
|
|||||||
}
|
}
|
||||||
let hashcontent = ["receiverID", "time", "application", "type", "message", "comment"]
|
let hashcontent = ["receiverID", "time", "application", "type", "message", "comment"]
|
||||||
.map(d => data[d]).join("|")
|
.map(d => data[d]).join("|")
|
||||||
data.sign = floCrypto.signData(hashcontent, myPrivKey);
|
data.sign = user.sign(hashcontent);
|
||||||
singleRequest(data.receiverID, data)
|
singleRequest(data.receiverID, data)
|
||||||
.then(result => resolve(result))
|
.then(result => resolve(result))
|
||||||
.catch(error => reject(error))
|
.catch(error => reject(error))
|
||||||
@ -482,19 +574,20 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//(NEEDS UPDATE) delete data from supernode cloud (received only)
|
/*(NEEDS UPDATE)
|
||||||
|
//delete data from supernode cloud (received only)
|
||||||
floCloudAPI.deleteApplicationData = function(vectorClocks, options = {}) {
|
floCloudAPI.deleteApplicationData = function(vectorClocks, options = {}) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
var delreq = {
|
var delreq = {
|
||||||
requestorID: myFloID,
|
requestorID: user.id,
|
||||||
pubKey: myPubKey,
|
pubKey: user.public,
|
||||||
time: Date.now(),
|
time: Date.now(),
|
||||||
delete: (Array.isArray(vectorClocks) ? vectorClocks : [vectorClocks]),
|
delete: (Array.isArray(vectorClocks) ? vectorClocks : [vectorClocks]),
|
||||||
application: options.application || DEFAULT.application
|
application: options.application || DEFAULT.application
|
||||||
}
|
}
|
||||||
let hashcontent = ["time", "application", "delete"]
|
let hashcontent = ["time", "application", "delete"]
|
||||||
.map(d => delreq[d]).join("|")
|
.map(d => delreq[d]).join("|")
|
||||||
delreq.sign = floCrypto.signData(hashcontent, myPrivKey)
|
delreq.sign = user.sign(hashcontent)
|
||||||
singleRequest(delreq.requestorID, delreq).then(result => {
|
singleRequest(delreq.requestorID, delreq).then(result => {
|
||||||
let success = [],
|
let success = [],
|
||||||
failed = [];
|
failed = [];
|
||||||
@ -507,8 +600,9 @@
|
|||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
//(NEEDS UPDATE) edit comment of data in supernode cloud (mutable comments only)
|
/*(NEEDS UPDATE)
|
||||||
|
//edit comment of data in supernode cloud (mutable comments only)
|
||||||
floCloudAPI.editApplicationData = function(vectorClock, newComment, oldData, options = {}) {
|
floCloudAPI.editApplicationData = function(vectorClock, newComment, oldData, options = {}) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let p0
|
let p0
|
||||||
@ -523,12 +617,12 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
p0.then(d => {
|
p0.then(d => {
|
||||||
if (d.senderID != myFloID)
|
if (d.senderID != user.id)
|
||||||
return reject("Invalid requestorID")
|
return reject("Invalid requestorID")
|
||||||
else if (!d.comment.startsWith("EDIT:"))
|
else if (!d.comment.startsWith("EDIT:"))
|
||||||
return reject("Data immutable")
|
return reject("Data immutable")
|
||||||
let data = {
|
let data = {
|
||||||
requestorID: myFloID,
|
requestorID: user.id,
|
||||||
receiverID: d.receiverID,
|
receiverID: d.receiverID,
|
||||||
time: Date.now(),
|
time: Date.now(),
|
||||||
application: d.application,
|
application: d.application,
|
||||||
@ -542,29 +636,30 @@
|
|||||||
"comment"
|
"comment"
|
||||||
]
|
]
|
||||||
.map(x => d[x]).join("|")
|
.map(x => d[x]).join("|")
|
||||||
data.edit.sign = floCrypto.signData(hashcontent, myPrivKey)
|
data.edit.sign = user.sign(hashcontent)
|
||||||
singleRequest(data.receiverID, data)
|
singleRequest(data.receiverID, data)
|
||||||
.then(result => resolve("Data comment updated"))
|
.then(result => resolve("Data comment updated"))
|
||||||
.catch(error => reject(error))
|
.catch(error => reject(error))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
//tag data in supernode cloud (subAdmin access only)
|
//tag data in supernode cloud (subAdmin access only)
|
||||||
floCloudAPI.tagApplicationData = function(vectorClock, tag, options = {}) {
|
floCloudAPI.tagApplicationData = function(vectorClock, tag, options = {}) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!floGlobals.subAdmins.includes(myFloID))
|
if (!floGlobals.subAdmins.includes(user.id))
|
||||||
return reject("Only subAdmins can tag data")
|
return reject("Only subAdmins can tag data")
|
||||||
var request = {
|
var request = {
|
||||||
receiverID: options.receiverID || DEFAULT.adminID,
|
receiverID: options.receiverID || DEFAULT.adminID,
|
||||||
requestorID: myFloID,
|
requestorID: user.id,
|
||||||
pubKey: myPubKey,
|
pubKey: user.public,
|
||||||
time: Date.now(),
|
time: Date.now(),
|
||||||
vectorClock: vectorClock,
|
vectorClock: vectorClock,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
}
|
}
|
||||||
let hashcontent = ["time", "vectorClock", 'tag'].map(d => request[d]).join("|");
|
let hashcontent = ["time", "vectorClock", 'tag'].map(d => request[d]).join("|");
|
||||||
request.sign = floCrypto.signData(hashcontent, myPrivKey);
|
request.sign = user.sign(hashcontent);
|
||||||
singleRequest(request.receiverID, request)
|
singleRequest(request.receiverID, request)
|
||||||
.then(result => resolve(result))
|
.then(result => resolve(result))
|
||||||
.catch(error => reject(error))
|
.catch(error => reject(error))
|
||||||
@ -576,14 +671,14 @@
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
var request = {
|
var request = {
|
||||||
receiverID: options.receiverID || DEFAULT.adminID,
|
receiverID: options.receiverID || DEFAULT.adminID,
|
||||||
requestorID: myFloID,
|
requestorID: user.id,
|
||||||
pubKey: myPubKey,
|
pubKey: user.public,
|
||||||
time: Date.now(),
|
time: Date.now(),
|
||||||
vectorClock: vectorClock,
|
vectorClock: vectorClock,
|
||||||
note: note,
|
note: note,
|
||||||
}
|
}
|
||||||
let hashcontent = ["time", "vectorClock", 'note'].map(d => request[d]).join("|");
|
let hashcontent = ["time", "vectorClock", 'note'].map(d => request[d]).join("|");
|
||||||
request.sign = floCrypto.signData(hashcontent, myPrivKey);
|
request.sign = user.sign(hashcontent);
|
||||||
singleRequest(request.receiverID, request)
|
singleRequest(request.receiverID, request)
|
||||||
.then(result => resolve(result))
|
.then(result => resolve(result))
|
||||||
.catch(error => reject(error))
|
.catch(error => reject(error))
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
(function(EXPORTS) { //floCrypto v2.3.0a
|
(function(EXPORTS) { //floCrypto v2.3.3a
|
||||||
/* FLO Crypto Operators */
|
/* FLO Crypto Operators */
|
||||||
'use strict';
|
'use strict';
|
||||||
const floCrypto = EXPORTS;
|
const floCrypto = EXPORTS;
|
||||||
@ -7,6 +7,7 @@
|
|||||||
const ecparams = EllipticCurve.getSECCurveByName("secp256k1");
|
const ecparams = EllipticCurve.getSECCurveByName("secp256k1");
|
||||||
const ascii_alternatives = `‘ '\n’ '\n“ "\n” "\n– --\n— ---\n≥ >=\n≤ <=\n≠ !=\n× *\n÷ /\n← <-\n→ ->\n↔ <->\n⇒ =>\n⇐ <=\n⇔ <=>`;
|
const ascii_alternatives = `‘ '\n’ '\n“ "\n” "\n– --\n— ---\n≥ >=\n≤ <=\n≠ !=\n× *\n÷ /\n← <-\n→ ->\n↔ <->\n⇒ =>\n⇐ <=\n⇔ <=>`;
|
||||||
const exponent1 = () => p.add(BigInteger.ONE).divide(BigInteger("4"));
|
const exponent1 = () => p.add(BigInteger.ONE).divide(BigInteger("4"));
|
||||||
|
coinjs.compressed = true; //defaulting coinjs compressed to true;
|
||||||
|
|
||||||
function calculateY(x) {
|
function calculateY(x) {
|
||||||
let exp = exponent1();
|
let exp = exponent1();
|
||||||
@ -121,12 +122,8 @@
|
|||||||
//Sign data using private-key
|
//Sign data using private-key
|
||||||
floCrypto.signData = function(data, privateKeyHex) {
|
floCrypto.signData = function(data, privateKeyHex) {
|
||||||
var key = new Bitcoin.ECKey(privateKeyHex);
|
var key = new Bitcoin.ECKey(privateKeyHex);
|
||||||
key.setCompressed(true);
|
|
||||||
var privateKeyArr = key.getBitcoinPrivateKeyByteArray();
|
|
||||||
var privateKey = BigInteger.fromByteArrayUnsigned(privateKeyArr);
|
|
||||||
var messageHash = Crypto.SHA256(data);
|
var messageHash = Crypto.SHA256(data);
|
||||||
var messageHashBigInteger = new BigInteger(messageHash);
|
var messageSign = Bitcoin.ECDSA.sign(messageHash, key.priv);
|
||||||
var messageSign = Bitcoin.ECDSA.sign(messageHashBigInteger, key.priv);
|
|
||||||
var sighex = Crypto.util.bytesToHex(messageSign);
|
var sighex = Crypto.util.bytesToHex(messageSign);
|
||||||
return sighex;
|
return sighex;
|
||||||
}
|
}
|
||||||
@ -134,11 +131,9 @@
|
|||||||
//Verify signatue of the data using public-key
|
//Verify signatue of the data using public-key
|
||||||
floCrypto.verifySign = function(data, signatureHex, publicKeyHex) {
|
floCrypto.verifySign = function(data, signatureHex, publicKeyHex) {
|
||||||
var msgHash = Crypto.SHA256(data);
|
var msgHash = Crypto.SHA256(data);
|
||||||
var messageHashBigInteger = new BigInteger(msgHash);
|
|
||||||
var sigBytes = Crypto.util.hexToBytes(signatureHex);
|
var sigBytes = Crypto.util.hexToBytes(signatureHex);
|
||||||
var signature = Bitcoin.ECDSA.parseSig(sigBytes);
|
|
||||||
var publicKeyPoint = ecparams.getCurve().decodePointHex(publicKeyHex);
|
var publicKeyPoint = ecparams.getCurve().decodePointHex(publicKeyHex);
|
||||||
var verify = Bitcoin.ECDSA.verifyRaw(messageHashBigInteger, signature.r, signature.s, publicKeyPoint);
|
var verify = Bitcoin.ECDSA.verify(msgHash, sigBytes, publicKeyPoint);
|
||||||
return verify;
|
return verify;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,6 +177,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
floCrypto.getAddress = function(privateKeyHex, strict = false) {
|
||||||
|
if (!privateKeyHex)
|
||||||
|
return;
|
||||||
|
var key = new Bitcoin.ECKey(privateKeyHex);
|
||||||
|
if (key.priv == null)
|
||||||
|
return null;
|
||||||
|
key.setCompressed(true);
|
||||||
|
let pubKey = key.getPubKeyHex(),
|
||||||
|
version = bitjs.Base58.decode(privateKeyHex)[0];
|
||||||
|
switch (version) {
|
||||||
|
case coinjs.priv: //BTC
|
||||||
|
return coinjs.bech32Address(pubKey).address;
|
||||||
|
case bitjs.priv: //FLO
|
||||||
|
return bitjs.pubkey2address(pubKey);
|
||||||
|
default:
|
||||||
|
return strict ? false : bitjs.pubkey2address(pubKey); //default to FLO address (if strict=false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Verify the private-key for the given public-key or flo-ID
|
//Verify the private-key for the given public-key or flo-ID
|
||||||
floCrypto.verifyPrivKey = function(privateKeyHex, pubKey_floID, isfloID = true) {
|
floCrypto.verifyPrivKey = function(privateKeyHex, pubKey_floID, isfloID = true) {
|
||||||
if (!privateKeyHex || !pubKey_floID)
|
if (!privateKeyHex || !pubKey_floID)
|
||||||
@ -202,18 +216,81 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check if the given Address is valid or not
|
//Check if the given flo-id is valid or not
|
||||||
floCrypto.validateFloID = floCrypto.validateAddr = function(inpAddr) {
|
floCrypto.validateFloID = function(floID) {
|
||||||
if (!inpAddr)
|
if (!floID)
|
||||||
return false;
|
return false;
|
||||||
try {
|
try {
|
||||||
let addr = new Bitcoin.Address(inpAddr);
|
let addr = new Bitcoin.Address(floID);
|
||||||
return true;
|
return true;
|
||||||
} catch {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Check if the given address (any blockchain) is valid or not
|
||||||
|
floCrypto.validateAddr = function(address, std = true, bech = true) {
|
||||||
|
if (address.length == 34) { //legacy or segwit encoding
|
||||||
|
if (std === false)
|
||||||
|
return false;
|
||||||
|
let decode = bitjs.Base58.decode(address);
|
||||||
|
var raw = decode.slice(0, decode.length - 4),
|
||||||
|
checksum = decode.slice(decode.length - 4);
|
||||||
|
var hash = Crypto.SHA256(Crypto.SHA256(raw, {
|
||||||
|
asBytes: true
|
||||||
|
}), {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
if (hash[0] != checksum[0] || hash[1] != checksum[1] || hash[2] != checksum[2] || hash[3] != checksum[3])
|
||||||
|
return false;
|
||||||
|
else if (std === true || (!Array.isArray(std) && std === raw[0]) || (Array.isArray(std) && std.includes(raw[0])))
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
} else if (address.length == 42 || address.length == 62) { //bech encoding
|
||||||
|
if (bech === false)
|
||||||
|
return false;
|
||||||
|
let decode = coinjs.bech32_decode(address);
|
||||||
|
if (!decode)
|
||||||
|
return false;
|
||||||
|
var raw = decode.data;
|
||||||
|
if (bech === true || (!Array.isArray(bech) && bech === raw[0]) || (Array.isArray(bech) && bech.includes(raw[0])))
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
} else //unknown length
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
floCrypto.verifyPubKey = function(pubKeyHex, address) {
|
||||||
|
let pub_hash = Crypto.util.bytesToHex(ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(pubKeyHex), {
|
||||||
|
asBytes: true
|
||||||
|
})));
|
||||||
|
if (address.length == 34) { //legacy encoding
|
||||||
|
let decode = bitjs.Base58.decode(address);
|
||||||
|
var raw = decode.slice(0, decode.length - 4),
|
||||||
|
checksum = decode.slice(decode.length - 4);
|
||||||
|
var hash = Crypto.SHA256(Crypto.SHA256(raw, {
|
||||||
|
asBytes: true
|
||||||
|
}), {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
if (hash[0] != checksum[0] || hash[1] != checksum[1] || hash[2] != checksum[2] || hash[3] != checksum[3])
|
||||||
|
return false;
|
||||||
|
raw.shift();
|
||||||
|
return pub_hash === Crypto.util.bytesToHex(raw);
|
||||||
|
} else if (address.length == 42 || address.length == 62) { //bech encoding
|
||||||
|
let decode = coinjs.bech32_decode(address);
|
||||||
|
if (!decode)
|
||||||
|
return false;
|
||||||
|
var raw = decode.data;
|
||||||
|
raw.shift();
|
||||||
|
raw = coinjs.bech32_convert(raw, 5, 8, false);
|
||||||
|
return pub_hash === Crypto.util.bytesToHex(raw);
|
||||||
|
} else //unknown length
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//Split the str using shamir's Secret and Returns the shares
|
//Split the str using shamir's Secret and Returns the shares
|
||||||
floCrypto.createShamirsSecretShares = function(str, total_shares, threshold_limit) {
|
floCrypto.createShamirsSecretShares = function(str, total_shares, threshold_limit) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -1,8 +1,144 @@
|
|||||||
(function(EXPORTS) { //floDapps v2.2.1
|
(function(EXPORTS) { //floDapps v2.3.2c
|
||||||
/* General functions for FLO Dapps*/
|
/* General functions for FLO Dapps*/
|
||||||
//'use strict';
|
'use strict';
|
||||||
const floDapps = EXPORTS;
|
const floDapps = EXPORTS;
|
||||||
|
|
||||||
|
const DEFAULT = {
|
||||||
|
root: "floDapps",
|
||||||
|
application: floGlobals.application,
|
||||||
|
adminID: floGlobals.adminID
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.defineProperties(floDapps, {
|
||||||
|
application: {
|
||||||
|
get: () => DEFAULT.application
|
||||||
|
},
|
||||||
|
adminID: {
|
||||||
|
get: () => DEFAULT.adminID
|
||||||
|
},
|
||||||
|
root: {
|
||||||
|
get: () => DEFAULT.root
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var user_priv_raw, aes_key, user_priv_wrap; //private variable inside capsule
|
||||||
|
const raw_user = {
|
||||||
|
get private() {
|
||||||
|
if (!user_priv_raw)
|
||||||
|
throw "User not logged in";
|
||||||
|
return Crypto.AES.decrypt(user_priv_raw, aes_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var user_id, user_public, user_private;
|
||||||
|
const user = floDapps.user = {
|
||||||
|
get id() {
|
||||||
|
if (!user_id)
|
||||||
|
throw "User not logged in";
|
||||||
|
return user_id;
|
||||||
|
},
|
||||||
|
get public() {
|
||||||
|
if (!user_public)
|
||||||
|
throw "User not logged in";
|
||||||
|
return user_public;
|
||||||
|
},
|
||||||
|
get private() {
|
||||||
|
if (!user_private)
|
||||||
|
throw "User not logged in";
|
||||||
|
else if (user_private instanceof Function)
|
||||||
|
return user_private();
|
||||||
|
else
|
||||||
|
return Crypto.AES.decrypt(user_private, aes_key);
|
||||||
|
},
|
||||||
|
sign(message) {
|
||||||
|
return floCrypto.signData(message, raw_user.private);
|
||||||
|
},
|
||||||
|
decrypt(data) {
|
||||||
|
return floCrypto.decryptData(data, raw_user.private);
|
||||||
|
},
|
||||||
|
encipher(message) {
|
||||||
|
return Crypto.AES.encrypt(message, raw_user.private);
|
||||||
|
},
|
||||||
|
decipher(data) {
|
||||||
|
return Crypto.AES.decrypt(data, raw_user.private);
|
||||||
|
},
|
||||||
|
get db_name() {
|
||||||
|
return "floDapps#" + user.id;
|
||||||
|
},
|
||||||
|
lock() {
|
||||||
|
user_private = user_priv_wrap;
|
||||||
|
},
|
||||||
|
async unlock() {
|
||||||
|
if (await user.private === raw_user.private)
|
||||||
|
user_private = user_priv_raw;
|
||||||
|
},
|
||||||
|
clear() {
|
||||||
|
user_id = user_public = user_private = undefined;
|
||||||
|
user_priv_raw = aes_key = undefined;
|
||||||
|
delete user.contacts;
|
||||||
|
delete user.pubKeys;
|
||||||
|
delete user.messages;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.defineProperties(window, {
|
||||||
|
myFloID: {
|
||||||
|
get: () => {
|
||||||
|
try {
|
||||||
|
return user.id;
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
myUserID: {
|
||||||
|
get: () => {
|
||||||
|
try {
|
||||||
|
return user.id;
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
myPubKey: {
|
||||||
|
get: () => {
|
||||||
|
try {
|
||||||
|
return user.public;
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
myPrivKey: {
|
||||||
|
get: () => {
|
||||||
|
try {
|
||||||
|
return user.private;
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var subAdmins, settings
|
||||||
|
Object.defineProperties(floGlobals, {
|
||||||
|
subAdmins: {
|
||||||
|
get: () => subAdmins
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
get: () => settings
|
||||||
|
},
|
||||||
|
contacts: {
|
||||||
|
get: () => user.contacts
|
||||||
|
},
|
||||||
|
pubKeys: {
|
||||||
|
get: () => user.pubKeys
|
||||||
|
},
|
||||||
|
messages: {
|
||||||
|
get: () => user.messages
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
function initIndexedDB() {
|
function initIndexedDB() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
var obs_g = {
|
var obs_g = {
|
||||||
@ -28,41 +164,41 @@
|
|||||||
}
|
}
|
||||||
//add other given objectStores
|
//add other given objectStores
|
||||||
initIndexedDB.appObs = initIndexedDB.appObs || {}
|
initIndexedDB.appObs = initIndexedDB.appObs || {}
|
||||||
for (o in initIndexedDB.appObs)
|
for (let o in initIndexedDB.appObs)
|
||||||
if (!(o in obs_a))
|
if (!(o in obs_a))
|
||||||
obs_a[o] = initIndexedDB.appObs[o]
|
obs_a[o] = initIndexedDB.appObs[o]
|
||||||
Promise.all([
|
Promise.all([
|
||||||
compactIDB.initDB(floGlobals.application, obs_a),
|
compactIDB.initDB(DEFAULT.application, obs_a),
|
||||||
compactIDB.initDB("floDapps", obs_g)
|
compactIDB.initDB(DEFAULT.root, obs_g)
|
||||||
]).then(result => {
|
]).then(result => {
|
||||||
compactIDB.setDefaultDB(floGlobals.application)
|
compactIDB.setDefaultDB(DEFAULT.application)
|
||||||
resolve("IndexedDB App Storage Initated Successfully")
|
resolve("IndexedDB App Storage Initated Successfully")
|
||||||
}).catch(error => reject(error));
|
}).catch(error => reject(error));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function initUserDB(floID) {
|
function initUserDB() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
var obs = {
|
var obs = {
|
||||||
contacts: {},
|
contacts: {},
|
||||||
pubKeys: {},
|
pubKeys: {},
|
||||||
messages: {}
|
messages: {}
|
||||||
}
|
}
|
||||||
compactIDB.initDB(`floDapps#${floID}`, obs).then(result => {
|
compactIDB.initDB(user.db_name, obs).then(result => {
|
||||||
resolve("UserDB Initated Successfully")
|
resolve("UserDB Initated Successfully")
|
||||||
}).catch(error => reject('Init userDB failed'));
|
}).catch(error => reject('Init userDB failed'));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadUserDB(floID) {
|
function loadUserDB() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
var loadData = ["contacts", "pubKeys", "messages"]
|
var loadData = ["contacts", "pubKeys", "messages"]
|
||||||
var promises = []
|
var promises = []
|
||||||
for (var i = 0; i < loadData.length; i++)
|
for (var i = 0; i < loadData.length; i++)
|
||||||
promises[i] = compactIDB.readAllData(loadData[i], `floDapps#${floID}`)
|
promises[i] = compactIDB.readAllData(loadData[i], user.db_name)
|
||||||
Promise.all(promises).then(results => {
|
Promise.all(promises).then(results => {
|
||||||
for (var i = 0; i < loadData.length; i++)
|
for (var i = 0; i < loadData.length; i++)
|
||||||
floGlobals[loadData[i]] = results[i]
|
user[loadData[i]] = results[i]
|
||||||
resolve("Loaded Data from userDB")
|
resolve("Loaded Data from userDB")
|
||||||
}).catch(error => reject('Load userDB failed'))
|
}).catch(error => reject('Load userDB failed'))
|
||||||
})
|
})
|
||||||
@ -72,7 +208,7 @@
|
|||||||
|
|
||||||
startUpFunctions.push(function readSupernodeListFromAPI() {
|
startUpFunctions.push(function readSupernodeListFromAPI() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
compactIDB.readData("lastTx", floCloudAPI.SNStorageID, "floDapps").then(lastTx => {
|
compactIDB.readData("lastTx", floCloudAPI.SNStorageID, DEFAULT.root).then(lastTx => {
|
||||||
floBlockchainAPI.readData(floCloudAPI.SNStorageID, {
|
floBlockchainAPI.readData(floCloudAPI.SNStorageID, {
|
||||||
ignoreOld: lastTx,
|
ignoreOld: lastTx,
|
||||||
sentOnly: true,
|
sentOnly: true,
|
||||||
@ -80,14 +216,14 @@
|
|||||||
}).then(result => {
|
}).then(result => {
|
||||||
for (var i = result.data.length - 1; i >= 0; i--) {
|
for (var i = result.data.length - 1; i >= 0; i--) {
|
||||||
var content = JSON.parse(result.data[i]).SuperNodeStorage;
|
var content = JSON.parse(result.data[i]).SuperNodeStorage;
|
||||||
for (sn in content.removeNodes)
|
for (let sn in content.removeNodes)
|
||||||
compactIDB.removeData("supernodes", sn, "floDapps");
|
compactIDB.removeData("supernodes", sn, DEFAULT.root);
|
||||||
for (sn in content.newNodes)
|
for (let sn in content.newNodes)
|
||||||
compactIDB.writeData("supernodes", content.newNodes[sn], sn, "floDapps");
|
compactIDB.writeData("supernodes", content.newNodes[sn], sn, DEFAULT.root);
|
||||||
}
|
}
|
||||||
compactIDB.writeData("lastTx", result.totalTxs, floCloudAPI.SNStorageID, "floDapps");
|
compactIDB.writeData("lastTx", result.totalTxs, floCloudAPI.SNStorageID, DEFAULT.root);
|
||||||
compactIDB.readAllData("supernodes", "floDapps").then(result => {
|
compactIDB.readAllData("supernodes", DEFAULT.root).then(nodes => {
|
||||||
floCloudAPI.init(result)
|
floCloudAPI.init(nodes)
|
||||||
.then(result => resolve("Loaded Supernode list\n" + result))
|
.then(result => resolve("Loaded Supernode list\n" + result))
|
||||||
.catch(error => reject(error))
|
.catch(error => reject(error))
|
||||||
})
|
})
|
||||||
@ -98,14 +234,14 @@
|
|||||||
|
|
||||||
startUpFunctions.push(function readAppConfigFromAPI() {
|
startUpFunctions.push(function readAppConfigFromAPI() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
compactIDB.readData("lastTx", `${floGlobals.application}|${floGlobals.adminID}`, "floDapps").then(lastTx => {
|
compactIDB.readData("lastTx", `${DEFAULT.application}|${DEFAULT.adminID}`, DEFAULT.root).then(lastTx => {
|
||||||
floBlockchainAPI.readData(floGlobals.adminID, {
|
floBlockchainAPI.readData(DEFAULT.adminID, {
|
||||||
ignoreOld: lastTx,
|
ignoreOld: lastTx,
|
||||||
sentOnly: true,
|
sentOnly: true,
|
||||||
pattern: floGlobals.application
|
pattern: DEFAULT.application
|
||||||
}).then(result => {
|
}).then(result => {
|
||||||
for (var i = result.data.length - 1; i >= 0; i--) {
|
for (var i = result.data.length - 1; i >= 0; i--) {
|
||||||
var content = JSON.parse(result.data[i])[floGlobals.application];
|
var content = JSON.parse(result.data[i])[DEFAULT.application];
|
||||||
if (!content || typeof content !== "object")
|
if (!content || typeof content !== "object")
|
||||||
continue;
|
continue;
|
||||||
if (Array.isArray(content.removeSubAdmin))
|
if (Array.isArray(content.removeSubAdmin))
|
||||||
@ -118,11 +254,11 @@
|
|||||||
for (let l in content.settings)
|
for (let l in content.settings)
|
||||||
compactIDB.writeData("settings", content.settings[l], l)
|
compactIDB.writeData("settings", content.settings[l], l)
|
||||||
}
|
}
|
||||||
compactIDB.writeData("lastTx", result.totalTxs, `${floGlobals.application}|${floGlobals.adminID}`, "floDapps");
|
compactIDB.writeData("lastTx", result.totalTxs, `${DEFAULT.application}|${DEFAULT.adminID}`, DEFAULT.root);
|
||||||
compactIDB.readAllData("subAdmins").then(result => {
|
compactIDB.readAllData("subAdmins").then(result => {
|
||||||
floGlobals.subAdmins = Object.keys(result);
|
subAdmins = Object.keys(result);
|
||||||
compactIDB.readAllData("settings").then(result => {
|
compactIDB.readAllData("settings").then(result => {
|
||||||
floGlobals.settings = result;
|
settings = result;
|
||||||
resolve("Read app configuration from blockchain");
|
resolve("Read app configuration from blockchain");
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -186,7 +322,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
const getPrivateKeyCredentials = () => new Promise((resolve, reject) => {
|
const getPrivateKeyCredentials = () => new Promise((resolve, reject) => {
|
||||||
var indexArr = localStorage.getItem(`${floGlobals.application}#privKey`)
|
var indexArr = localStorage.getItem(`${DEFAULT.application}#privKey`)
|
||||||
if (indexArr) {
|
if (indexArr) {
|
||||||
readSharesFromIDB(JSON.parse(indexArr))
|
readSharesFromIDB(JSON.parse(indexArr))
|
||||||
.then(result => resolve(result))
|
.then(result => resolve(result))
|
||||||
@ -197,7 +333,7 @@
|
|||||||
if (!result)
|
if (!result)
|
||||||
return reject("Empty Private Key")
|
return reject("Empty Private Key")
|
||||||
var floID = floCrypto.getFloID(result)
|
var floID = floCrypto.getFloID(result)
|
||||||
if (!floID || !floCrypto.validateAddr(floID))
|
if (!floID || !floCrypto.validateFloID(floID))
|
||||||
return reject("Invalid Private Key")
|
return reject("Invalid Private Key")
|
||||||
privKey = result;
|
privKey = result;
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
@ -210,7 +346,7 @@
|
|||||||
var shares = floCrypto.createShamirsSecretShares(privKey, threshold, threshold)
|
var shares = floCrypto.createShamirsSecretShares(privKey, threshold, threshold)
|
||||||
writeSharesToIDB(shares).then(resultIndexes => {
|
writeSharesToIDB(shares).then(resultIndexes => {
|
||||||
//store index keys in localStorage
|
//store index keys in localStorage
|
||||||
localStorage.setItem(`${floGlobals.application}#privKey`, JSON.stringify(resultIndexes))
|
localStorage.setItem(`${DEFAULT.application}#privKey`, JSON.stringify(resultIndexes))
|
||||||
//also add a dummy privatekey to the IDB
|
//also add a dummy privatekey to the IDB
|
||||||
var randomPrivKey = floCrypto.generateNewID().privKey
|
var randomPrivKey = floCrypto.generateNewID().privKey
|
||||||
var randomThreshold = floCrypto.randInt(10, 20)
|
var randomThreshold = floCrypto.randInt(10, 20)
|
||||||
@ -242,9 +378,14 @@
|
|||||||
getPrivateKeyCredentials().then(key => {
|
getPrivateKeyCredentials().then(key => {
|
||||||
checkIfPinRequired(key).then(privKey => {
|
checkIfPinRequired(key).then(privKey => {
|
||||||
try {
|
try {
|
||||||
myPrivKey = privKey
|
user_public = floCrypto.getPubKeyHex(privKey);
|
||||||
myPubKey = floCrypto.getPubKeyHex(myPrivKey)
|
user_id = floCrypto.getAddress(privKey);
|
||||||
myFloID = floCrypto.getFloID(myPubKey)
|
floCloudAPI.user(user_id, privKey); //Set user for floCloudAPI
|
||||||
|
user_priv_wrap = () => checkIfPinRequired(key);
|
||||||
|
let n = floCrypto.randInt(12, 20);
|
||||||
|
aes_key = floCrypto.randString(n);
|
||||||
|
user_priv_raw = Crypto.AES.encrypt(privKey, aes_key);
|
||||||
|
user_private = user_priv_wrap;
|
||||||
resolve('Login Credentials loaded successful')
|
resolve('Login Credentials loaded successful')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
@ -305,8 +446,8 @@
|
|||||||
});
|
});
|
||||||
let p2 = new Promise((res, rej) => {
|
let p2 = new Promise((res, rej) => {
|
||||||
callAndLog(getCredentials()).then(r => {
|
callAndLog(getCredentials()).then(r => {
|
||||||
callAndLog(initUserDB(myFloID)).then(r => {
|
callAndLog(initUserDB()).then(r => {
|
||||||
callAndLog(loadUserDB(myFloID))
|
callAndLog(loadUserDB())
|
||||||
.then(r => res(true))
|
.then(r => res(true))
|
||||||
.catch(e => rej(false))
|
.catch(e => rej(false))
|
||||||
}).catch(e => rej(false))
|
}).catch(e => rej(false))
|
||||||
@ -315,7 +456,10 @@
|
|||||||
Promise.all([p1, p2])
|
Promise.all([p1, p2])
|
||||||
.then(r => resolve('App Startup finished successful'))
|
.then(r => resolve('App Startup finished successful'))
|
||||||
.catch(e => reject('App Startup failed'))
|
.catch(e => reject('App Startup failed'))
|
||||||
}).catch(error => reject("App database initiation failed"))
|
}).catch(error => {
|
||||||
|
startUpLog(false, error);
|
||||||
|
reject("App database initiation failed")
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,10 +475,10 @@
|
|||||||
|
|
||||||
floDapps.storeContact = function(floID, name) {
|
floDapps.storeContact = function(floID, name) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!floCrypto.validateAddr(floID))
|
if (!floCrypto.validateFloID(floID))
|
||||||
return reject("Invalid floID!")
|
return reject("Invalid floID!")
|
||||||
compactIDB.writeData("contacts", name, floID, `floDapps#${myFloID}`).then(result => {
|
compactIDB.writeData("contacts", name, floID, user.db_name).then(result => {
|
||||||
floGlobals.contacts[floID] = name;
|
user.contacts[floID] = name;
|
||||||
resolve("Contact stored")
|
resolve("Contact stored")
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
});
|
});
|
||||||
@ -342,14 +486,14 @@
|
|||||||
|
|
||||||
floDapps.storePubKey = function(floID, pubKey) {
|
floDapps.storePubKey = function(floID, pubKey) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (floID in floGlobals.pubKeys)
|
if (floID in user.pubKeys)
|
||||||
return resolve("pubKey already stored")
|
return resolve("pubKey already stored")
|
||||||
if (!floCrypto.validateAddr(floID))
|
if (!floCrypto.validateFloID(floID))
|
||||||
return reject("Invalid floID!")
|
return reject("Invalid floID!")
|
||||||
if (floCrypto.getFloID(pubKey) != floID)
|
if (floCrypto.getFloID(pubKey) != floID)
|
||||||
return reject("Incorrect pubKey")
|
return reject("Incorrect pubKey")
|
||||||
compactIDB.writeData("pubKeys", pubKey, floID, `floDapps#${myFloID}`).then(result => {
|
compactIDB.writeData("pubKeys", pubKey, floID, user.db_name).then(result => {
|
||||||
floGlobals.pubKeys[floID] = pubKey;
|
user.pubKeys[floID] = pubKey;
|
||||||
resolve("pubKey stored")
|
resolve("pubKey stored")
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
});
|
});
|
||||||
@ -359,11 +503,11 @@
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let options = {
|
let options = {
|
||||||
receiverID: floID,
|
receiverID: floID,
|
||||||
application: "floDapps",
|
application: DEFAULT.root,
|
||||||
comment: floGlobals.application
|
comment: DEFAULT.application
|
||||||
}
|
}
|
||||||
if (floID in floGlobals.pubKeys)
|
if (floID in user.pubKeys)
|
||||||
message = floCrypto.encryptData(JSON.stringify(message), floGlobals.pubKeys[floID])
|
message = floCrypto.encryptData(JSON.stringify(message), user.pubKeys[floID])
|
||||||
floCloudAPI.sendApplicationData(message, "Message", options)
|
floCloudAPI.sendApplicationData(message, "Message", options)
|
||||||
.then(result => resolve(result))
|
.then(result => resolve(result))
|
||||||
.catch(error => reject(error))
|
.catch(error => reject(error))
|
||||||
@ -372,20 +516,21 @@
|
|||||||
|
|
||||||
floDapps.requestInbox = function(callback) {
|
floDapps.requestInbox = function(callback) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let lastVC = Object.keys(floGlobals.messages).sort().pop()
|
let lastVC = Object.keys(user.messages).sort().pop()
|
||||||
let options = {
|
let options = {
|
||||||
receiverID: myFloID,
|
receiverID: user.id,
|
||||||
application: "floDapps",
|
application: DEFAULT.root,
|
||||||
lowerVectorClock: lastVC + 1
|
lowerVectorClock: lastVC + 1
|
||||||
}
|
}
|
||||||
|
let privKey = raw_user.private;
|
||||||
options.callback = (d, e) => {
|
options.callback = (d, e) => {
|
||||||
for (let v in d) {
|
for (let v in d) {
|
||||||
try {
|
try {
|
||||||
if (d[v].message instanceof Object && "secret" in d[v].message)
|
if (d[v].message instanceof Object && "secret" in d[v].message)
|
||||||
d[v].message = floCrypto.decryptData(d[v].message, myPrivKey)
|
d[v].message = floCrypto.decryptData(d[v].message, privKey)
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
compactIDB.writeData("messages", d[v], v, `floDapps#${myFloID}`)
|
compactIDB.writeData("messages", d[v], v, user.db_name)
|
||||||
floGlobals.messages[v] = d[v]
|
user.messages[v] = d[v]
|
||||||
}
|
}
|
||||||
if (callback instanceof Function)
|
if (callback instanceof Function)
|
||||||
callback(d, e)
|
callback(d, e)
|
||||||
@ -404,14 +549,14 @@
|
|||||||
if (!addList && !rmList && !settings)
|
if (!addList && !rmList && !settings)
|
||||||
return reject("No configuration change")
|
return reject("No configuration change")
|
||||||
var floData = {
|
var floData = {
|
||||||
[floGlobals.application]: {
|
[DEFAULT.application]: {
|
||||||
addSubAdmin: addList,
|
addSubAdmin: addList,
|
||||||
removeSubAdmin: rmList,
|
removeSubAdmin: rmList,
|
||||||
settings: settings
|
settings: settings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var floID = floCrypto.getFloID(adminPrivKey)
|
var floID = floCrypto.getFloID(adminPrivKey)
|
||||||
if (floID != floGlobals.adminID)
|
if (floID != DEFAULT.adminID)
|
||||||
reject('Access Denied for Admin privilege')
|
reject('Access Denied for Admin privilege')
|
||||||
else
|
else
|
||||||
floBlockchainAPI.writeData(floID, JSON.stringify(floData), adminPrivKey)
|
floBlockchainAPI.writeData(floID, JSON.stringify(floData), adminPrivKey)
|
||||||
@ -422,9 +567,9 @@
|
|||||||
|
|
||||||
const clearCredentials = floDapps.clearCredentials = function() {
|
const clearCredentials = floDapps.clearCredentials = function() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
compactIDB.clearData('credentials', floGlobals.application).then(result => {
|
compactIDB.clearData('credentials', DEFAULT.application).then(result => {
|
||||||
localStorage.removeItem(`${floGlobals.application}#privKey`)
|
localStorage.removeItem(`${DEFAULT.application}#privKey`);
|
||||||
myPrivKey = myPubKey = myFloID = undefined;
|
user.clear();
|
||||||
resolve("privKey credentials deleted!")
|
resolve("privKey credentials deleted!")
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
})
|
})
|
||||||
@ -433,7 +578,7 @@
|
|||||||
floDapps.deleteUserData = function(credentials = false) {
|
floDapps.deleteUserData = function(credentials = false) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let p = []
|
let p = []
|
||||||
p.push(compactIDB.deleteDB(`floDapps#${myFloID}`))
|
p.push(compactIDB.deleteDB(user.db_name))
|
||||||
if (credentials)
|
if (credentials)
|
||||||
p.push(clearCredentials())
|
p.push(clearCredentials())
|
||||||
Promise.all(p)
|
Promise.all(p)
|
||||||
@ -444,10 +589,10 @@
|
|||||||
|
|
||||||
floDapps.deleteAppData = function() {
|
floDapps.deleteAppData = function() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
compactIDB.deleteDB(floGlobals.application).then(result => {
|
compactIDB.deleteDB(DEFAULT.application).then(result => {
|
||||||
localStorage.removeItem(`${floGlobals.application}#privKey`)
|
localStorage.removeItem(`${DEFAULT.application}#privKey`)
|
||||||
myPrivKey = myPubKey = myFloID = undefined;
|
user.clear();
|
||||||
compactIDB.removeData('lastTx', `${floGlobals.application}|${floGlobals.adminID}`, 'floDapps')
|
compactIDB.removeData('lastTx', `${DEFAULT.application}|${DEFAULT.adminID}`, DEFAULT.root)
|
||||||
.then(result => resolve("App database(local) deleted"))
|
.then(result => resolve("App database(local) deleted"))
|
||||||
.catch(error => reject(error))
|
.catch(error => reject(error))
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
@ -455,17 +600,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
floDapps.securePrivKey = function(pwd) {
|
floDapps.securePrivKey = function(pwd) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
let indexArr = localStorage.getItem(`${floGlobals.application}#privKey`)
|
let indexArr = localStorage.getItem(`${DEFAULT.application}#privKey`)
|
||||||
if (!indexArr)
|
if (!indexArr)
|
||||||
return reject("PrivKey not found");
|
return reject("PrivKey not found");
|
||||||
indexArr = JSON.parse(indexArr)
|
indexArr = JSON.parse(indexArr)
|
||||||
let encryptedKey = Crypto.AES.encrypt(myPrivKey, pwd);
|
let encryptedKey = Crypto.AES.encrypt(await user.private, pwd);
|
||||||
let threshold = indexArr.length;
|
let threshold = indexArr.length;
|
||||||
let shares = floCrypto.createShamirsSecretShares(encryptedKey, threshold, threshold)
|
let shares = floCrypto.createShamirsSecretShares(encryptedKey, threshold, threshold)
|
||||||
let promises = [];
|
let promises = [];
|
||||||
let overwriteFn = (share, index) =>
|
let overwriteFn = (share, index) =>
|
||||||
compactIDB.writeData("credentials", share, index, floGlobals.application);
|
compactIDB.writeData("credentials", share, index, DEFAULT.application);
|
||||||
for (var i = 0; i < threshold; i++)
|
for (var i = 0; i < threshold; i++)
|
||||||
promises.push(overwriteFn(shares[i], indexArr[i]));
|
promises.push(overwriteFn(shares[i], indexArr[i]));
|
||||||
Promise.all(promises)
|
Promise.all(promises)
|
||||||
@ -494,7 +639,7 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
var indexArr = localStorage.getItem(`${floGlobals.application}#privKey`)
|
var indexArr = localStorage.getItem(`${DEFAULT.application}#privKey`)
|
||||||
console.info(indexArr)
|
console.info(indexArr)
|
||||||
if (!indexArr)
|
if (!indexArr)
|
||||||
reject('No login credentials found')
|
reject('No login credentials found')
|
||||||
@ -535,7 +680,7 @@
|
|||||||
filteredResult[d] = JSON.parse(JSON.stringify(floGlobals.generalData[fk][d]))
|
filteredResult[d] = JSON.parse(JSON.stringify(floGlobals.generalData[fk][d]))
|
||||||
}
|
}
|
||||||
if (options.decrypt) {
|
if (options.decrypt) {
|
||||||
let decryptionKey = (options.decrypt === true) ? myPrivKey : options.decrypt;
|
let decryptionKey = (options.decrypt === true) ? raw_user.private : options.decrypt;
|
||||||
if (!Array.isArray(decryptionKey))
|
if (!Array.isArray(decryptionKey))
|
||||||
decryptionKey = [decryptionKey];
|
decryptionKey = [decryptionKey];
|
||||||
for (let f in filteredResult) {
|
for (let f in filteredResult) {
|
||||||
@ -561,14 +706,14 @@
|
|||||||
|
|
||||||
syncData.oldDevice = () => new Promise((resolve, reject) => {
|
syncData.oldDevice = () => new Promise((resolve, reject) => {
|
||||||
let sync = {
|
let sync = {
|
||||||
contacts: floGlobals.contacts,
|
contacts: user.contacts,
|
||||||
pubKeys: floGlobals.pubKeys,
|
pubKeys: user.pubKeys,
|
||||||
messages: floGlobals.messages
|
messages: user.messages
|
||||||
}
|
}
|
||||||
let message = Crypto.AES.encrypt(JSON.stringify(sync), myPrivKey)
|
let message = Crypto.AES.encrypt(JSON.stringify(sync), raw_user.private)
|
||||||
let options = {
|
let options = {
|
||||||
receiverID: myFloID,
|
receiverID: user.id,
|
||||||
application: "floDapps"
|
application: DEFAULT.root
|
||||||
}
|
}
|
||||||
floCloudAPI.sendApplicationData(message, "syncData", options)
|
floCloudAPI.sendApplicationData(message, "syncData", options)
|
||||||
.then(result => resolve(result))
|
.then(result => resolve(result))
|
||||||
@ -577,20 +722,20 @@
|
|||||||
|
|
||||||
syncData.newDevice = () => new Promise((resolve, reject) => {
|
syncData.newDevice = () => new Promise((resolve, reject) => {
|
||||||
var options = {
|
var options = {
|
||||||
receiverID: myFloID,
|
receiverID: user.id,
|
||||||
senderID: myFloID,
|
senderID: user.id,
|
||||||
application: "floDapps",
|
application: DEFAULT.root,
|
||||||
mostRecent: true,
|
mostRecent: true,
|
||||||
}
|
}
|
||||||
floCloudAPI.requestApplicationData("syncData", options).then(response => {
|
floCloudAPI.requestApplicationData("syncData", options).then(response => {
|
||||||
let vc = Object.keys(response).sort().pop()
|
let vc = Object.keys(response).sort().pop()
|
||||||
let sync = JSON.parse(Crypto.AES.decrypt(response[vc].message, myPrivKey))
|
let sync = JSON.parse(Crypto.AES.decrypt(response[vc].message, raw_user.private))
|
||||||
let promises = []
|
let promises = []
|
||||||
let store = (key, val, obs) => promises.push(compactIDB.writeData(obs, val, key, `floDapps#${floID}`));
|
let store = (key, val, obs) => promises.push(compactIDB.writeData(obs, val, key, user.db_name));
|
||||||
["contacts", "pubKeys", "messages"].forEach(c => {
|
["contacts", "pubKeys", "messages"].forEach(c => {
|
||||||
for (let i in sync[c]) {
|
for (let i in sync[c]) {
|
||||||
store(i, sync[c][i], c)
|
store(i, sync[c][i], c)
|
||||||
floGlobals[c][i] = sync[c][i]
|
user[c][i] = sync[c][i]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
Promise.all(promises)
|
Promise.all(promises)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
(function(EXPORTS) { //floTokenAPI v1.0.3a
|
(function(EXPORTS) { //floTokenAPI v1.0.3b
|
||||||
/* Token Operator to send/receive tokens via blockchain using API calls*/
|
/* Token Operator to send/receive tokens via blockchain using API calls*/
|
||||||
'use strict';
|
'use strict';
|
||||||
const tokenAPI = EXPORTS;
|
const tokenAPI = EXPORTS;
|
||||||
@ -20,6 +20,13 @@
|
|||||||
|
|
||||||
if (floGlobals.currency) tokenAPI.currency = floGlobals.currency;
|
if (floGlobals.currency) tokenAPI.currency = floGlobals.currency;
|
||||||
|
|
||||||
|
Object.defineProperties(floGlobals, {
|
||||||
|
currency: {
|
||||||
|
get: () => DEFAULT.currency,
|
||||||
|
set: currency => DEFAULT.currency = currency
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const fetch_api = tokenAPI.fetch = function(apicall) {
|
const fetch_api = tokenAPI.fetch = function(apicall) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
console.log(DEFAULT.apiURL + apicall);
|
console.log(DEFAULT.apiURL + apicall);
|
||||||
|
|||||||
119
scripts/fn_ui.js
119
scripts/fn_ui.js
@ -13,11 +13,11 @@ const relativeTime = new RelativeTime({ style: 'narrow' });
|
|||||||
// use floDapps.storeContact() to store contacts that can be used by other apps on same device
|
// use floDapps.storeContact() to store contacts that can be used by other apps on same device
|
||||||
function syncUserData(obsName, data) {
|
function syncUserData(obsName, data) {
|
||||||
const dataToSend = Crypto.AES.encrypt(JSON.stringify(data), myPrivKey);
|
const dataToSend = Crypto.AES.encrypt(JSON.stringify(data), myPrivKey);
|
||||||
return floCloudAPI.sendApplicationData(dataToSend, obsName, { receiverID: myFloID });
|
return floCloudAPI.sendApplicationData(dataToSend, obsName, { receiverID: floDapps.user.id });
|
||||||
}
|
}
|
||||||
// store user data in separate IDB
|
// store user data in separate IDB
|
||||||
async function organizeSyncedData(obsName) {
|
async function organizeSyncedData(obsName) {
|
||||||
const fetchedData = await floCloudAPI.requestApplicationData(obsName, { mostRecent: true, senderIDs: [myFloID], receiverID: myFloID });
|
const fetchedData = await floCloudAPI.requestApplicationData(obsName, { mostRecent: true, senderIDs: [floDapps.user.id], receiverID: floDapps.user.id });
|
||||||
if (fetchedData.length && await compactIDB.readData(obsName, 'lastSyncTime') !== fetchedData[0].time) {
|
if (fetchedData.length && await compactIDB.readData(obsName, 'lastSyncTime') !== fetchedData[0].time) {
|
||||||
await compactIDB.clearData(obsName);
|
await compactIDB.clearData(obsName);
|
||||||
const dataToDecrypt = floCloudAPI.util.decodeMessage(fetchedData[0].message);
|
const dataToDecrypt = floCloudAPI.util.decodeMessage(fetchedData[0].message);
|
||||||
@ -94,13 +94,13 @@ function withdrawMoneyFromWallet() {
|
|||||||
if (!upiId)
|
if (!upiId)
|
||||||
return notify("Please add an UPI ID to continue", 'error');
|
return notify("Please add an UPI ID to continue", 'error');
|
||||||
buttonLoader('withdraw_rupee_button', true);
|
buttonLoader('withdraw_rupee_button', true);
|
||||||
getRef('withdrawal_blockchain_link').classList.add('hide');
|
getRef('withdrawal_blockchain_link').classList.add('hidden');
|
||||||
User.sendToken(cashier, amount, 'for token-to-cash').then(txid => {
|
User.sendToken(cashier, amount, 'for token-to-cash').then(txid => {
|
||||||
console.warn(`Withdraw ${amount} from cashier ${cashier}`, txid);
|
console.warn(`Withdraw ${amount} from cashier ${cashier}`, txid);
|
||||||
User.tokenToCash(cashier, amount, txid, upiId).then(result => {
|
User.tokenToCash(cashier, amount, txid, upiId).then(result => {
|
||||||
showChildElement('withdraw_wallet_process', 1);
|
showChildElement('withdraw_wallet_process', 1);
|
||||||
refreshBalance();
|
refreshBalance();
|
||||||
getRef('withdrawal_blockchain_link').classList.remove('hide');
|
getRef('withdrawal_blockchain_link').classList.remove('hidden');
|
||||||
getRef('withdrawal_blockchain_link').href = `https://flosight.duckdns.org/tx/${txid}`
|
getRef('withdrawal_blockchain_link').href = `https://flosight.duckdns.org/tx/${txid}`
|
||||||
console.log(result);
|
console.log(result);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
@ -121,7 +121,7 @@ function withdrawMoneyFromWallet() {
|
|||||||
function transferToExchange() {
|
function transferToExchange() {
|
||||||
const amount = parseFloat(getRef('exchange_transfer__amount').value.trim());
|
const amount = parseFloat(getRef('exchange_transfer__amount').value.trim());
|
||||||
buttonLoader('exchange_transfer__button', true);
|
buttonLoader('exchange_transfer__button', true);
|
||||||
floExchangeAPI.depositToken('rupee', amount, myFloID, 'FRJkPqdbbsug3TtQRAWviqvTL9Qr2EMnrm', myPrivKey).then(txid => {
|
floExchangeAPI.depositToken('rupee', amount, floDapps.user.id, 'FRJkPqdbbsug3TtQRAWviqvTL9Qr2EMnrm', myPrivKey).then(txid => {
|
||||||
console.log(txid);
|
console.log(txid);
|
||||||
showChildElement('exchange_transfer_process', 1);
|
showChildElement('exchange_transfer_process', 1);
|
||||||
getRef('exchange_transfer__success_message').textContent = `Transferred ${formatAmount(amount)} to exchange`;
|
getRef('exchange_transfer__success_message').textContent = `Transferred ${formatAmount(amount)} to exchange`;
|
||||||
@ -160,7 +160,7 @@ function saveUpiId() {
|
|||||||
getRef('saved_upi_ids_list').append(html.node`${render.savedUpiId(upiId)}`);
|
getRef('saved_upi_ids_list').append(html.node`${render.savedUpiId(upiId)}`);
|
||||||
} else if (pagesData.lastPage === 'home') {
|
} else if (pagesData.lastPage === 'home') {
|
||||||
getRef('select_withdraw_upi_id').append(render.savedUpiIdOption(upiId));
|
getRef('select_withdraw_upi_id').append(render.savedUpiIdOption(upiId));
|
||||||
getRef('select_withdraw_upi_id').parentNode.classList.remove('hide')
|
getRef('select_withdraw_upi_id').parentNode.classList.remove('hidden')
|
||||||
}
|
}
|
||||||
closePopup();
|
closePopup();
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
@ -231,9 +231,9 @@ const pendingTransactionsObserver = new MutationObserver((mutations) => {
|
|||||||
mutations.forEach(mutation => {
|
mutations.forEach(mutation => {
|
||||||
if (mutation.type === 'childList') {
|
if (mutation.type === 'childList') {
|
||||||
if (mutation.target.children.length)
|
if (mutation.target.children.length)
|
||||||
mutation.target.parentNode.classList.remove('hide')
|
mutation.target.parentNode.classList.remove('hidden')
|
||||||
else
|
else
|
||||||
mutation.target.parentNode.classList.add('hide')
|
mutation.target.parentNode.classList.add('hidden')
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -447,9 +447,9 @@ function confirmTopUp(button) {
|
|||||||
getRef('top_up__reason_selector').addEventListener('change', e => {
|
getRef('top_up__reason_selector').addEventListener('change', e => {
|
||||||
console.log(e.target.value);
|
console.log(e.target.value);
|
||||||
if (e.target.value === 'other') {
|
if (e.target.value === 'other') {
|
||||||
getRef('top_up__specified_reason').parentNode.classList.remove('hide');
|
getRef('top_up__specified_reason').parentNode.classList.remove('hidden');
|
||||||
} else {
|
} else {
|
||||||
getRef('top_up__specified_reason').parentNode.classList.add('hide');
|
getRef('top_up__specified_reason').parentNode.classList.add('hidden');
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
function declineTopUp() {
|
function declineTopUp() {
|
||||||
@ -546,15 +546,15 @@ const render = {
|
|||||||
let transactionReceiver
|
let transactionReceiver
|
||||||
let className
|
let className
|
||||||
let icon
|
let icon
|
||||||
if (sender === myFloID) {
|
if (sender === floDapps.user.id) {
|
||||||
className = 'transaction grid sent'
|
className = 'transaction grid sent'
|
||||||
transactionReceiver = `Sent to ${getFloIdTitle(receiver) || 'Myself'}`;
|
transactionReceiver = `Sent to ${getFloIdTitle(receiver) || 'Myself'}`;
|
||||||
icon = svg`<svg class="icon sent" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z"/></svg>`;
|
icon = svg`<svg class="icon sent" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z"/></svg>`;
|
||||||
} else if (receiver === myFloID) {
|
} else if (receiver === floDapps.user.id) {
|
||||||
className = 'transaction grid received'
|
className = 'transaction grid received'
|
||||||
transactionReceiver = `Received from ${getFloIdTitle(sender)}`;
|
transactionReceiver = `Received from ${getFloIdTitle(sender)}`;
|
||||||
icon = svg`<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"/></svg>`;
|
icon = svg`<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"/></svg>`;
|
||||||
} else { //This should not happen unless API returns transaction that does not involve myFloID
|
} else { //This should not happen unless API returns transaction that does not involve floDapps.user.id
|
||||||
return html`sender: ${sender} | receiver: ${receiver}`;
|
return html`sender: ${sender} | receiver: ${receiver}`;
|
||||||
}
|
}
|
||||||
return html.node`
|
return html.node`
|
||||||
@ -634,7 +634,7 @@ const render = {
|
|||||||
},
|
},
|
||||||
transactionMessage(details) {
|
transactionMessage(details) {
|
||||||
const { tokenAmount, time, sender, receiver, flodata } = floTokenAPI.util.parseTxData(details)
|
const { tokenAmount, time, sender, receiver, flodata } = floTokenAPI.util.parseTxData(details)
|
||||||
let messageType = sender === receiver ? 'self' : sender === myFloID ? 'sent' : 'received';
|
let messageType = sender === receiver ? 'self' : sender === floDapps.user.id ? 'sent' : 'received';
|
||||||
const clone = getRef('transaction_message_template').content.cloneNode(true).firstElementChild;
|
const clone = getRef('transaction_message_template').content.cloneNode(true).firstElementChild;
|
||||||
clone.classList.add(messageType);
|
clone.classList.add(messageType);
|
||||||
clone.querySelector('.transaction-message__amount').textContent = formatAmount(tokenAmount);
|
clone.querySelector('.transaction-message__amount').textContent = formatAmount(tokenAmount);
|
||||||
@ -677,7 +677,7 @@ const render = {
|
|||||||
if (rupeeHistoryLoader)
|
if (rupeeHistoryLoader)
|
||||||
rupeeHistoryLoader.clear()
|
rupeeHistoryLoader.clear()
|
||||||
getRef('payments_history').innerHTML = '<sm-spinner></sm-spinner>';
|
getRef('payments_history').innerHTML = '<sm-spinner></sm-spinner>';
|
||||||
floTokenAPI.getAllTxs(myFloID).then(({ transactions }) => {
|
floTokenAPI.getAllTxs(floDapps.user.id).then(({ transactions }) => {
|
||||||
for (const transactionId in transactions) {
|
for (const transactionId in transactions) {
|
||||||
paymentTransactions.push({
|
paymentTransactions.push({
|
||||||
...floTokenAPI.util.parseTxData(transactions[transactionId]),
|
...floTokenAPI.util.parseTxData(transactions[transactionId]),
|
||||||
@ -687,7 +687,7 @@ const render = {
|
|||||||
const filter = getRef('payments_type_filter').querySelector('input:checked').value;
|
const filter = getRef('payments_type_filter').querySelector('input:checked').value;
|
||||||
if (filter !== 'all') {
|
if (filter !== 'all') {
|
||||||
let propToCheck = filter === 'sent' ? 'sender' : 'receiver';
|
let propToCheck = filter === 'sent' ? 'sender' : 'receiver';
|
||||||
paymentTransactions = paymentTransactions.filter(v => v[propToCheck] === myFloID)
|
paymentTransactions = paymentTransactions.filter(v => v[propToCheck] === floDapps.user.id)
|
||||||
}
|
}
|
||||||
// solve sorting issue at backend
|
// solve sorting issue at backend
|
||||||
paymentTransactions.sort((a, b) => b.time - a.time);
|
paymentTransactions.sort((a, b) => b.time - a.time);
|
||||||
@ -737,7 +737,7 @@ const render = {
|
|||||||
try {
|
try {
|
||||||
// render transactions
|
// render transactions
|
||||||
getRef('payments_history').innerHTML = '<sm-spinner class="justify-self-center margin-top-1-5"></sm-spinner>';
|
getRef('payments_history').innerHTML = '<sm-spinner class="justify-self-center margin-top-1-5"></sm-spinner>';
|
||||||
getAddressDetails( btc_api.convert.legacy2bech(myFloID)).then(result => {
|
getAddressDetails( btc_api.convert.legacy2bech(floDapps.user.id)).then(result => {
|
||||||
if (result.txs.length) {
|
if (result.txs.length) {
|
||||||
let allTransactions = result.txs;
|
let allTransactions = result.txs;
|
||||||
const filter = getRef('payments_type_filter').querySelector('input:checked').value;
|
const filter = getRef('payments_type_filter').querySelector('input:checked').value;
|
||||||
@ -811,13 +811,13 @@ function buttonLoader(id, show) {
|
|||||||
async function refreshBalance(button) {
|
async function refreshBalance(button) {
|
||||||
if (button)
|
if (button)
|
||||||
buttonLoader(button, true)
|
buttonLoader(button, true)
|
||||||
floTokenAPI.getBalance(myFloID).then((balance = 0) => {
|
floTokenAPI.getBalance(floDapps.user.id).then((balance = 0) => {
|
||||||
const [beforeDecimal, afterDecimal] = formatAmount(balance).split('₹')[1].split('.')
|
const [beforeDecimal, afterDecimal] = formatAmount(balance).split('₹')[1].split('.')
|
||||||
renderElem(getRef('rupee_balance'), html`<span><b>${beforeDecimal}</b></span>.<span>${afterDecimal}</span>`)
|
renderElem(getRef('rupee_balance'), html`<span><b>${beforeDecimal}</b></span>.<span>${afterDecimal}</span>`)
|
||||||
if (button)
|
if (button)
|
||||||
buttonLoader(button, false)
|
buttonLoader(button, false)
|
||||||
})
|
})
|
||||||
btc_api.getBalance(btc_api.convert.legacy2bech(myFloID)).then(btcBalance => {
|
btc_api.getBalance(btc_api.convert.legacy2bech(floDapps.user.id)).then(btcBalance => {
|
||||||
if(btcBalance) {
|
if(btcBalance) {
|
||||||
const [beforeDecimal, afterDecimal = '00'] = String(btcBalance).split('.')
|
const [beforeDecimal, afterDecimal = '00'] = String(btcBalance).split('.')
|
||||||
renderElem(getRef('btc_balance'), html`<span><b>${beforeDecimal}</b></span>.<span>${afterDecimal}</span>`)
|
renderElem(getRef('btc_balance'), html`<span><b>${beforeDecimal}</b></span>.<span>${afterDecimal}</span>`)
|
||||||
@ -826,14 +826,14 @@ async function refreshBalance(button) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
try {
|
try {
|
||||||
const [floBal, floRates] = await Promise.all([floBlockchainAPI.getBalance(myFloID), floExchangeAPI.getRates('FLO')])
|
const [floBal, floRates] = await Promise.all([floBlockchainAPI.getBalance(floDapps.user.id), floExchangeAPI.getRates('FLO')])
|
||||||
const [beforeDecimal, afterDecimal = '00'] = String(floBal).split('.')
|
const [beforeDecimal, afterDecimal = '00'] = String(floBal).split('.')
|
||||||
renderElem(getRef('flo_balance'), html`<span><b>${beforeDecimal}</b></span>.<span>${afterDecimal}</span>`)
|
renderElem(getRef('flo_balance'), html`<span><b>${beforeDecimal}</b></span>.<span>${afterDecimal}</span>`)
|
||||||
if (floBal < floGlobals.settings.user_flo_threshold) {
|
if (floBal < floGlobals.settings.user_flo_threshold) {
|
||||||
getRef('low_user_flo_warning').textContent = `Your FLO balance is low. You will receive ${floGlobals.settings.send_user_flo} FLO of worth ₹${parseFloat(floRates.rate.toFixed(2))} deducted from top-up amount.`;
|
getRef('low_user_flo_warning').textContent = `Your FLO balance is low. You will receive ${floGlobals.settings.send_user_flo} FLO of worth ₹${parseFloat(floRates.rate.toFixed(2))} deducted from top-up amount.`;
|
||||||
getRef('low_user_flo_warning').classList.remove('hide');
|
getRef('low_user_flo_warning').classList.remove('hidden');
|
||||||
} else {
|
} else {
|
||||||
getRef('low_user_flo_warning').classList.add('hide');
|
getRef('low_user_flo_warning').classList.add('hidden');
|
||||||
}
|
}
|
||||||
if (button)
|
if (button)
|
||||||
buttonLoader(button, false)
|
buttonLoader(button, false)
|
||||||
@ -969,7 +969,7 @@ function deleteSavedId() {
|
|||||||
}
|
}
|
||||||
const savedIdsObserver = new MutationObserver((mutationList) => {
|
const savedIdsObserver = new MutationObserver((mutationList) => {
|
||||||
mutationList.forEach(mutation => {
|
mutationList.forEach(mutation => {
|
||||||
conditionalClassToggle(getRef('saved_ids_tip'), 'hide', !mutation.target.children.length);
|
conditionalClassToggle(getRef('saved_ids_tip'), 'hidden', !mutation.target.children.length);
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -1031,10 +1031,10 @@ function showTokenTransfer(type) {
|
|||||||
if (pagesData.lastPage === 'contact') {
|
if (pagesData.lastPage === 'contact') {
|
||||||
getRef('token_transfer__receiver').value = pagesData.params.floId;
|
getRef('token_transfer__receiver').value = pagesData.params.floId;
|
||||||
getRef('token_transfer__receiver').readOnly = true;
|
getRef('token_transfer__receiver').readOnly = true;
|
||||||
getRef('token_transfer__receiver').querySelector('button').classList.add('hide');
|
getRef('token_transfer__receiver').querySelector('button').classList.add('hidden');
|
||||||
} else {
|
} else {
|
||||||
getRef('token_transfer__receiver').readOnly = false;
|
getRef('token_transfer__receiver').readOnly = false;
|
||||||
getRef('token_transfer__receiver').querySelector('button').classList.remove('hide');
|
getRef('token_transfer__receiver').querySelector('button').classList.remove('hidden');
|
||||||
}
|
}
|
||||||
openPopup('token_transfer_popup');
|
openPopup('token_transfer_popup');
|
||||||
if (pagesData.lastPage === 'contact') {
|
if (pagesData.lastPage === 'contact') {
|
||||||
@ -1091,8 +1091,8 @@ function toggleFilters() {
|
|||||||
easing: 'ease',
|
easing: 'ease',
|
||||||
fill: 'forwards',
|
fill: 'forwards',
|
||||||
}
|
}
|
||||||
if (getRef('history_applied_filters_wrapper').classList.contains('hide') && getRef('history_applied_filters').children.length > 0) {
|
if (getRef('history_applied_filters_wrapper').classList.contains('hidden') && getRef('history_applied_filters').children.length > 0) {
|
||||||
getRef('history_applied_filters_wrapper').classList.remove('hide')
|
getRef('history_applied_filters_wrapper').classList.remove('hidden')
|
||||||
const filtersContainerDimensions = getRef('history_applied_filters_wrapper').getBoundingClientRect();
|
const filtersContainerDimensions = getRef('history_applied_filters_wrapper').getBoundingClientRect();
|
||||||
getRef('history_applied_filters_wrapper').animate([
|
getRef('history_applied_filters_wrapper').animate([
|
||||||
{
|
{
|
||||||
@ -1108,7 +1108,7 @@ function toggleFilters() {
|
|||||||
{ transform: `translateY(-${filtersContainerDimensions.height}px)` },
|
{ transform: `translateY(-${filtersContainerDimensions.height}px)` },
|
||||||
{ transform: `translateY(0)` },
|
{ transform: `translateY(0)` },
|
||||||
], animOptions)
|
], animOptions)
|
||||||
} else if (!getRef('history_applied_filters_wrapper').classList.contains('hide') && getRef('history_applied_filters').children.length === 0) {
|
} else if (!getRef('history_applied_filters_wrapper').classList.contains('hidden') && getRef('history_applied_filters').children.length === 0) {
|
||||||
getRef('history_applied_filters_wrapper').animate([
|
getRef('history_applied_filters_wrapper').animate([
|
||||||
{
|
{
|
||||||
transform: `translateY(0)`,
|
transform: `translateY(0)`,
|
||||||
@ -1120,7 +1120,7 @@ function toggleFilters() {
|
|||||||
},
|
},
|
||||||
], animOptions)
|
], animOptions)
|
||||||
.onfinish = () => {
|
.onfinish = () => {
|
||||||
getRef('history_applied_filters_wrapper').classList.add('hide')
|
getRef('history_applied_filters_wrapper').classList.add('hidden')
|
||||||
}
|
}
|
||||||
const filtersContainerDimensions = getRef('history_applied_filters_wrapper').getBoundingClientRect();
|
const filtersContainerDimensions = getRef('history_applied_filters_wrapper').getBoundingClientRect();
|
||||||
const historyDimensions = getRef('payments_history').getBoundingClientRect();
|
const historyDimensions = getRef('payments_history').getBoundingClientRect();
|
||||||
@ -1184,7 +1184,7 @@ delegate(getRef('history_applied_filters'), 'click', '.applied-filter', e => {
|
|||||||
function changeUpi() {
|
function changeUpi() {
|
||||||
const upiId = getRef('upi_id').value.trim();
|
const upiId = getRef('upi_id').value.trim();
|
||||||
Cashier.updateUPI(upiId).then(() => {
|
Cashier.updateUPI(upiId).then(() => {
|
||||||
getRef('my_upi_id').classList.remove('hide')
|
getRef('my_upi_id').classList.remove('hidden')
|
||||||
getRef('my_upi_id').value = upiId;
|
getRef('my_upi_id').value = upiId;
|
||||||
getRef('change_upi_button').textContent = 'Change UPI ID';
|
getRef('change_upi_button').textContent = 'Change UPI ID';
|
||||||
notify('UPI ID updated successfully', 'success');
|
notify('UPI ID updated successfully', 'success');
|
||||||
@ -1195,31 +1195,36 @@ function changeUpi() {
|
|||||||
}
|
}
|
||||||
function getSignedIn(passwordType) {
|
function getSignedIn(passwordType) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (passwordType === 'PIN/Password') {
|
try {
|
||||||
getRef('private_key_field').removeAttribute('data-private-key');
|
console.log(floDapps.user.id)
|
||||||
getRef('private_key_field').setAttribute('placeholder', 'PIN');
|
|
||||||
getRef('private_key_field').customValidation = null
|
}catch(err) {
|
||||||
|
if (passwordType === 'PIN/Password') {
|
||||||
} else {
|
getRef('private_key_field').removeAttribute('data-private-key');
|
||||||
getRef('private_key_field').dataset.privateKey = ''
|
getRef('private_key_field').setAttribute('placeholder', 'Password');
|
||||||
getRef('private_key_field').setAttribute('placeholder', 'FLO private key');
|
getRef('private_key_field').customValidation = null
|
||||||
getRef('private_key_field').customValidation = floCrypto.getPubKeyHex
|
|
||||||
|
} else {
|
||||||
|
getRef('private_key_field').dataset.privateKey = ''
|
||||||
|
getRef('private_key_field').setAttribute('placeholder', 'FLO private key');
|
||||||
|
getRef('private_key_field').customValidation = floCrypto.getPubKeyHex
|
||||||
|
}
|
||||||
|
if (window.location.hash.includes('sign_in') || window.location.hash.includes('sign_up')) {
|
||||||
|
showPage(window.location.hash);
|
||||||
|
} else {
|
||||||
|
location.hash = `#/sign_in`;
|
||||||
|
}
|
||||||
|
getRef('sign_in_button').onclick = () => {
|
||||||
|
resolve(getRef('private_key_field').value.trim());
|
||||||
|
getRef('private_key_field').value = '';
|
||||||
|
showPage('loading');
|
||||||
|
};
|
||||||
|
getRef('sign_up_button').onclick = () => {
|
||||||
|
resolve(getRef('generated_private_key').value.trim());
|
||||||
|
getRef('generated_private_key').value = '';
|
||||||
|
showPage('loading');
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (window.location.hash.includes('sign_in') || window.location.hash.includes('sign_up')) {
|
|
||||||
showPage(window.location.hash);
|
|
||||||
} else {
|
|
||||||
location.hash = `#/sign_in`;
|
|
||||||
}
|
|
||||||
getRef('sign_in_button').onclick = () => {
|
|
||||||
resolve(getRef('private_key_field').value.trim());
|
|
||||||
getRef('private_key_field').value = '';
|
|
||||||
showPage('loading');
|
|
||||||
};
|
|
||||||
getRef('sign_up_button').onclick = () => {
|
|
||||||
resolve(getRef('generated_private_key').value.trim());
|
|
||||||
getRef('generated_private_key').value = '';
|
|
||||||
showPage('loading');
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function signOut() {
|
function signOut() {
|
||||||
@ -1369,7 +1374,7 @@ getRef('fees_selector').addEventListener('change', e => {
|
|||||||
|
|
||||||
getRef('send_transaction').onclick = evt => {
|
getRef('send_transaction').onclick = evt => {
|
||||||
buttonLoader('send_transaction', true)
|
buttonLoader('send_transaction', true)
|
||||||
const senders = btc_api.convert.legacy2bech(myFloID);
|
const senders = btc_api.convert.legacy2bech(floDapps.user.id);
|
||||||
const privKeys = btc_api.convert.wif(myPrivKey);
|
const privKeys = btc_api.convert.wif(myPrivKey);
|
||||||
const receivers = [...getRef('receiver_container').querySelectorAll('.receiver-input')].map(input => input.value.trim());
|
const receivers = [...getRef('receiver_container').querySelectorAll('.receiver-input')].map(input => input.value.trim());
|
||||||
const amounts = [...getRef('receiver_container').querySelectorAll('.amount-input')].map(input => {
|
const amounts = [...getRef('receiver_container').querySelectorAll('.amount-input')].map(input => {
|
||||||
@ -1400,7 +1405,7 @@ function convertAsset() {
|
|||||||
const fromAsset = getRef('from_asset_selector').value;
|
const fromAsset = getRef('from_asset_selector').value;
|
||||||
const fromAmount = parseFloat(getRef('from_amount').value.trim());
|
const fromAmount = parseFloat(getRef('from_amount').value.trim());
|
||||||
if (fromAsset === 'BTC') {
|
if (fromAsset === 'BTC') {
|
||||||
btc_api.getBalance(btc_api.convert.legacy2bech(myFloID)).then(btcBalance => {
|
btc_api.getBalance(btc_api.convert.legacy2bech(floDapps.user.id)).then(btcBalance => {
|
||||||
if (btcBalance < fromAmount) {
|
if (btcBalance < fromAmount) {
|
||||||
notify('You do not have enough BTC to convert', 'error');
|
notify('You do not have enough BTC to convert', 'error');
|
||||||
buttonLoader('convert_asset_button', false)
|
buttonLoader('convert_asset_button', false)
|
||||||
@ -1408,7 +1413,7 @@ function convertAsset() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
floTokenAPI.getBalance(myFloID).then((balance = 0) => {
|
floTokenAPI.getBalance(floDapps.user.id).then((balance = 0) => {
|
||||||
if(balance < fromAmount) {
|
if(balance < fromAmount) {
|
||||||
notify('You do not have enough rupee tokens to convert', 'error');
|
notify('You do not have enough rupee tokens to convert', 'error');
|
||||||
buttonLoader('convert_asset_button', false)
|
buttonLoader('convert_asset_button', false)
|
||||||
|
|||||||
2574
scripts/lib.js
2574
scripts/lib.js
File diff suppressed because it is too large
Load Diff
@ -109,7 +109,7 @@ document.addEventListener('popupopened', async e => {
|
|||||||
if (hasSavedIds) {
|
if (hasSavedIds) {
|
||||||
const clone = frag.cloneNode(true)
|
const clone = frag.cloneNode(true)
|
||||||
getRef('select_withdraw_upi_id').append(clone)
|
getRef('select_withdraw_upi_id').append(clone)
|
||||||
getRef('select_withdraw_upi_id').parentNode.classList.remove('hide')
|
getRef('select_withdraw_upi_id').parentNode.classList.remove('hidden')
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'send_btc_popup':
|
case 'send_btc_popup':
|
||||||
@ -128,7 +128,7 @@ document.addEventListener('popupclosed', e => {
|
|||||||
showChildElement('topup_wallet_process', 0)
|
showChildElement('topup_wallet_process', 0)
|
||||||
break;
|
break;
|
||||||
case 'withdraw_wallet_popup':
|
case 'withdraw_wallet_popup':
|
||||||
getRef('select_withdraw_upi_id').parentNode.classList.add('hide')
|
getRef('select_withdraw_upi_id').parentNode.classList.add('hidden')
|
||||||
getRef('select_withdraw_upi_id').innerHTML = ''
|
getRef('select_withdraw_upi_id').innerHTML = ''
|
||||||
showChildElement('withdraw_wallet_process', 0)
|
showChildElement('withdraw_wallet_process', 0)
|
||||||
break;
|
break;
|
||||||
@ -292,7 +292,7 @@ window.addEventListener("load", () => {
|
|||||||
} else {
|
} else {
|
||||||
notify('Browser is not fully compatible, some features may not work. for best experience please use Chrome, Edge, Firefox or Safari', 'error')
|
notify('Browser is not fully compatible, some features may not work. for best experience please use Chrome, Edge, Firefox or Safari', 'error')
|
||||||
}
|
}
|
||||||
document.body.classList.remove('hide')
|
document.body.classList.remove('hidden')
|
||||||
document.querySelectorAll('sm-input[data-flo-id]').forEach(input => input.customValidation = floCrypto.validateAddr)
|
document.querySelectorAll('sm-input[data-flo-id]').forEach(input => input.customValidation = floCrypto.validateAddr)
|
||||||
document.addEventListener('keyup', (e) => {
|
document.addEventListener('keyup', (e) => {
|
||||||
if (e.key === 'Escape') {
|
if (e.key === 'Escape') {
|
||||||
@ -356,10 +356,11 @@ async function showPage(targetPage, options = {}) {
|
|||||||
let params = {}
|
let params = {}
|
||||||
let searchParams
|
let searchParams
|
||||||
if (targetPage === '') {
|
if (targetPage === '') {
|
||||||
if (typeof myFloID === "undefined") {
|
try {
|
||||||
|
if(floDapps.user.id)
|
||||||
|
pageId = 'home'
|
||||||
|
}catch(e){
|
||||||
pageId = 'sign_in'
|
pageId = 'sign_in'
|
||||||
} else {
|
|
||||||
pageId = 'home'
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (targetPage.includes('/')) {
|
if (targetPage.includes('/')) {
|
||||||
@ -378,10 +379,13 @@ async function showPage(targetPage, options = {}) {
|
|||||||
pageId = targetPage
|
pageId = targetPage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (typeof myFloID === "undefined" && !(['sign_up', 'sign_in', 'loading', 'landing'].includes(pageId))) return
|
try {
|
||||||
else if (typeof myFloID !== "undefined" && (['sign_up', 'sign_in', 'loading', 'landing'].includes(pageId))) {
|
if (floDapps.user.id && (['sign_up', 'sign_in', 'loading', 'landing'].includes(pageId))) {
|
||||||
history.replaceState(null, null, '#/home');
|
history.replaceState(null, null, '#/home');
|
||||||
pageId = 'home'
|
pageId = 'home'
|
||||||
|
}
|
||||||
|
}catch(e){
|
||||||
|
if ( !(['sign_up', 'sign_in', 'loading', 'landing'].includes(pageId))) return
|
||||||
}
|
}
|
||||||
if (searchParams) {
|
if (searchParams) {
|
||||||
const urlSearchParams = new URLSearchParams('?' + searchParams);
|
const urlSearchParams = new URLSearchParams('?' + searchParams);
|
||||||
@ -400,7 +404,6 @@ async function showPage(targetPage, options = {}) {
|
|||||||
break;
|
break;
|
||||||
case 'home':
|
case 'home':
|
||||||
getExchangeRate().then(rate => {
|
getExchangeRate().then(rate => {
|
||||||
console.log(rate)
|
|
||||||
getRef('conversion_rate').textContent = `1BTC = ${formatAmount(rate.inr)}`;
|
getRef('conversion_rate').textContent = `1BTC = ${formatAmount(rate.inr)}`;
|
||||||
})
|
})
|
||||||
break;
|
break;
|
||||||
@ -408,8 +411,8 @@ async function showPage(targetPage, options = {}) {
|
|||||||
getRef('contact__title').textContent = getFloIdTitle(params.floId)
|
getRef('contact__title').textContent = getFloIdTitle(params.floId)
|
||||||
getRef('contact__transactions').innerHTML = '<sm-spinner></sm-spinner>'
|
getRef('contact__transactions').innerHTML = '<sm-spinner></sm-spinner>'
|
||||||
Promise.all([
|
Promise.all([
|
||||||
floTokenAPI.fetch(`api/v1.0/getTokenTransactions?token=rupee&senderFloAddress=${myFloID}&destFloAddress=${params.floId}`),
|
floTokenAPI.fetch(`api/v1.0/getTokenTransactions?token=rupee&senderFloAddress=${floDapps.user.id}&destFloAddress=${params.floId}`),
|
||||||
floTokenAPI.fetch(`api/v1.0/getTokenTransactions?token=rupee&senderFloAddress=${params.floId}&destFloAddress=${myFloID}`)])
|
floTokenAPI.fetch(`api/v1.0/getTokenTransactions?token=rupee&senderFloAddress=${params.floId}&destFloAddress=${floDapps.user.id}`)])
|
||||||
.then(([sentTransactions, receivedTransactions]) => {
|
.then(([sentTransactions, receivedTransactions]) => {
|
||||||
const allTransactions = Object.values({ ...sentTransactions.transactions, ...receivedTransactions.transactions }).sort((a, b) => b.transactionDetails.time - a.transactionDetails.time)
|
const allTransactions = Object.values({ ...sentTransactions.transactions, ...receivedTransactions.transactions }).sort((a, b) => b.transactionDetails.time - a.transactionDetails.time)
|
||||||
if (contactHistoryLoader) {
|
if (contactHistoryLoader) {
|
||||||
@ -585,9 +588,9 @@ async function showPage(targetPage, options = {}) {
|
|||||||
const currentActiveElement = document.querySelector(`.nav-item[href="#/${pageId}"]`)
|
const currentActiveElement = document.querySelector(`.nav-item[href="#/${pageId}"]`)
|
||||||
if (currentActiveElement) {
|
if (currentActiveElement) {
|
||||||
getRef('main_card').classList.remove('nav-hidden')
|
getRef('main_card').classList.remove('nav-hidden')
|
||||||
if (getRef('main_navbar').classList.contains('hide')) {
|
if (getRef('main_navbar').classList.contains('hidden')) {
|
||||||
getRef('main_navbar').classList.remove('hide-away')
|
getRef('main_navbar').classList.remove('hide-away')
|
||||||
getRef('main_navbar').classList.remove('hide')
|
getRef('main_navbar').classList.remove('hidden')
|
||||||
getRef('main_navbar').animate([
|
getRef('main_navbar').animate([
|
||||||
{
|
{
|
||||||
transform: isMobileView ? `translateY(100%)` : `translateX(-100%)`,
|
transform: isMobileView ? `translateY(100%)` : `translateX(-100%)`,
|
||||||
@ -642,7 +645,7 @@ async function showPage(targetPage, options = {}) {
|
|||||||
currentActiveElement.classList.add('nav-item--active')
|
currentActiveElement.classList.add('nav-item--active')
|
||||||
} else {
|
} else {
|
||||||
getRef('main_card').classList.add('nav-hidden')
|
getRef('main_card').classList.add('nav-hidden')
|
||||||
if (!getRef('main_navbar').classList.contains('hide')) {
|
if (!getRef('main_navbar').classList.contains('hidden')) {
|
||||||
getRef('main_navbar').classList.add('hide-away')
|
getRef('main_navbar').classList.add('hide-away')
|
||||||
getRef('main_navbar').animate([
|
getRef('main_navbar').animate([
|
||||||
{
|
{
|
||||||
@ -658,14 +661,14 @@ async function showPage(targetPage, options = {}) {
|
|||||||
fill: 'forwards',
|
fill: 'forwards',
|
||||||
easing: 'ease'
|
easing: 'ease'
|
||||||
}).onfinish = () => {
|
}).onfinish = () => {
|
||||||
getRef('main_navbar').classList.add('hide')
|
getRef('main_navbar').classList.add('hidden')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
document.querySelectorAll('.page').forEach(page => page.classList.add('hide'))
|
document.querySelectorAll('.page').forEach(page => page.classList.add('hidden'))
|
||||||
getRef(pageId).closest('.page').classList.remove('hide')
|
getRef(pageId).closest('.page').classList.remove('hidden')
|
||||||
document.querySelectorAll('.inner-page').forEach(page => page.classList.add('hide'))
|
document.querySelectorAll('.inner-page').forEach(page => page.classList.add('hidden'))
|
||||||
getRef(pageId).classList.remove('hide')
|
getRef(pageId).classList.remove('hidden')
|
||||||
getRef('main_card').style.overflowY = "hidden";
|
getRef('main_card').style.overflowY = "hidden";
|
||||||
getRef(pageId).animate([
|
getRef(pageId).animate([
|
||||||
{
|
{
|
||||||
@ -849,22 +852,22 @@ function showChildElement(id, index, options = {}) {
|
|||||||
easing: 'ease',
|
easing: 'ease',
|
||||||
fill: 'forwards'
|
fill: 'forwards'
|
||||||
}
|
}
|
||||||
const visibleElement = [...getRef(id).children].find(elem => !elem.classList.contains(mobileView ? 'hide-on-mobile' : 'hide'));
|
const visibleElement = [...getRef(id).children].find(elem => !elem.classList.contains(mobileView ? 'hide-on-mobile' : 'hidden'));
|
||||||
if (visibleElement === getRef(id).children[index]) return;
|
if (visibleElement === getRef(id).children[index]) return;
|
||||||
if (visibleElement) {
|
if (visibleElement) {
|
||||||
if (exit) {
|
if (exit) {
|
||||||
visibleElement.animate(exit, animOptions).onfinish = () => {
|
visibleElement.animate(exit, animOptions).onfinish = () => {
|
||||||
visibleElement.classList.add(mobileView ? 'hide-on-mobile' : 'hide')
|
visibleElement.classList.add(mobileView ? 'hide-on-mobile' : 'hidden')
|
||||||
getRef(id).children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hide')
|
getRef(id).children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hidden')
|
||||||
if (entry)
|
if (entry)
|
||||||
getRef(id).children[index].animate(entry, animOptions)
|
getRef(id).children[index].animate(entry, animOptions)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
visibleElement.classList.add(mobileView ? 'hide-on-mobile' : 'hide')
|
visibleElement.classList.add(mobileView ? 'hide-on-mobile' : 'hidden')
|
||||||
getRef(id).children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hide')
|
getRef(id).children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hidden')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
getRef(id).children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hide')
|
getRef(id).children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hidden')
|
||||||
getRef(id).children[index].animate(entry, animOptions)
|
getRef(id).children[index].animate(entry, animOptions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user