Reset wallet keys (#2929)

This commit is contained in:
Tiago Vasconcelos 2025-02-06 13:07:36 +00:00 committed by GitHub
parent 34a959f0bc
commit 432b3a0fe0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 94 additions and 27 deletions

View File

@ -233,4 +233,14 @@
</q-card-section>
</q-card>
</q-expansion-item>
<q-separator></q-separator>
<q-card-section>
<p v-text="$t('reset_wallet_keys_desc')"></p>
<q-btn
unelevated
color="red-10"
@click="resetKeys()"
:label="$t('reset_wallet_keys')"
></q-btn>
</q-card-section>
</q-expansion-item>

View File

@ -1,5 +1,6 @@
from http import HTTPStatus
from typing import Optional
from uuid import uuid4
from fastapi import (
APIRouter,
@ -8,13 +9,10 @@ from fastapi import (
HTTPException,
)
from lnbits.core.models import (
CreateWallet,
KeyType,
Wallet,
)
from lnbits.core.models import CreateWallet, KeyType, User, Wallet
from lnbits.decorators import (
WalletTypeInfo,
check_user_exists,
require_admin_key,
require_invoice_key,
)
@ -56,6 +54,20 @@ async def api_update_wallet_name(
}
@wallet_router.put("/reset/{wallet_id}")
async def api_reset_wallet_keys(
wallet_id: str, user: User = Depends(check_user_exists)
) -> Wallet:
wallet = await get_wallet(wallet_id)
if not wallet or wallet.user != user.id:
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="Wallet not found")
wallet.adminkey = uuid4().hex
wallet.inkey = uuid4().hex
await update_wallet(wallet)
return wallet
@wallet_router.patch("")
async def api_update_wallet(
name: Optional[str] = Body(None),
@ -75,13 +87,17 @@ async def api_update_wallet(
return wallet
@wallet_router.delete("")
@wallet_router.delete("/{wallet_id}")
async def api_delete_wallet(
wallet: WalletTypeInfo = Depends(require_admin_key),
wallet_id: str, user: User = Depends(check_user_exists)
) -> None:
wallet = await get_wallet(wallet_id)
if not wallet or wallet.user != user.id:
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="Wallet not found")
await delete_wallet(
user_id=wallet.wallet.user,
wallet_id=wallet.wallet.id,
user_id=wallet.user,
wallet_id=wallet.id,
)

File diff suppressed because one or more lines are too long

View File

@ -505,5 +505,8 @@ window.localisation.en = {
payments_balance_chart: 'Balance Chart',
payments_wallets_chart: 'Wallets Chart',
payments_balance_in_out_chart: 'Balance In/Out Chart',
payments_count_in_out_chart: 'Count In/Out Chart'
payments_count_in_out_chart: 'Count In/Out Chart',
reset_wallet_keys: 'Reset Keys',
reset_wallet_keys_desc:
'Reset the API keys for this wallet. This will invalidate the current keys and generate new ones.'
}

View File

@ -132,15 +132,20 @@ window.LNbits = {
name: name
})
},
deleteWallet(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
resetWalletKeys(wallet) {
return this.request('put', `/api/v1/wallet/reset/${wallet.id}`).then(
res => {
return res.data
}
)
},
deleteWallet(wallet) {
return this.request('delete', `/api/v1/wallet/${wallet.id}`).then(_ => {
let url = new URL(window.location.href)
url.searchParams.delete('wal')
window.location = url
})
},
getPayments(wallet, params) {
return this.request(
'get',

View File

@ -564,6 +564,40 @@ window.WalletPageLogic = {
}
})
},
resetKeys() {
LNbits.utils
.confirmDialog('Are you sure you want to reset your API keys?')
.onOk(() => {
LNbits.api
.resetWalletKeys(this.g.wallet)
.then(response => {
const {id, adminkey, inkey} = response
this.g.wallet = {
...this.g.wallet,
inkey,
adminkey
}
const walletIndex = this.g.user.wallets.findIndex(
wallet => wallet.id === id
)
if (walletIndex !== -1) {
this.g.user.wallets[walletIndex] = {
...this.g.user.wallets[walletIndex],
inkey,
adminkey
}
}
Quasar.Notify.create({
timeout: 3500,
type: 'positive',
message: 'API keys reset!'
})
})
.catch(err => {
LNbits.utils.notifyApiError(err)
})
})
},
updateWallet(data) {
LNbits.api
.request('PATCH', '/api/v1/wallet', this.g.wallet.adminkey, data)

View File

@ -35,12 +35,14 @@ async def test_create_account(client, settings: Settings):
assert "user" in result
# check POST and DELETE /api/v1/wallet with adminkey:
# check POST and DELETE /api/v1/wallet with adminkey and user token:
# create additional wallet and delete it
@pytest.mark.anyio
async def test_create_wallet_and_delete(client, adminkey_headers_to):
async def test_create_wallet_and_delete(
client, adminkey_headers_from, user_headers_from
):
response = await client.post(
"/api/v1/wallet", json={"name": "test"}, headers=adminkey_headers_to
"/api/v1/wallet", json={"name": "test"}, headers=adminkey_headers_from
)
assert response.status_code == 200
result = response.json()
@ -51,20 +53,17 @@ async def test_create_wallet_and_delete(client, adminkey_headers_to):
assert "adminkey" in result
invalid_response = await client.delete(
"/api/v1/wallet",
f"/api/v1/wallet/{result['id']}",
headers={
"X-Api-Key": result["inkey"],
"X-Api-Key": result["adminkey"],
"Content-type": "application/json",
},
)
assert invalid_response.status_code == 401
response = await client.delete(
"/api/v1/wallet",
headers={
"X-Api-Key": result["adminkey"],
"Content-type": "application/json",
},
f"/api/v1/wallet/{result['id']}",
headers=user_headers_from,
)
assert response.status_code == 200