mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-11-04 11:55:50 +00:00
137 lines
4.8 KiB
JavaScript
137 lines
4.8 KiB
JavaScript
const {prepareAccountData, prepareLedgerData} = require("./3_helpers");
|
|
const {prepareTxData} = require("./4_helpers");
|
|
const crypto = require("crypto");
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const fernet = require("fernet");
|
|
|
|
/**
|
|
* Fetches some initial data to be displayed on application startup
|
|
*
|
|
* @param client
|
|
* @param wallet
|
|
* @param appWindow
|
|
* @returns {Promise<void>}
|
|
*/
|
|
const initialize = async (client, wallet, appWindow) => {
|
|
// Reference: https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/account-methods/account_info
|
|
const accountInfoResponse = await client.request({
|
|
"command": "account_info",
|
|
"account": wallet.address,
|
|
"ledger_index": "current"
|
|
})
|
|
const accountData = prepareAccountData(accountInfoResponse.result.account_data)
|
|
appWindow.webContents.send('update-account-data', accountData)
|
|
|
|
// Reference: https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/account-methods/account_tx
|
|
const txResponse = await client.request({
|
|
"command": "account_tx",
|
|
"account": wallet.address
|
|
})
|
|
const transactions = prepareTxData(txResponse.result.transactions)
|
|
appWindow.webContents.send('update-transaction-data', transactions)
|
|
}
|
|
|
|
/**
|
|
* Handles the subscriptions to ledger events and the internal routing of the responses
|
|
*
|
|
* @param client
|
|
* @param wallet
|
|
* @param appWindow
|
|
* @returns {Promise<void>}
|
|
*/
|
|
const subscribe = async (client, wallet, appWindow) => {
|
|
|
|
// Reference: https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/subscription-methods/subscribe
|
|
await client.request({
|
|
"command": "subscribe",
|
|
"streams": ["ledger"],
|
|
"accounts": [wallet.address]
|
|
})
|
|
|
|
// Reference: https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/subscription-methods/subscribe#ledger-stream
|
|
client.on("ledgerClosed", async (rawLedgerData) => {
|
|
const ledger = prepareLedgerData(rawLedgerData)
|
|
appWindow.webContents.send('update-ledger-data', ledger)
|
|
})
|
|
|
|
// Wait for transaction on subscribed account and re-request account data
|
|
client.on("transaction", async (transaction) => {
|
|
// Reference: https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/account-methods/account_info
|
|
const accountInfoRequest = {
|
|
"command": "account_info",
|
|
"account": wallet.address,
|
|
"ledger_index": transaction.ledger_index
|
|
}
|
|
|
|
const accountInfoResponse = await client.request(accountInfoRequest)
|
|
const accountData = prepareAccountData(accountInfoResponse.result.account_data)
|
|
appWindow.webContents.send('update-account-data', accountData)
|
|
|
|
const transactions = prepareTxData([transaction])
|
|
appWindow.webContents.send('update-transaction-data', transactions)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Saves the wallet seed using proper cryptographic functions
|
|
*
|
|
* @param WALLET_DIR
|
|
* @param seed
|
|
* @param password
|
|
*/
|
|
const saveSaltedSeed = (WALLET_DIR, seed, password)=> {
|
|
const salt = crypto.randomBytes(20).toString('hex')
|
|
|
|
fs.writeFileSync(path.join(__dirname, WALLET_DIR, 'salt.txt'), salt);
|
|
|
|
// Hashing salted password using Password-Based Key Derivation Function 2
|
|
const derivedKey = crypto.pbkdf2Sync(password, salt, 1000, 32, 'sha256')
|
|
|
|
// Generate a Fernet secret we can use for symmetric encryption
|
|
const secret = new fernet.Secret(derivedKey.toString('base64'));
|
|
|
|
// Generate encryption token with secret, time and initialization vector
|
|
// In a real-world use case we would have current time and a random IV,
|
|
// but for demo purposes being deterministic is just fine
|
|
const token = new fernet.Token({
|
|
secret: secret,
|
|
time: Date.parse(1),
|
|
iv: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
|
})
|
|
|
|
const privateKey = token.encode(seed)
|
|
|
|
fs.writeFileSync(path.join(__dirname, WALLET_DIR, 'seed.txt'), privateKey)
|
|
}
|
|
|
|
/**
|
|
* Loads the plaintext value of the encrypted seed
|
|
*
|
|
* @param WALLET_DIR
|
|
* @param password
|
|
* @returns {*}
|
|
*/
|
|
const loadSaltedSeed = (WALLET_DIR, password) => {
|
|
const salt = fs.readFileSync(path.join(__dirname, WALLET_DIR, 'salt.txt')).toString()
|
|
|
|
const encodedSeed = fs.readFileSync(path.join(__dirname, WALLET_DIR, 'seed.txt')).toString()
|
|
|
|
// Hashing salted password using Password-Based Key Derivation Function 2
|
|
const derivedKey = crypto.pbkdf2Sync(password, salt, 1000, 32, 'sha256')
|
|
|
|
// Generate a Fernet secret we can use for symmetric encryption
|
|
const secret = new fernet.Secret(derivedKey.toString('base64'));
|
|
|
|
// Generate decryption token
|
|
const token = new fernet.Token({
|
|
secret: secret,
|
|
token: encodedSeed,
|
|
ttl: 0
|
|
})
|
|
|
|
return token.decode();
|
|
}
|
|
|
|
module.exports = { initialize, subscribe, saveSaltedSeed, loadSaltedSeed }
|