2025-01-16 11:23:34 +00:00
|
|
|
window.AccountPageLogic = {
|
2024-09-24 11:06:27 +02:00
|
|
|
mixins: [window.windowMixin],
|
2024-12-10 13:42:01 +01:00
|
|
|
data() {
|
2023-12-12 12:38:19 +02:00
|
|
|
return {
|
|
|
|
user: null,
|
|
|
|
hasUsername: false,
|
2023-12-14 12:34:23 +02:00
|
|
|
showUserId: false,
|
2024-02-12 10:48:07 +00:00
|
|
|
reactionOptions: [
|
|
|
|
'None',
|
|
|
|
'confettiBothSides',
|
|
|
|
'confettiFireworks',
|
2025-01-16 11:23:34 +00:00
|
|
|
'confettiStars',
|
|
|
|
'confettiTop'
|
2024-02-12 10:48:07 +00:00
|
|
|
],
|
2024-10-29 09:58:22 +01:00
|
|
|
borderOptions: ['retro-border', 'hard-border', 'no-border'],
|
2024-01-15 11:51:34 +02:00
|
|
|
tab: 'user',
|
2024-09-30 14:53:38 +03:00
|
|
|
credentialsData: {
|
2023-12-12 12:38:19 +02:00
|
|
|
show: false,
|
|
|
|
oldPassword: null,
|
|
|
|
newPassword: null,
|
2024-09-30 14:53:38 +03:00
|
|
|
newPasswordRepeat: null,
|
|
|
|
username: null,
|
|
|
|
pubkey: null
|
2025-01-16 17:25:27 +02:00
|
|
|
},
|
|
|
|
apiAcl: {
|
|
|
|
showNewAclDialog: false,
|
|
|
|
showPasswordDialog: false,
|
|
|
|
showNewTokenDialog: false,
|
|
|
|
data: [],
|
|
|
|
passwordGuardedFunction: null,
|
|
|
|
newAclName: '',
|
|
|
|
newTokenName: '',
|
|
|
|
password: '',
|
|
|
|
apiToken: null,
|
|
|
|
selectedTokenId: null,
|
|
|
|
columns: [
|
|
|
|
{
|
|
|
|
name: 'Name',
|
|
|
|
align: 'left',
|
|
|
|
label: this.$t('Name'),
|
|
|
|
field: 'Name',
|
|
|
|
sortable: false
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'path',
|
|
|
|
align: 'left',
|
|
|
|
label: this.$t('path'),
|
|
|
|
field: 'path',
|
|
|
|
sortable: false
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'read',
|
|
|
|
align: 'left',
|
|
|
|
label: this.$t('read'),
|
|
|
|
field: 'read',
|
|
|
|
sortable: false
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'write',
|
|
|
|
align: 'left',
|
|
|
|
label: this.$t('write'),
|
|
|
|
field: 'write',
|
|
|
|
sortable: false
|
|
|
|
}
|
|
|
|
],
|
|
|
|
pagination: {
|
|
|
|
rowsPerPage: 100,
|
|
|
|
page: 1
|
|
|
|
}
|
|
|
|
},
|
|
|
|
selectedApiAcl: {
|
|
|
|
id: null,
|
|
|
|
name: null,
|
|
|
|
endpoints: [],
|
|
|
|
token_id_list: [],
|
|
|
|
allRead: false,
|
|
|
|
allWrite: false
|
2023-12-12 12:38:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
2024-12-10 13:42:01 +01:00
|
|
|
activeLanguage(lang) {
|
2024-09-25 12:09:00 +02:00
|
|
|
return window.i18n.global.locale === lang
|
2024-01-15 11:51:34 +02:00
|
|
|
},
|
2024-12-10 13:42:01 +01:00
|
|
|
changeLanguage(newValue) {
|
2024-09-25 12:09:00 +02:00
|
|
|
window.i18n.global.locale = newValue
|
2024-01-15 11:51:34 +02:00
|
|
|
this.$q.localStorage.set('lnbits.lang', newValue)
|
|
|
|
},
|
2024-12-10 13:42:01 +01:00
|
|
|
toggleDarkMode() {
|
2024-01-15 11:51:34 +02:00
|
|
|
this.$q.dark.toggle()
|
|
|
|
this.$q.localStorage.set('lnbits.darkMode', this.$q.dark.isActive)
|
2024-08-30 17:16:24 +01:00
|
|
|
if (!this.$q.dark.isActive && this.gradientChoice) {
|
|
|
|
this.toggleGradient()
|
|
|
|
}
|
|
|
|
},
|
2024-12-10 13:42:01 +01:00
|
|
|
toggleGradient() {
|
2024-08-30 17:16:24 +01:00
|
|
|
this.gradientChoice = !this.gradientChoice
|
|
|
|
this.applyGradient()
|
|
|
|
if (!this.gradientChoice) {
|
|
|
|
window.location.reload()
|
|
|
|
}
|
2024-01-15 11:51:34 +02:00
|
|
|
},
|
2024-12-10 13:42:01 +01:00
|
|
|
reactionChoiceFunc() {
|
2024-02-12 10:48:07 +00:00
|
|
|
this.$q.localStorage.set('lnbits.reactions', this.reactionChoice)
|
2024-02-08 13:34:03 +00:00
|
|
|
},
|
2024-12-10 13:42:01 +01:00
|
|
|
changeColor(newValue) {
|
2024-01-15 11:51:34 +02:00
|
|
|
document.body.setAttribute('data-theme', newValue)
|
|
|
|
this.$q.localStorage.set('lnbits.theme', newValue)
|
2024-08-30 17:16:24 +01:00
|
|
|
this.setColors()
|
|
|
|
if (this.$q.localStorage.getItem('lnbits.gradientBg')) {
|
|
|
|
this.applyGradient()
|
|
|
|
}
|
|
|
|
},
|
2024-12-10 13:42:01 +01:00
|
|
|
async updateAccount() {
|
2023-12-12 12:38:19 +02:00
|
|
|
try {
|
|
|
|
const {data} = await LNbits.api.request(
|
|
|
|
'PUT',
|
|
|
|
'/api/v1/auth/update',
|
|
|
|
null,
|
|
|
|
{
|
|
|
|
user_id: this.user.id,
|
|
|
|
username: this.user.username,
|
|
|
|
email: this.user.email,
|
2024-10-29 09:58:22 +01:00
|
|
|
extra: this.user.extra
|
2023-12-12 12:38:19 +02:00
|
|
|
}
|
|
|
|
)
|
|
|
|
this.user = data
|
2024-09-30 14:53:38 +03:00
|
|
|
this.hasUsername = !!data.username
|
2024-09-24 16:18:56 +02:00
|
|
|
Quasar.Notify.create({
|
2023-12-12 12:38:19 +02:00
|
|
|
type: 'positive',
|
|
|
|
message: 'Account updated.'
|
|
|
|
})
|
|
|
|
} catch (e) {
|
|
|
|
LNbits.utils.notifyApiError(e)
|
|
|
|
}
|
|
|
|
},
|
2024-12-10 13:42:01 +01:00
|
|
|
disableUpdatePassword() {
|
2024-09-30 14:53:38 +03:00
|
|
|
return (
|
|
|
|
!this.credentialsData.newPassword ||
|
|
|
|
!this.credentialsData.newPasswordRepeat ||
|
|
|
|
this.credentialsData.newPassword !==
|
|
|
|
this.credentialsData.newPasswordRepeat
|
|
|
|
)
|
|
|
|
},
|
2024-12-10 13:42:01 +01:00
|
|
|
async updatePassword() {
|
2024-09-30 14:53:38 +03:00
|
|
|
if (!this.credentialsData.username) {
|
2024-09-24 16:18:56 +02:00
|
|
|
Quasar.Notify.create({
|
2024-02-06 11:48:13 +02:00
|
|
|
type: 'warning',
|
2024-09-30 14:53:38 +03:00
|
|
|
message: 'Please set a username.'
|
2024-02-06 11:48:13 +02:00
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
2023-12-12 12:38:19 +02:00
|
|
|
try {
|
|
|
|
const {data} = await LNbits.api.request(
|
|
|
|
'PUT',
|
|
|
|
'/api/v1/auth/password',
|
|
|
|
null,
|
|
|
|
{
|
|
|
|
user_id: this.user.id,
|
2024-09-30 14:53:38 +03:00
|
|
|
username: this.credentialsData.username,
|
|
|
|
password_old: this.credentialsData.oldPassword,
|
|
|
|
password: this.credentialsData.newPassword,
|
|
|
|
password_repeat: this.credentialsData.newPasswordRepeat
|
2023-12-12 12:38:19 +02:00
|
|
|
}
|
|
|
|
)
|
|
|
|
this.user = data
|
2024-09-30 14:53:38 +03:00
|
|
|
this.hasUsername = !!data.username
|
|
|
|
this.credentialsData.show = false
|
2024-09-24 16:18:56 +02:00
|
|
|
Quasar.Notify.create({
|
2023-12-12 12:38:19 +02:00
|
|
|
type: 'positive',
|
|
|
|
message: 'Password updated.'
|
|
|
|
})
|
|
|
|
} catch (e) {
|
|
|
|
LNbits.utils.notifyApiError(e)
|
|
|
|
}
|
|
|
|
},
|
2024-12-10 13:42:01 +01:00
|
|
|
async updatePubkey() {
|
2024-09-30 14:53:38 +03:00
|
|
|
try {
|
|
|
|
const {data} = await LNbits.api.request(
|
|
|
|
'PUT',
|
|
|
|
'/api/v1/auth/pubkey',
|
|
|
|
null,
|
|
|
|
{
|
|
|
|
user_id: this.user.id,
|
|
|
|
pubkey: this.credentialsData.pubkey
|
|
|
|
}
|
|
|
|
)
|
|
|
|
this.user = data
|
|
|
|
this.hasUsername = !!data.username
|
|
|
|
this.credentialsData.show = false
|
|
|
|
this.$q.notify({
|
|
|
|
type: 'positive',
|
|
|
|
message: 'Public key updated.'
|
2024-02-06 11:48:13 +02:00
|
|
|
})
|
2024-09-30 14:53:38 +03:00
|
|
|
} catch (e) {
|
|
|
|
LNbits.utils.notifyApiError(e)
|
2024-02-06 11:48:13 +02:00
|
|
|
}
|
2024-09-30 14:53:38 +03:00
|
|
|
},
|
2024-12-10 13:42:01 +01:00
|
|
|
showUpdateCredentials() {
|
2024-09-30 14:53:38 +03:00
|
|
|
this.credentialsData = {
|
2023-12-12 12:38:19 +02:00
|
|
|
show: true,
|
|
|
|
oldPassword: null,
|
2024-09-30 14:53:38 +03:00
|
|
|
username: this.user.username,
|
|
|
|
pubkey: this.user.pubkey,
|
2023-12-12 12:38:19 +02:00
|
|
|
newPassword: null,
|
|
|
|
newPasswordRepeat: null
|
|
|
|
}
|
2025-01-16 17:25:27 +02:00
|
|
|
},
|
|
|
|
newApiAclDialog() {
|
|
|
|
this.apiAcl.newAclName = null
|
|
|
|
this.apiAcl.showNewAclDialog = true
|
|
|
|
},
|
|
|
|
newTokenAclDialog() {
|
|
|
|
this.apiAcl.newTokenName = null
|
|
|
|
this.apiAcl.newTokenExpiry = null
|
|
|
|
this.apiAcl.showNewTokenDialog = true
|
|
|
|
},
|
|
|
|
handleApiACLSelected(aclId) {
|
|
|
|
this.selectedApiAcl = {
|
|
|
|
id: null,
|
|
|
|
name: null,
|
|
|
|
endpoints: [],
|
|
|
|
token_id_list: []
|
|
|
|
}
|
|
|
|
this.apiAcl.selectedTokenId = null
|
|
|
|
if (!aclId) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
setTimeout(() => {
|
|
|
|
const selectedApiAcl = this.apiAcl.data.find(t => t.id === aclId)
|
|
|
|
if (!this.selectedApiAcl) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
this.selectedApiAcl = {...selectedApiAcl}
|
|
|
|
this.selectedApiAcl.allRead = this.selectedApiAcl.endpoints.every(
|
|
|
|
e => e.read
|
|
|
|
)
|
|
|
|
this.selectedApiAcl.allWrite = this.selectedApiAcl.endpoints.every(
|
|
|
|
e => e.write
|
|
|
|
)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
handleAllEndpointsReadAccess() {
|
|
|
|
this.selectedApiAcl.endpoints.forEach(
|
|
|
|
e => (e.read = this.selectedApiAcl.allRead)
|
|
|
|
)
|
|
|
|
},
|
|
|
|
handleAllEndpointsWriteAccess() {
|
|
|
|
this.selectedApiAcl.endpoints.forEach(
|
|
|
|
e => (e.write = this.selectedApiAcl.allWrite)
|
|
|
|
)
|
|
|
|
},
|
|
|
|
async getApiACLs() {
|
|
|
|
try {
|
|
|
|
const {data} = await LNbits.api.request('GET', '/api/v1/auth/acl', null)
|
|
|
|
this.apiAcl.data = data.access_control_list
|
|
|
|
} catch (e) {
|
|
|
|
LNbits.utils.notifyApiError(e)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
askPasswordAndRunFunction(func) {
|
|
|
|
this.apiAcl.passwordGuardedFunction = func
|
|
|
|
this.apiAcl.showPasswordDialog = true
|
|
|
|
},
|
|
|
|
runPasswordGuardedFunction() {
|
|
|
|
this.apiAcl.showPasswordDialog = false
|
|
|
|
const func = this.apiAcl.passwordGuardedFunction
|
|
|
|
if (func) {
|
|
|
|
this[func]()
|
|
|
|
}
|
|
|
|
},
|
|
|
|
async addApiACL() {
|
|
|
|
if (!this.apiAcl.newAclName) {
|
|
|
|
this.$q.notify({
|
|
|
|
type: 'warning',
|
|
|
|
message: 'Name is required.'
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const {data} = await LNbits.api.request(
|
|
|
|
'PUT',
|
|
|
|
'/api/v1/auth/acl',
|
|
|
|
null,
|
|
|
|
{
|
|
|
|
id: this.apiAcl.newAclName,
|
|
|
|
name: this.apiAcl.newAclName,
|
|
|
|
password: this.apiAcl.password
|
|
|
|
}
|
|
|
|
)
|
|
|
|
this.apiAcl.data = data.access_control_list
|
|
|
|
const acl = this.apiAcl.data.find(
|
|
|
|
t => t.name === this.apiAcl.newAclName
|
|
|
|
)
|
|
|
|
|
|
|
|
this.handleApiACLSelected(acl.id)
|
|
|
|
this.apiAcl.showNewAclDialog = false
|
|
|
|
this.$q.notify({
|
|
|
|
type: 'positive',
|
|
|
|
message: 'Access Control List created.'
|
|
|
|
})
|
|
|
|
} catch (e) {
|
|
|
|
LNbits.utils.notifyApiError(e)
|
|
|
|
} finally {
|
|
|
|
this.apiAcl.name = ''
|
|
|
|
this.apiAcl.password = ''
|
|
|
|
}
|
|
|
|
|
|
|
|
this.apiAcl.showNewAclDialog = false
|
|
|
|
},
|
|
|
|
|
|
|
|
async updateApiACLs() {
|
|
|
|
try {
|
|
|
|
const {data} = await LNbits.api.request(
|
|
|
|
'PUT',
|
|
|
|
'/api/v1/auth/acl',
|
|
|
|
null,
|
|
|
|
{
|
|
|
|
id: this.user.id,
|
|
|
|
password: this.apiAcl.password,
|
|
|
|
...this.selectedApiAcl
|
|
|
|
}
|
|
|
|
)
|
|
|
|
this.apiAcl.data = data.access_control_list
|
|
|
|
} catch (e) {
|
|
|
|
LNbits.utils.notifyApiError(e)
|
|
|
|
} finally {
|
|
|
|
this.apiAcl.password = ''
|
|
|
|
}
|
|
|
|
},
|
|
|
|
async deleteApiACL() {
|
|
|
|
if (!this.selectedApiAcl.id) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
await LNbits.api.request('DELETE', '/api/v1/auth/acl', null, {
|
|
|
|
id: this.selectedApiAcl.id,
|
|
|
|
password: this.apiAcl.password
|
|
|
|
})
|
|
|
|
this.$q.notify({
|
|
|
|
type: 'positive',
|
|
|
|
message: 'Access Control List deleted.'
|
|
|
|
})
|
|
|
|
} catch (e) {
|
|
|
|
LNbits.utils.notifyApiError(e)
|
|
|
|
} finally {
|
|
|
|
this.apiAcl.password = ''
|
|
|
|
}
|
|
|
|
this.apiAcl.data = this.apiAcl.data.filter(
|
|
|
|
t => t.id !== this.selectedApiAcl.id
|
|
|
|
)
|
|
|
|
this.handleApiACLSelected(this.apiAcl.data[0]?.id)
|
|
|
|
},
|
|
|
|
async generateApiToken() {
|
|
|
|
if (!this.selectedApiAcl.id) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
const expirationTimeMilliseconds =
|
|
|
|
new Date(this.apiAcl.newTokenExpiry) - new Date()
|
|
|
|
try {
|
|
|
|
const {data} = await LNbits.api.request(
|
|
|
|
'POST',
|
|
|
|
'/api/v1/auth/acl/token',
|
|
|
|
null,
|
|
|
|
{
|
|
|
|
acl_id: this.selectedApiAcl.id,
|
|
|
|
token_name: this.apiAcl.newTokenName,
|
|
|
|
password: this.apiAcl.password,
|
|
|
|
expiration_time_minutes: Math.trunc(
|
|
|
|
expirationTimeMilliseconds / 60000
|
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
this.apiAcl.apiToken = data.api_token
|
|
|
|
this.apiAcl.selectedTokenId = data.id
|
|
|
|
Quasar.Notify.create({
|
|
|
|
type: 'positive',
|
|
|
|
message: 'Token Generated.'
|
|
|
|
})
|
|
|
|
|
|
|
|
await this.getApiACLs()
|
|
|
|
this.handleApiACLSelected(this.selectedApiAcl.id)
|
|
|
|
this.apiAcl.showNewTokenDialog = false
|
|
|
|
} catch (e) {
|
|
|
|
LNbits.utils.notifyApiError(e)
|
|
|
|
} finally {
|
|
|
|
this.apiAcl.password = ''
|
|
|
|
}
|
|
|
|
},
|
|
|
|
async deleteToken() {
|
|
|
|
if (!this.apiAcl.selectedTokenId) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
await LNbits.api.request('DELETE', '/api/v1/auth/acl/token', null, {
|
|
|
|
id: this.apiAcl.selectedTokenId,
|
|
|
|
acl_id: this.selectedApiAcl.id,
|
|
|
|
password: this.apiAcl.password
|
|
|
|
})
|
|
|
|
this.$q.notify({
|
|
|
|
type: 'positive',
|
|
|
|
message: 'Token deleted.'
|
|
|
|
})
|
|
|
|
|
|
|
|
this.selectedApiAcl.token_id_list =
|
|
|
|
this.selectedApiAcl.token_id_list.filter(
|
|
|
|
t => t.id !== this.apiAcl.selectedTokenId
|
|
|
|
)
|
|
|
|
this.apiAcl.selectedTokenId = null
|
|
|
|
} catch (e) {
|
|
|
|
LNbits.utils.notifyApiError(e)
|
|
|
|
} finally {
|
|
|
|
this.apiAcl.password = ''
|
|
|
|
}
|
2023-12-12 12:38:19 +02:00
|
|
|
}
|
|
|
|
},
|
2024-12-10 13:42:01 +01:00
|
|
|
async created() {
|
2023-12-12 12:38:19 +02:00
|
|
|
try {
|
|
|
|
const {data} = await LNbits.api.getAuthenticatedUser()
|
|
|
|
this.user = data
|
|
|
|
this.hasUsername = !!data.username
|
2024-10-29 09:58:22 +01:00
|
|
|
if (!this.user.extra) this.user.extra = {}
|
2023-12-12 12:38:19 +02:00
|
|
|
} catch (e) {
|
|
|
|
LNbits.utils.notifyApiError(e)
|
|
|
|
}
|
2024-12-20 08:07:50 +00:00
|
|
|
const hash = window.location.hash.replace('#', '')
|
|
|
|
if (hash) {
|
|
|
|
this.tab = hash
|
|
|
|
}
|
2025-01-16 17:25:27 +02:00
|
|
|
await this.getApiACLs()
|
2023-12-12 12:38:19 +02:00
|
|
|
}
|
2025-01-16 11:23:34 +00:00
|
|
|
}
|