lnbits-legend/lnbits/static/js/base.js

524 lines
14 KiB
JavaScript
Raw Normal View History

2020-10-13 13:57:26 -03:00
/* globals crypto, moment, Vue, axios, Quasar, _ */
Vue.use(VueI18n)
2020-10-13 13:57:26 -03:00
window.LOCALE = 'en'
window.i18n = new VueI18n({
locale: window.LOCALE,
fallbackLocale: window.LOCALE,
messages: window.localisation
})
2020-10-13 13:57:26 -03:00
window.EventHub = new Vue()
window.LNbits = {
api: {
request: function (method, url, apiKey, data) {
return axios({
method: method,
url: url,
headers: {
2020-04-16 17:27:36 +02:00
'X-Api-Key': apiKey
},
data: data
2020-05-03 13:55:17 -03:00
})
},
createInvoice: async function (
wallet,
amount,
memo,
unit = 'sat',
lnurlCallback = null
) {
return this.request('post', '/api/v1/payments', wallet.inkey, {
out: false,
amount: amount,
memo: memo,
unit: unit,
lnurl_callback: lnurlCallback
2020-05-03 13:55:17 -03:00
})
},
payInvoice: function (wallet, bolt11) {
2020-04-01 22:18:46 +02:00
return this.request('post', '/api/v1/payments', wallet.adminkey, {
out: true,
bolt11: bolt11
2020-05-03 13:55:17 -03:00
})
},
payLnurl: function (
wallet,
callback,
description_hash,
amount,
2020-10-13 15:18:34 -03:00
description = '',
comment = ''
) {
return this.request('post', '/api/v1/payments/lnurl', wallet.adminkey, {
callback,
description_hash,
amount,
2020-10-13 15:18:34 -03:00
comment,
description
})
},
authLnurl: function (wallet, callback) {
return this.request('post', '/api/v1/lnurlauth', wallet.adminkey, {
callback
})
},
createAccount: function (name) {
return this.request('post', '/api/v1/account', null, {
name: name
})
},
getWallet: function (wallet) {
return this.request('get', '/api/v1/wallet', wallet.inkey)
},
createWallet: function (wallet, name) {
return this.request('post', '/api/v1/wallet', wallet.adminkey, {
name: name
}).then(res => {
window.location = '/wallet?usr=' + res.data.user + '&wal=' + res.data.id
})
},
updateWallet: function (name, wallet) {
return this.request('patch', '/api/v1/wallet', wallet.adminkey, {
name: name
})
},
deleteWallet: function (wallet) {
return this.request('delete', '/api/v1/wallet', wallet.adminkey).then(
_ => {
let url = new URL(window.location.href)
url.searchParams.delete('wal')
window.location = url
}
)
},
getPayments: function (wallet, query) {
const params = new URLSearchParams(query)
return this.request(
'get',
'/api/v1/payments/paginated?' + params,
wallet.inkey
)
},
getPayment: function (wallet, paymentHash) {
return this.request(
'get',
'/api/v1/payments/' + paymentHash,
wallet.inkey
)
}
},
events: {
onInvoicePaid: function (wallet, cb) {
let listener = ev => {
cb(JSON.parse(ev.data))
}
this.listenersCount = this.listenersCount || {[wallet.inkey]: 0}
this.listenersCount[wallet.inkey]++
this.listeners = this.listeners || {}
if (!(wallet.inkey in this.listeners)) {
this.listeners[wallet.inkey] = new EventSource(
'/api/v1/payments/sse?api-key=' + wallet.inkey
)
}
this.listeners[wallet.inkey].addEventListener(
'payment-received',
listener
)
return () => {
this.listeners[wallet.inkey].removeEventListener(
'payment-received',
listener
)
this.listenersCount[wallet.inkey]--
if (this.listenersCount[wallet.inkey] <= 0) {
this.listeners[wallet.inkey].close()
delete this.listeners[wallet.inkey]
}
}
}
},
map: {
extension: function (data) {
2020-05-03 13:55:17 -03:00
var obj = _.object(
2021-03-27 22:10:24 -03:00
[
'code',
'isValid',
2022-02-07 20:43:47 +00:00
'isAdminOnly',
2021-03-27 22:10:24 -03:00
'name',
'shortDescription',
2022-12-31 01:46:55 +00:00
'tile',
2021-03-27 22:10:24 -03:00
'contributors',
'hidden'
],
2020-05-03 13:55:17 -03:00
data
)
obj.url = ['/', obj.code, '/'].join('')
return obj
},
user: function (data) {
2022-02-07 20:43:47 +00:00
var obj = {
id: data.id,
2022-12-09 14:27:32 +02:00
admin: data.admin,
2022-02-07 20:43:47 +00:00
email: data.email,
extensions: data.extensions,
wallets: data.wallets,
admin: data.admin
2022-02-07 20:43:47 +00:00
}
2020-05-03 13:55:17 -03:00
var mapWallet = this.wallet
obj.wallets = obj.wallets
.map(function (obj) {
2020-05-03 13:55:17 -03:00
return mapWallet(obj)
})
.sort(function (a, b) {
2020-05-03 13:55:17 -03:00
return a.name.localeCompare(b.name)
})
obj.walletOptions = obj.wallets.map(function (obj) {
2020-04-05 12:19:25 +02:00
return {
2020-04-18 23:17:16 +02:00
label: [obj.name, ' - ', obj.id].join(''),
2020-04-05 12:19:25 +02:00
value: obj.id
2020-05-03 13:55:17 -03:00
}
})
return obj
},
wallet: function (data) {
2022-02-07 20:43:47 +00:00
newWallet = {
id: data.id,
name: data.name,
adminkey: data.adminkey,
inkey: data.inkey,
currency: data.currency
2022-02-07 20:43:47 +00:00
}
newWallet.msat = data.balance_msat
newWallet.sat = Math.floor(data.balance_msat / 1000)
2022-02-07 20:43:47 +00:00
newWallet.fsat = new Intl.NumberFormat(window.LOCALE).format(
newWallet.sat
)
newWallet.url = ['/wallet?usr=', data.user, '&wal=', data.id].join('')
return newWallet
},
payment: function (data) {
2021-08-29 19:38:42 +02:00
obj = {
checking_id: data.checking_id,
2021-08-29 19:38:42 +02:00
pending: data.pending,
amount: data.amount,
fee: data.fee,
memo: data.memo,
time: data.time,
bolt11: data.bolt11,
preimage: data.preimage,
payment_hash: data.payment_hash,
2022-12-02 19:05:22 +01:00
expiry: data.expiry,
2021-08-29 19:38:42 +02:00
extra: data.extra,
wallet_id: data.wallet_id,
webhook: data.webhook,
webhook_status: data.webhook_status,
fiat_amount: data.fiat_amount,
fiat_currency: data.fiat_currency
2022-02-07 20:43:47 +00:00
}
2021-08-29 19:38:42 +02:00
2020-05-03 13:55:17 -03:00
obj.date = Quasar.utils.date.formatDate(
new Date(obj.time * 1000),
'YYYY-MM-DD HH:mm'
)
obj.dateFrom = moment(obj.date).fromNow()
2022-12-02 19:05:22 +01:00
obj.expirydate = Quasar.utils.date.formatDate(
new Date(obj.expiry * 1000),
'YYYY-MM-DD HH:mm'
)
obj.expirydateFrom = moment(obj.expirydate).fromNow()
2020-05-03 13:55:17 -03:00
obj.msat = obj.amount
obj.sat = obj.msat / 1000
[FEAT] Node Managment (#1895) * [FEAT] Node Managment feat: node dashboard channels and transactions fix: update channel variables better types refactor ui add onchain balances and backend_name mock values for fake wallet remove app tab start implementing peers and channel management peer and channel management implement channel closing add channel states, better errors seperate payments and invoices on transactions tab display total channel balance feat: optional public page feat: show node address fix: port conversion feat: details dialog on transactions fix: peer info without alias fix: rename channel balances small improvements to channels tab feat: pagination on transactions tab test caching transactions refactor: move WALLET into wallets module fix: backwards compatibility refactor: move get_node_class to nodes modules post merge bundle fundle feat: disconnect peer feat: initial lnd support only use filtered channels for total balance adjust closing logic add basic node tests add setting for disabling transactions tab revert unnecessary changes add tests for invoices and payments improve payment and invoice implementations the previously used invoice fixture has a session scope, but a new invoice is required tests and bug fixes for channels api use query instead of body in channel delete delete requests should generally not use a body take node id through path instead of body for delete endpoint add peer management tests more tests for errors improve error handling rename id and pubkey to peer_id for consistency remove dead code fix http status codes make cache keys safer cache node public info comments for node settings rename node prop in frontend adjust tests to new status codes cln: use amount_msat instead of value for onchain balance turn transactions tab off by default enable transactions in tests only allow super user to create or delete fix prop name in admin navbar --------- Co-authored-by: jacksn <jkranawetter05@gmail.com>
2023-09-25 15:04:44 +02:00
obj.tag = obj.extra?.tag
2020-10-13 13:57:26 -03:00
obj.fsat = new Intl.NumberFormat(window.LOCALE).format(obj.sat)
2020-05-03 13:55:17 -03:00
obj.isIn = obj.amount > 0
obj.isOut = obj.amount < 0
2021-06-21 23:22:52 -03:00
obj.isPaid = !obj.pending
2020-05-03 13:55:17 -03:00
obj._q = [obj.memo, obj.sat].join(' ').toLowerCase()
return obj
}
},
utils: {
confirmDialog: function (msg) {
return Quasar.plugins.Dialog.create({
message: msg,
ok: {
flat: true,
color: 'orange'
},
cancel: {
flat: true,
color: 'grey'
}
2020-05-03 13:55:17 -03:00
})
},
digestMessage: async function (message) {
const msgUint8 = new TextEncoder().encode(message)
const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8)
const hashArray = Array.from(new Uint8Array(hashBuffer))
const hashHex = hashArray
.map(b => b.toString(16).padStart(2, '0'))
.join('')
return hashHex
},
formatCurrency: function (value, currency) {
2020-10-13 13:57:26 -03:00
return new Intl.NumberFormat(window.LOCALE, {
2020-05-03 13:55:17 -03:00
style: 'currency',
currency: currency
}).format(value)
},
formatSat: function (value) {
2020-10-13 13:57:26 -03:00
return new Intl.NumberFormat(window.LOCALE).format(value)
},
[FEAT] Node Managment (#1895) * [FEAT] Node Managment feat: node dashboard channels and transactions fix: update channel variables better types refactor ui add onchain balances and backend_name mock values for fake wallet remove app tab start implementing peers and channel management peer and channel management implement channel closing add channel states, better errors seperate payments and invoices on transactions tab display total channel balance feat: optional public page feat: show node address fix: port conversion feat: details dialog on transactions fix: peer info without alias fix: rename channel balances small improvements to channels tab feat: pagination on transactions tab test caching transactions refactor: move WALLET into wallets module fix: backwards compatibility refactor: move get_node_class to nodes modules post merge bundle fundle feat: disconnect peer feat: initial lnd support only use filtered channels for total balance adjust closing logic add basic node tests add setting for disabling transactions tab revert unnecessary changes add tests for invoices and payments improve payment and invoice implementations the previously used invoice fixture has a session scope, but a new invoice is required tests and bug fixes for channels api use query instead of body in channel delete delete requests should generally not use a body take node id through path instead of body for delete endpoint add peer management tests more tests for errors improve error handling rename id and pubkey to peer_id for consistency remove dead code fix http status codes make cache keys safer cache node public info comments for node settings rename node prop in frontend adjust tests to new status codes cln: use amount_msat instead of value for onchain balance turn transactions tab off by default enable transactions in tests only allow super user to create or delete fix prop name in admin navbar --------- Co-authored-by: jacksn <jkranawetter05@gmail.com>
2023-09-25 15:04:44 +02:00
formatMsat: function (value) {
return this.formatSat(value / 1000)
},
notifyApiError: function (error) {
var types = {
400: 'warning',
401: 'warning',
500: 'negative'
2020-05-03 13:55:17 -03:00
}
Quasar.plugins.Notify.create({
timeout: 5000,
type: types[error.response.status] || 'warning',
2022-02-07 20:43:47 +00:00
message:
error.response.data.message || error.response.data.detail || null,
2020-05-03 13:55:17 -03:00
caption:
[error.response.status, ' ', error.response.statusText]
.join('')
.toUpperCase() || null,
icon: null
2020-05-03 13:55:17 -03:00
})
2020-04-01 22:18:46 +02:00
},
search: function (data, q, field, separator) {
try {
2020-05-03 13:55:17 -03:00
var queries = q.toLowerCase().split(separator || ' ')
return data.filter(function (obj) {
2020-05-03 13:55:17 -03:00
var matches = 0
_.each(queries, function (q) {
2020-05-03 13:55:17 -03:00
if (obj[field].indexOf(q) !== -1) matches++
})
return matches === queries.length
2020-05-03 13:55:17 -03:00
})
} catch (err) {
2020-05-03 13:55:17 -03:00
return data
}
},
exportCSV: function (columns, data, fileName) {
var wrapCsvValue = function (val, formatFn) {
2020-05-03 13:55:17 -03:00
var formatted = formatFn !== void 0 ? formatFn(val) : val
2020-04-01 22:18:46 +02:00
2020-05-03 13:55:17 -03:00
formatted =
formatted === void 0 || formatted === null ? '' : String(formatted)
2020-04-01 22:18:46 +02:00
2020-05-03 13:55:17 -03:00
formatted = formatted.split('"').join('""')
2020-04-01 22:18:46 +02:00
2020-05-03 13:55:17 -03:00
return `"${formatted}"`
2020-04-01 22:18:46 +02:00
}
2020-05-03 13:55:17 -03:00
var content = [
columns.map(function (col) {
2020-05-03 13:55:17 -03:00
return wrapCsvValue(col.label)
})
]
.concat(
data.map(function (row) {
2020-05-03 13:55:17 -03:00
return columns
.map(function (col) {
2020-05-03 13:55:17 -03:00
return wrapCsvValue(
typeof col.field === 'function'
? col.field(row)
: row[col.field === void 0 ? col.name : col.field],
col.format
)
})
.join(',')
})
)
.join('\r\n')
2020-04-01 22:18:46 +02:00
2020-05-03 13:55:17 -03:00
var status = Quasar.utils.exportFile(
`${fileName || 'table-export'}.csv`,
2020-05-03 13:55:17 -03:00
content,
'text/csv'
)
2020-04-01 22:18:46 +02:00
if (status !== true) {
Quasar.plugins.Notify.create({
message: 'Browser denied file download...',
color: 'negative',
icon: null
2020-05-03 13:55:17 -03:00
})
2020-04-01 22:18:46 +02:00
}
},
convertMarkdown(text) {
const converter = new showdown.Converter()
converter.setFlavor('github')
converter.setOption('simpleLineBreaks', true)
return converter.makeHtml(text)
}
}
2020-05-03 13:55:17 -03:00
}
2020-10-13 13:57:26 -03:00
window.windowMixin = {
i18n: window.i18n,
data: function () {
return {
[FEAT] Node Managment (#1895) * [FEAT] Node Managment feat: node dashboard channels and transactions fix: update channel variables better types refactor ui add onchain balances and backend_name mock values for fake wallet remove app tab start implementing peers and channel management peer and channel management implement channel closing add channel states, better errors seperate payments and invoices on transactions tab display total channel balance feat: optional public page feat: show node address fix: port conversion feat: details dialog on transactions fix: peer info without alias fix: rename channel balances small improvements to channels tab feat: pagination on transactions tab test caching transactions refactor: move WALLET into wallets module fix: backwards compatibility refactor: move get_node_class to nodes modules post merge bundle fundle feat: disconnect peer feat: initial lnd support only use filtered channels for total balance adjust closing logic add basic node tests add setting for disabling transactions tab revert unnecessary changes add tests for invoices and payments improve payment and invoice implementations the previously used invoice fixture has a session scope, but a new invoice is required tests and bug fixes for channels api use query instead of body in channel delete delete requests should generally not use a body take node id through path instead of body for delete endpoint add peer management tests more tests for errors improve error handling rename id and pubkey to peer_id for consistency remove dead code fix http status codes make cache keys safer cache node public info comments for node settings rename node prop in frontend adjust tests to new status codes cln: use amount_msat instead of value for onchain balance turn transactions tab off by default enable transactions in tests only allow super user to create or delete fix prop name in admin navbar --------- Co-authored-by: jacksn <jkranawetter05@gmail.com>
2023-09-25 15:04:44 +02:00
toggleSubs: true,
g: {
2022-07-04 13:03:21 -06:00
offline: !navigator.onLine,
visibleDrawer: false,
extensions: [],
user: null,
wallet: null,
payments: [],
allowedThemes: null,
langs: []
}
2020-05-03 13:55:17 -03:00
}
},
2021-06-30 13:38:10 +01:00
methods: {
activeLanguage: function (lang) {
return window.i18n.locale === lang
},
changeLanguage: function (newValue) {
window.i18n.locale = newValue
this.$q.localStorage.set('lnbits.lang', newValue)
},
2021-06-30 13:38:10 +01:00
changeColor: function (newValue) {
document.body.setAttribute('data-theme', newValue)
2021-06-30 12:40:58 +01:00
this.$q.localStorage.set('lnbits.theme', newValue)
},
toggleDarkMode: function () {
2020-05-03 13:55:17 -03:00
this.$q.dark.toggle()
this.$q.localStorage.set('lnbits.darkMode', this.$q.dark.isActive)
},
copyText: function (text, message, position) {
2020-05-03 13:55:17 -03:00
var notify = this.$q.notify
Quasar.utils.copyToClipboard(text).then(function () {
2020-05-03 13:55:17 -03:00
notify({
message: message || 'Copied to clipboard!',
position: position || 'bottom'
})
})
}
},
created: function () {
if (
this.$q.localStorage.getItem('lnbits.darkMode') == true ||
this.$q.localStorage.getItem('lnbits.darkMode') == false
) {
2022-02-17 21:34:36 +00:00
this.$q.dark.set(this.$q.localStorage.getItem('lnbits.darkMode'))
} else {
2022-02-17 21:34:36 +00:00
this.$q.dark.set(true)
}
this.g.allowedThemes = window.allowedThemes ?? ['bitcoin']
2021-07-01 11:54:45 +01:00
let locale = this.$q.localStorage.getItem('lnbits.lang')
if (locale) {
window.LOCALE = locale
window.i18n.locale = locale
}
this.g.langs = window.langs ?? []
2022-07-05 16:16:46 -06:00
addEventListener('offline', event => {
2022-07-04 13:03:21 -06:00
this.g.offline = true
})
addEventListener('online', event => {
this.g.offline = false
})
2021-07-01 11:54:45 +01:00
// failsafe if admin changes themes halfway
if (!this.$q.localStorage.getItem('lnbits.theme')) {
2022-02-17 21:34:36 +00:00
this.changeColor(this.g.allowedThemes[0])
}
2021-07-01 12:34:50 +01:00
if (
this.$q.localStorage.getItem('lnbits.theme') &&
!this.g.allowedThemes.includes(
this.$q.localStorage.getItem('lnbits.theme')
)
) {
this.changeColor(this.g.allowedThemes[0])
2021-06-30 12:40:58 +01:00
}
2021-07-01 11:54:45 +01:00
2021-07-01 12:34:50 +01:00
if (this.$q.localStorage.getItem('lnbits.theme')) {
document.body.setAttribute(
'data-theme',
this.$q.localStorage.getItem('lnbits.theme')
)
2021-07-01 11:54:45 +01:00
}
if (window.user) {
2020-10-13 13:57:26 -03:00
this.g.user = Object.freeze(window.LNbits.map.user(window.user))
}
if (window.wallet) {
2020-10-13 13:57:26 -03:00
this.g.wallet = Object.freeze(window.LNbits.map.wallet(window.wallet))
}
if (window.extensions) {
2020-05-03 13:55:17 -03:00
var user = this.g.user
const extensions = Object.freeze(
2020-05-03 13:55:17 -03:00
window.extensions
.map(function (data) {
2020-10-13 13:57:26 -03:00
return window.LNbits.map.extension(data)
2020-05-03 13:55:17 -03:00
})
2021-03-27 22:10:24 -03:00
.filter(function (obj) {
return !obj.hidden
})
2022-02-07 20:43:47 +00:00
.filter(function (obj) {
[FEAT] Node Managment (#1895) * [FEAT] Node Managment feat: node dashboard channels and transactions fix: update channel variables better types refactor ui add onchain balances and backend_name mock values for fake wallet remove app tab start implementing peers and channel management peer and channel management implement channel closing add channel states, better errors seperate payments and invoices on transactions tab display total channel balance feat: optional public page feat: show node address fix: port conversion feat: details dialog on transactions fix: peer info without alias fix: rename channel balances small improvements to channels tab feat: pagination on transactions tab test caching transactions refactor: move WALLET into wallets module fix: backwards compatibility refactor: move get_node_class to nodes modules post merge bundle fundle feat: disconnect peer feat: initial lnd support only use filtered channels for total balance adjust closing logic add basic node tests add setting for disabling transactions tab revert unnecessary changes add tests for invoices and payments improve payment and invoice implementations the previously used invoice fixture has a session scope, but a new invoice is required tests and bug fixes for channels api use query instead of body in channel delete delete requests should generally not use a body take node id through path instead of body for delete endpoint add peer management tests more tests for errors improve error handling rename id and pubkey to peer_id for consistency remove dead code fix http status codes make cache keys safer cache node public info comments for node settings rename node prop in frontend adjust tests to new status codes cln: use amount_msat instead of value for onchain balance turn transactions tab off by default enable transactions in tests only allow super user to create or delete fix prop name in admin navbar --------- Co-authored-by: jacksn <jkranawetter05@gmail.com>
2023-09-25 15:04:44 +02:00
if (window.user?.admin) return obj
2022-02-07 20:43:47 +00:00
return !obj.isAdminOnly
})
.map(function (obj) {
2020-05-03 13:55:17 -03:00
if (user) {
obj.isEnabled = user.extensions.indexOf(obj.code) !== -1
2020-05-03 13:55:17 -03:00
} else {
obj.isEnabled = false
}
return obj
})
.sort(function (a, b) {
const nameA = a.name.toUpperCase()
const nameB = b.name.toUpperCase()
return nameA < nameB ? -1 : nameA > nameB ? 1 : 0
2020-05-03 13:55:17 -03:00
})
)
this.g.extensions = extensions
}
}
2020-05-03 13:55:17 -03:00
}
2020-10-13 13:57:26 -03:00
window.decryptLnurlPayAES = function (success_action, preimage) {
let keyb = new Uint8Array(
preimage.match(/[\da-f]{2}/gi).map(h => parseInt(h, 16))
)
return crypto.subtle
.importKey('raw', keyb, {name: 'AES-CBC', length: 256}, false, ['decrypt'])
.then(key => {
let ivb = Uint8Array.from(window.atob(success_action.iv), c =>
c.charCodeAt(0)
)
let ciphertextb = Uint8Array.from(
window.atob(success_action.ciphertext),
c => c.charCodeAt(0)
)
return crypto.subtle.decrypt({name: 'AES-CBC', iv: ivb}, key, ciphertextb)
})
.then(valueb => {
let decoder = new TextDecoder('utf-8')
return decoder.decode(valueb)
})
2022-07-05 16:16:46 -06:00
}