added option to set password

This commit is contained in:
sairaj mote 2022-08-17 18:08:16 +05:30
parent 2e753968b8
commit 6bff6c476b
4 changed files with 142 additions and 62 deletions

View File

@ -788,6 +788,16 @@
</div> </div>
<sm-button class="danger justify-self-start" onclick="signOut()">Sign out</sm-button> <sm-button class="danger justify-self-start" onclick="signOut()">Sign out</sm-button>
</div> </div>
<div class="grid gap-1 card">
<h4>Secure private key</h4>
<p>
You can set a password to secure your private key and use the password instead of private key.
This is applied to this browser only.
</p>
<button id="secure_pwd_button" class="button button--primary justify-self-start secure-priv-key"
onclick="openPopup('secure_pwd_popup')">Set
password</button>
</div>
<div class="grid gap-1 user-element card"> <div class="grid gap-1 user-element card">
<h4>My UPI IDs</h4> <h4>My UPI IDs</h4>
<ul id="saved_upi_ids_list" class="observe-empty-state"></ul> <ul id="saved_upi_ids_list" class="observe-empty-state"></ul>
@ -1434,6 +1444,26 @@
</div> </div>
</div> </div>
</sm-popup> </sm-popup>
<sm-popup id="secure_pwd_popup">
<header slot="header" class="popup__header">
<button class="popup__header__close justify-self-start">
<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="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" />
</svg>
</button>
<h3 id="secure_pwd_title">Set password</h3>
</header>
<sm-form>
<sm-input id="secure_pwd_input" type="password" placeholder="Password" animate required autofocus>
</sm-input>
<button class="button button--primary cta secure-priv-key" type="submit" onclick="setSecurePassword()">
Set
</button>
</sm-form>
</sm-popup>
<!-- Cashier popups --> <!-- Cashier popups -->
<sm-popup id="confirm_topup_popup"> <sm-popup id="confirm_topup_popup">

View File

@ -1117,13 +1117,13 @@ customElements.define('sm-notifications', class extends HTMLElement {
createNotification(message, options = {}) { createNotification(message, options = {}) {
const { pinned = false, icon = '', action } = options; const { pinned = false, icon = '', action } = options;
const notification = document.createElement('output') const notification = document.createElement('div')
notification.id = this.randString(8) notification.id = this.randString(8)
notification.classList.add('notification'); notification.classList.add('notification');
let composition = ``; let composition = ``;
composition += ` composition += `
<div class="icon-container">${icon}</div> <div class="icon-container">${icon}</div>
<p>${message}</p> <output>${message}</output>
`; `;
if (action) { if (action) {
composition += ` composition += `
@ -1177,6 +1177,7 @@ customElements.define('sm-notifications', class extends HTMLElement {
} }
removeNotification(notification, direction = 'left') { removeNotification(notification, direction = 'left') {
if (!notification) return;
const sign = direction === 'left' ? '-' : '+'; const sign = direction === 'left' ? '-' : '+';
notification.animate([ notification.animate([
{ {
@ -1218,8 +1219,10 @@ customElements.define('sm-notifications', class extends HTMLElement {
this.mediaQuery.addEventListener('change', this.handleOrientationChange); this.mediaQuery.addEventListener('change', this.handleOrientationChange);
this.notificationPanel.addEventListener('pointerdown', e => { this.notificationPanel.addEventListener('pointerdown', e => {
if (e.target.closest('.notification')) { if (e.target.closest('.close')) {
this.swipeThreshold = this.clientWidth / 2; this.removeNotification(e.target.closest('.notification'));
} else if (e.target.closest('.notification')) {
this.swipeThreshold = e.target.closest('.notification').getBoundingClientRect().width / 2;
this.currentTarget = e.target.closest('.notification'); this.currentTarget = e.target.closest('.notification');
this.currentTarget.setPointerCapture(e.pointerId); this.currentTarget.setPointerCapture(e.pointerId);
this.startTime = Date.now(); this.startTime = Date.now();
@ -1262,12 +1265,6 @@ customElements.define('sm-notifications', class extends HTMLElement {
this.notificationPanel.releasePointerCapture(e.pointerId); this.notificationPanel.releasePointerCapture(e.pointerId);
this.currentX = 0; this.currentX = 0;
}); });
this.notificationPanel.addEventListener('click', e => {
if (e.target.closest('.close')) {
this.removeNotification(e.target.closest('.notification'));
}
});
const observer = new MutationObserver(mutationList => { const observer = new MutationObserver(mutationList => {
mutationList.forEach(mutation => { mutationList.forEach(mutation => {
if (mutation.type === 'childList') { if (mutation.type === 'childList') {

View File

@ -11,9 +11,16 @@
const relativeTime = new RelativeTime({ style: 'narrow' }); 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) { async function syncUserData(obsName, data) {
const dataToSend = Crypto.AES.encrypt(JSON.stringify(data), myPrivKey); floDapps.user.private.then(privateKey => {
return floCloudAPI.sendApplicationData(dataToSend, obsName, { receiverID: floDapps.user.id }); if (!privateKey) return;
const encryptedData = Crypto.AES.encrypt(JSON.stringify(data), privateKey);
return floCloudAPI.sendApplicationData(encryptedData, obsName, { receiverID: floDapps.user.id });
}).catch(error => {
console.log(error);
notify('Invalid password', 'error');
return false;
})
} }
// store user data in separate IDB // store user data in separate IDB
async function organizeSyncedData(obsName) { async function organizeSyncedData(obsName) {
@ -21,13 +28,20 @@ async function organizeSyncedData(obsName) {
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);
const decryptedData = JSON.parse(Crypto.AES.decrypt(dataToDecrypt, myPrivKey)); floDapps.user.private.then(privateKey => {
for (let key in decryptedData) { if (!privateKey) return;
floGlobals[obsName][key] = decryptedData[key]; const decryptedData = JSON.parse(Crypto.AES.decrypt(dataToDecrypt, privateKey));
compactIDB.addData(obsName, decryptedData[key], key); for (let key in decryptedData) {
} floGlobals[obsName][key] = decryptedData[key];
compactIDB.addData(obsName, fetchedData[0].time, 'lastSyncTime'); compactIDB.addData(obsName, decryptedData[key], key);
return true; }
compactIDB.addData(obsName, fetchedData[0].time, 'lastSyncTime');
return true;
}).catch(error => {
console.log(error);
notify('Invalid password', 'error');
return false;
})
} else { } else {
const idbData = await compactIDB.readAllData(obsName); const idbData = await compactIDB.readAllData(obsName);
for (const key in idbData) { for (const key in idbData) {
@ -121,22 +135,30 @@ 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, floDapps.user.id, 'FRJkPqdbbsug3TtQRAWviqvTL9Qr2EMnrm', myPrivKey).then(txid => { floDapps.user.private.then(privateKey => {
console.log(txid); if (!privateKey) return;
showChildElement('exchange_transfer_process', 1); floExchangeAPI.depositToken('rupee', amount, floDapps.user.id, 'FRJkPqdbbsug3TtQRAWviqvTL9Qr2EMnrm', privateKey).then(txid => {
getRef('exchange_transfer__success_message').textContent = `Transferred ${formatAmount(amount)} to exchange`; console.log(txid);
}).catch(error => { showChildElement('exchange_transfer_process', 1);
getRef('exchange_transfer__success_message').textContent = `Transferred ${formatAmount(amount)} to exchange`;
}).catch(error => {
console.log(error);
if (error.code) {
error = error.message;
}
if (error === 'Insufficient rupee# balance')
error = 'Insufficient rupee token balance in your wallet, please top-up your wallet.';
getRef('exchange_transfer__failed_reason').textContent = error;
showChildElement('exchange_transfer_process', 2);
}).finally(() => {
buttonLoader('exchange_transfer__button', false);
});
}).catch(error => {
console.log(error); console.log(error);
if (error.code) { notify('Invalid password', 'error');
error = error.message; closePopup();
} return false;
if (error === 'Insufficient rupee# balance') })
error = 'Insufficient rupee token balance in your wallet, please top-up your wallet.';
getRef('exchange_transfer__failed_reason').textContent = error;
showChildElement('exchange_transfer_process', 2);
}).finally(() => {
buttonLoader('exchange_transfer__button', false);
});
} }
async function renderSavedUpiIds() { async function renderSavedUpiIds() {
@ -470,12 +492,13 @@ function declineTopUp() {
} }
function completeTokenToCashRequest(request) { async function completeTokenToCashRequest(request) {
const { vectorClock, senderID, message: { token_txid, amount, upi_id } } = request; const { vectorClock, senderID, message: { token_txid, amount, upi_id } } = request;
var upiID; var upiID;
if (upi_id instanceof Object && "secret" in upi_id) { if (upi_id instanceof Object && "secret" in upi_id) {
try { try {
upiID = floCrypto.decryptData(upi_id, myPrivKey); const privateKey = await floGlobals.user.private
upiID = floCrypto.decryptData(upi_id, privateKey);
} catch (error) { } catch (error) {
console.error("UPI ID is not encrypted with a proper key", error); console.error("UPI ID is not encrypted with a proper key", error);
return notify("Invalid UPI ID", 'error'); return notify("Invalid UPI ID", 'error');
@ -1197,17 +1220,26 @@ function getSignedIn(passwordType) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
try { try {
console.log(floDapps.user.id) console.log(floDapps.user.id)
getPromptInput('Enter password', '', {
isPassword: true,
}).then(password => {
if (password) {
resolve(password)
}
})
}catch(err) { }catch(err) {
if (passwordType === 'PIN/Password') { if (passwordType === 'PIN/Password') {
floGlobals.isPrivKeySecured = true;
getRef('private_key_field').removeAttribute('data-private-key'); getRef('private_key_field').removeAttribute('data-private-key');
getRef('private_key_field').setAttribute('placeholder', 'Password'); getRef('private_key_field').setAttribute('placeholder', 'Password');
getRef('private_key_field').customValidation = null getRef('private_key_field').customValidation = null
getRef('secure_pwd_button').closest('.card').classList.add('hidden');
} else { } else {
floGlobals.isPrivKeySecured = false;
getRef('private_key_field').dataset.privateKey = '' getRef('private_key_field').dataset.privateKey = ''
getRef('private_key_field').setAttribute('placeholder', 'FLO private key'); getRef('private_key_field').setAttribute('placeholder', 'FLO private key');
getRef('private_key_field').customValidation = floCrypto.getPubKeyHex getRef('private_key_field').customValidation = floCrypto.getPubKeyHex;
getRef('secure_pwd_button').closest('.card').classList.remove('hidden');
} }
if (window.location.hash.includes('sign_in') || window.location.hash.includes('sign_up')) { if (window.location.hash.includes('sign_in') || window.location.hash.includes('sign_up')) {
showPage(window.location.hash); showPage(window.location.hash);
@ -1227,6 +1259,19 @@ function getSignedIn(passwordType) {
} }
}); });
} }
function setSecurePassword() {
if (!floGlobals.isPrivKeySecured) {
const password = getRef('secure_pwd_input').value.trim();
floDapps.securePrivKey(password).then(() => {
floGlobals.isPrivKeySecured = true;
notify('Password set successfully', 'success');
getRef('secure_pwd_button').closest('.card').classList.add('hidden');
closePopup();
}).catch(err => {
notify(err, 'error');
})
}
}
function signOut() { function signOut() {
getConfirmation('Sign out?', 'You are about to sign out of the app, continue?', 'Stay', 'Leave') getConfirmation('Sign out?', 'You are about to sign out of the app, continue?', 'Stay', 'Leave')
.then(async (res) => { .then(async (res) => {
@ -1372,31 +1417,38 @@ 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(floDapps.user.id); floGlobals.user.private.then(privateKey => {
const privKeys = btc_api.convert.wif(myPrivKey); const privKeys = btc_api.convert.wif(privateKey);
const receivers = [...getRef('receiver_container').querySelectorAll('.receiver-input')].map(input => input.value.trim()); const senders = btc_api.convert.legacy2bech(floDapps.user.id);
const amounts = [...getRef('receiver_container').querySelectorAll('.amount-input')].map(input => { const receivers = [...getRef('receiver_container').querySelectorAll('.receiver-input')].map(input => input.value.trim());
return parseFloat(input.value.trim()) const amounts = [...getRef('receiver_container').querySelectorAll('.amount-input')].map(input => {
}); return parseFloat(input.value.trim())
const fee = parseFloat(getRef('send_fee').value.trim()); });
console.debug(senders, receivers, amounts, fee); const fee = parseFloat(getRef('send_fee').value.trim());
btc_api.sendTx(senders, privKeys, receivers, amounts, fee).then(result => { console.debug(senders, receivers, amounts, fee);
console.log(result); btc_api.sendTx(senders, privKeys, receivers, amounts, fee).then(result => {
closePopup(); console.log(result);
getRef('txid').value = result.txid; closePopup();
openPopup('txid_popup'); getRef('txid').value = result.txid;
getRef('send_tx').reset() openPopup('txid_popup');
getExchangeRate().then(() => { getRef('send_tx').reset()
calculateBtcFees() getExchangeRate().then(() => {
}).catch(e => { calculateBtcFees()
console.error(e) }).catch(e => {
console.error(e)
})
}).catch(error => {
notify(`Error sending transaction \n ${error}`, 'error');
}).finally(_ => {
buttonLoader('send_transaction', false)
}) })
}).catch(error => { }).catch(error => {
notify(`Error sending transaction \n ${error}`, 'error'); console.log(error);
}).finally(_ => { notify('Invalid password', 'error');
buttonLoader('send_transaction', false) closePopup();
return false;
}) })
} }

View File

@ -134,6 +134,7 @@ document.addEventListener('popupclosed', e => {
break; break;
case 'transfer_to_exchange_popup': case 'transfer_to_exchange_popup':
showChildElement('exchange_transfer_process', 0); showChildElement('exchange_transfer_process', 0);
buttonLoader('exchange_transfer__button', false);
break; break;
case 'confirm_topup_popup': case 'confirm_topup_popup':
showChildElement('confirm_topup_wrapper', 0); showChildElement('confirm_topup_wrapper', 0);