Auto-provision merchant from account keypair on first access
Some checks failed
ci.yml / Auto-provision merchant from account keypair on first access (pull_request) Failing after 0s
Some checks failed
ci.yml / Auto-provision merchant from account keypair on first access (pull_request) Failing after 0s
The LNbits user account IS the merchant identity. GET /api/v1/merchant now auto-creates the merchant record using the account's existing Nostr keypair if one doesn't exist yet, so the extension is immediately usable without any setup screen. - Extract _auto_create_merchant() helper used by both GET and POST - Remove welcome/key-generation screen (replaced with loading spinner) - Remove dead frontend code (generateKeys, importKeys dialogs) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1b39744daa
commit
8606dce908
3 changed files with 62 additions and 136 deletions
|
|
@ -13,19 +13,6 @@ window.app = Vue.createApp({
|
||||||
orderPubkey: null,
|
orderPubkey: null,
|
||||||
showKeys: false,
|
showKeys: false,
|
||||||
stallCount: 0,
|
stallCount: 0,
|
||||||
importKeyDialog: {
|
|
||||||
show: false,
|
|
||||||
data: {
|
|
||||||
privateKey: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
generateKeyDialog: {
|
|
||||||
show: false,
|
|
||||||
privateKey: null,
|
|
||||||
nsec: null,
|
|
||||||
npub: null,
|
|
||||||
showNsec: false
|
|
||||||
},
|
|
||||||
wsConnection: null,
|
wsConnection: null,
|
||||||
nostrStatus: {
|
nostrStatus: {
|
||||||
connected: false,
|
connected: false,
|
||||||
|
|
@ -49,23 +36,6 @@ window.app = Vue.createApp({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
generateKeys: async function () {
|
|
||||||
// No longer need to generate keys here - the backend will use user's existing keypairs
|
|
||||||
await this.createMerchant()
|
|
||||||
},
|
|
||||||
importKeys: async function () {
|
|
||||||
this.importKeyDialog.show = false
|
|
||||||
// Import keys functionality removed since we use user's native keypairs
|
|
||||||
// Show a message that this is no longer needed
|
|
||||||
this.$q.notify({
|
|
||||||
type: 'info',
|
|
||||||
message: 'Merchants now use your account Nostr keys automatically. Key import is no longer needed.',
|
|
||||||
timeout: 3000
|
|
||||||
})
|
|
||||||
},
|
|
||||||
showImportKeysDialog: async function () {
|
|
||||||
this.importKeyDialog.show = true
|
|
||||||
},
|
|
||||||
toggleShowKeys: function () {
|
toggleShowKeys: function () {
|
||||||
this.showKeys = !this.showKeys
|
this.showKeys = !this.showKeys
|
||||||
},
|
},
|
||||||
|
|
@ -379,7 +349,11 @@ window.app = Vue.createApp({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created: async function () {
|
created: async function () {
|
||||||
await this.getMerchant()
|
const merchant = await this.getMerchant()
|
||||||
|
if (!merchant) {
|
||||||
|
// Auto-create merchant using the account's existing Nostr keypair
|
||||||
|
await this.createMerchant()
|
||||||
|
}
|
||||||
await this.checkNostrStatus()
|
await this.checkNostrStatus()
|
||||||
setInterval(async () => {
|
setInterval(async () => {
|
||||||
if (
|
if (
|
||||||
|
|
|
||||||
|
|
@ -124,58 +124,9 @@
|
||||||
</q-card>
|
</q-card>
|
||||||
</div>
|
</div>
|
||||||
<q-card v-else>
|
<q-card v-else>
|
||||||
<q-card-section>
|
<q-card-section class="text-center q-pa-xl">
|
||||||
<span class="text-h4">Welcome to Nostr Market!</span><br />
|
<q-spinner color="primary" size="3em" class="q-mb-md"></q-spinner>
|
||||||
In Nostr Market, merchant and customer communicate via NOSTR relays, so
|
<div class="text-h6">Setting up Nostr Market...</div>
|
||||||
loss of money, product information, and reputation become far less
|
|
||||||
likely if attacked.
|
|
||||||
</q-card-section>
|
|
||||||
<q-card-section>
|
|
||||||
<span class="text-h4">Terms</span><br />
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<span class="text-bold">merchant</span> - seller of products with
|
|
||||||
NOSTR key-pair
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<span class="text-bold">customer</span> - buyer of products with
|
|
||||||
NOSTR key-pair
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<span class="text-bold">product</span> - item for sale by the
|
|
||||||
merchant
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<span class="text-bold">stall</span> - list of products controlled
|
|
||||||
by merchant (a merchant can have multiple stalls)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<span class="text-bold">marketplace</span> - clientside software for
|
|
||||||
searching stalls and purchasing products
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</q-card-section>
|
|
||||||
<q-card-section>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12">
|
|
||||||
<q-btn
|
|
||||||
@click="showImportKeysDialog"
|
|
||||||
label="Import Key"
|
|
||||||
color="primary"
|
|
||||||
class="float-left"
|
|
||||||
>
|
|
||||||
<q-tooltip> Use an existing private key (hex or npub) </q-tooltip>
|
|
||||||
</q-btn>
|
|
||||||
<q-btn
|
|
||||||
label="Generate New Key"
|
|
||||||
color="green"
|
|
||||||
@click="generateKeys"
|
|
||||||
class="float-right"
|
|
||||||
>
|
|
||||||
<q-tooltip> A new key pair will be generated for you </q-tooltip>
|
|
||||||
</q-btn>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
53
views_api.py
53
views_api.py
|
|
@ -93,31 +93,21 @@ from .services import (
|
||||||
######################################## MERCHANT ######################################
|
######################################## MERCHANT ######################################
|
||||||
|
|
||||||
|
|
||||||
@nostrmarket_ext.post("/api/v1/merchant")
|
async def _auto_create_merchant(
|
||||||
async def api_create_merchant(
|
wallet: WalletTypeInfo,
|
||||||
data: CreateMerchantRequest,
|
config: MerchantConfig | None = None,
|
||||||
wallet: WalletTypeInfo = Depends(require_admin_key),
|
|
||||||
) -> Merchant:
|
) -> Merchant:
|
||||||
|
"""
|
||||||
try:
|
Provision a merchant record from the user's account keypair.
|
||||||
# Check if merchant already exists for this user
|
Called automatically on first GET or explicitly via POST.
|
||||||
merchant = await get_merchant_for_user(wallet.wallet.user)
|
"""
|
||||||
assert merchant is None, "A merchant already exists for this user"
|
|
||||||
|
|
||||||
# Get user's account to access their Nostr keypairs
|
|
||||||
account = await get_account(wallet.wallet.user)
|
account = await get_account(wallet.wallet.user)
|
||||||
if not account:
|
assert account, "User account not found"
|
||||||
raise HTTPException(
|
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
|
||||||
detail="User account not found",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check if user has Nostr keypairs, generate them if not
|
# In our fork, accounts always have keypairs.
|
||||||
|
# Generate as fallback only if somehow missing.
|
||||||
if not account.pubkey or not account.prvkey:
|
if not account.pubkey or not account.prvkey:
|
||||||
# Generate new keypair for user
|
|
||||||
private_key, public_key = generate_keypair()
|
private_key, public_key = generate_keypair()
|
||||||
|
|
||||||
# Update user account with new keypairs
|
|
||||||
account.pubkey = public_key
|
account.pubkey = public_key
|
||||||
account.prvkey = private_key
|
account.prvkey = private_key
|
||||||
await update_account(account)
|
await update_account(account)
|
||||||
|
|
@ -125,15 +115,13 @@ async def api_create_merchant(
|
||||||
public_key = account.pubkey
|
public_key = account.pubkey
|
||||||
private_key = account.prvkey
|
private_key = account.prvkey
|
||||||
|
|
||||||
# Check if another merchant is already using this public key
|
|
||||||
existing_merchant = await get_merchant_by_pubkey(public_key)
|
existing_merchant = await get_merchant_by_pubkey(public_key)
|
||||||
assert existing_merchant is None, "A merchant already uses this public key"
|
assert existing_merchant is None, "A merchant already uses this public key"
|
||||||
|
|
||||||
# Create PartialMerchant with user's keypairs
|
|
||||||
partial_merchant = PartialMerchant(
|
partial_merchant = PartialMerchant(
|
||||||
private_key=private_key,
|
private_key=private_key,
|
||||||
public_key=public_key,
|
public_key=public_key,
|
||||||
config=data.config
|
config=config or MerchantConfig(),
|
||||||
)
|
)
|
||||||
|
|
||||||
merchant = await create_merchant(wallet.wallet.user, partial_merchant)
|
merchant = await create_merchant(wallet.wallet.user, partial_merchant)
|
||||||
|
|
@ -150,10 +138,22 @@ async def api_create_merchant(
|
||||||
)
|
)
|
||||||
|
|
||||||
await resubscribe_to_all_merchants()
|
await resubscribe_to_all_merchants()
|
||||||
|
|
||||||
await nostr_client.merchant_temp_subscription(public_key)
|
await nostr_client.merchant_temp_subscription(public_key)
|
||||||
|
|
||||||
return merchant
|
return merchant
|
||||||
|
|
||||||
|
|
||||||
|
@nostrmarket_ext.post("/api/v1/merchant")
|
||||||
|
async def api_create_merchant(
|
||||||
|
data: CreateMerchantRequest,
|
||||||
|
wallet: WalletTypeInfo = Depends(require_admin_key),
|
||||||
|
) -> Merchant:
|
||||||
|
|
||||||
|
try:
|
||||||
|
merchant = await get_merchant_for_user(wallet.wallet.user)
|
||||||
|
assert merchant is None, "A merchant already exists for this user"
|
||||||
|
|
||||||
|
return await _auto_create_merchant(wallet, data.config)
|
||||||
except AssertionError as ex:
|
except AssertionError as ex:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST,
|
status_code=HTTPStatus.BAD_REQUEST,
|
||||||
|
|
@ -170,12 +170,13 @@ async def api_create_merchant(
|
||||||
@nostrmarket_ext.get("/api/v1/merchant")
|
@nostrmarket_ext.get("/api/v1/merchant")
|
||||||
async def api_get_merchant(
|
async def api_get_merchant(
|
||||||
wallet: WalletTypeInfo = Depends(require_invoice_key),
|
wallet: WalletTypeInfo = Depends(require_invoice_key),
|
||||||
) -> Optional[Merchant]:
|
) -> Merchant:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
merchant = await get_merchant_for_user(wallet.wallet.user)
|
merchant = await get_merchant_for_user(wallet.wallet.user)
|
||||||
if not merchant:
|
if not merchant:
|
||||||
return None
|
# Auto-provision merchant from the user's account keypair
|
||||||
|
merchant = await _auto_create_merchant(wallet)
|
||||||
|
|
||||||
merchant = await touch_merchant(wallet.wallet.user, merchant.id)
|
merchant = await touch_merchant(wallet.wallet.user, merchant.id)
|
||||||
assert merchant
|
assert merchant
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue