updated std ops

This commit is contained in:
sairaj mote 2022-08-16 02:22:07 +05:30
parent cca538ddf5
commit 2e753968b8
12 changed files with 3193 additions and 273 deletions

View File

@ -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

File diff suppressed because one or more lines are too long

View File

@ -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;
} }

View File

@ -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))

View File

@ -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);

View File

@ -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))

View File

@ -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 {

View File

@ -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)

View File

@ -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);

View File

@ -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
} else { }catch(err) {
getRef('private_key_field').dataset.privateKey = '' if (passwordType === 'PIN/Password') {
getRef('private_key_field').setAttribute('placeholder', 'FLO private key'); getRef('private_key_field').removeAttribute('data-private-key');
getRef('private_key_field').customValidation = floCrypto.getPubKeyHex getRef('private_key_field').setAttribute('placeholder', 'Password');
getRef('private_key_field').customValidation = null
} 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)

File diff suppressed because it is too large Load Diff

View File

@ -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)
} }
} }