Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ async def create_pay_link(data: CreatePayLinkData) -> PayLink:
created_at=now,
updated_at=now,
disposable=data.disposable if data.disposable is not None else True,
domain=data.domain,
)

await db.insert("lnurlp.pay_links", link)
Expand Down
7 changes: 6 additions & 1 deletion helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@ def parse_nostr_private_key(key: str) -> PrivateKey:
return PrivateKey(bytes.fromhex(key))


def lnurl_encode_link_id(req: Request, link_id: str) -> str:
def lnurl_encode_link(req: Request, link_id: str, domain: str | None = None) -> str:
if domain:
url_str = f"https://{domain}/lnurlp/{link_id}"
return str(lnurl_encode(url_str).bech32)

url = req.url_for("lnurlp.api_lnurl_response", link_id=link_id)
url = url.replace(path=url.path)
url_str = str(url)
if url.netloc.endswith(".onion"):
# change url string scheme to http
url_str = url_str.replace("https://", "http://")

return str(lnurl_encode(url_str).bech32)
22 changes: 20 additions & 2 deletions models.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class CreatePayLinkData(BaseModel):
username: str | None = Query(None)
zaps: bool | None = Query(False)
disposable: bool | None = Query(True)
domain: str | None = Query(None)


class PayLink(BaseModel):
Expand Down Expand Up @@ -67,8 +68,25 @@ class PayLink(BaseModel):
success_url: str | None = None
currency: str | None = None
fiat_base_multiplier: int | None = None

disposable: bool
domain: str | None = None


# TODO deprecated, unused in the code, should be deleted from db.
class PublicPayLink(BaseModel):
id: str
username: str | None = None
description: str
min: float
max: float
domain: str | None = None
currency: str | None = None
lnurl: str | None = Field(
default=None,
no_database=True,
deprecated=True,
description=(
"Deprecated: Instead of using this bech32 encoded string, dynamically "
"generate your own static link (lud17/bech32) on the client side. "
"Example: lnurlp://${window.location.hostname}/lnurlp/${paylink_id}"
),
)
20 changes: 18 additions & 2 deletions static/display.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,26 @@ window.PageLnurlpPublic = {
template: '#page-lnurlp-public',
data() {
return {
url: ''
url: '',
payLink: null
}
},
methods: {
setUrl(link_id, domain) {
this.url = `https://${domain || window.location.host}/lnurlp/${link_id}`
},
getPayLink() {
this.api
.request('GET', `/lnurlp/api/v1/links/public/${this.$route.params.id}`)
.then(res => {
this.payLink = res.data
this.setUrl(this.payLink.id, this.payLink.domain)
})
.catch(this.utils.notifyApiError)
}
},
created() {
this.url = window.location.origin + '/lnurlp/' + this.$route.params.id
this.setUrl(this.$route.params.id)
this.getPayLink()
}
}
8 changes: 7 additions & 1 deletion static/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ window.PageLnurlp = {
}
},
methods: {
lnaddress(link) {
const domain = link.domain || window.location.host
return `${link.username}@${domain}`
},
mapPayLink(obj) {
const locationPath = [
window.location.protocol,
Expand Down Expand Up @@ -140,11 +144,13 @@ window.PageLnurlp = {
(link.success_url ? ' and URL "' + link.success_url + '"' : '')
: 'do nothing',
lnurl: link.lnurl,
domain: link.domain,
pay_url: link.pay_url,
print_url: link.print_url,
username: link.username
}
this.activeUrl = window.location.origin + '/lnurlp/' + link.id
const domain = link.domain || window.location.host
this.activeUrl = `https://${domain}/lnurlp//${link.id}`
this.qrCodeDialog.show = true
},
openUpdateDialog(linkId) {
Expand Down
61 changes: 33 additions & 28 deletions static/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
<span v-text="col.label"></span>
</q-th>
<q-th auto-width></q-th>
<q-th auto-width></q-th>
</q-tr>
</template>
<template v-slot:body="props">
Expand All @@ -55,7 +54,6 @@
><q-tooltip>Shareable Page</q-tooltip></q-btn
>
<q-btn
unelevated
dense
size="xs"
icon="visibility"
Expand All @@ -64,6 +62,27 @@
@click="openQrCodeDialog(props.row.id)"
><q-tooltip>View Link</q-tooltip></q-btn
>
<q-btn
flat
dense
size="xs"
@click="openUpdateDialog(props.row.id)"
icon="edit"
color="light-blue"
class="q-ml-sm"
>
<q-tooltip>Edit</q-tooltip>
</q-btn>
<q-btn
flat
dense
size="xs"
@click="deletePayLink(props.row.id)"
icon="cancel"
color="pink"
class="q-ml-sm"
><q-tooltip>Delete</q-tooltip></q-btn
>
</q-td>
<q-td
v-for="col in props.cols"
Expand Down Expand Up @@ -104,27 +123,6 @@
</q-tooltip>
</q-icon>
</q-td>
<q-td auto-width>
<q-btn
flat
dense
size="xs"
@click="openUpdateDialog(props.row.id)"
icon="edit"
color="light-blue"
>
<q-tooltip>Edit</q-tooltip>
</q-btn>
<q-btn
flat
dense
size="xs"
@click="deletePayLink(props.row.id)"
icon="cancel"
color="pink"
><q-tooltip>Delete</q-tooltip></q-btn
>
</q-td>
</q-tr>
</template>
</q-table>
Expand Down Expand Up @@ -402,10 +400,17 @@
"
/>
</div>
<div class="col" style="margin-top: 10px">
<span class="label">
&nbsp;@&nbsp;<span v-text="domain"></span>
</span>
<div class="col" style="flex: 0 0 auto; margin-top: 10px">
<span class="label"> &nbsp;@&nbsp; </span>
</div>
<div class="col">
<q-input
filled
dense
v-model.trim="formDialog.data.domain"
type="text"
:label="domain"
/>
</div>
</div>
<div class="row q-col-gutter-sm q-mx-sm">
Expand Down Expand Up @@ -642,7 +647,7 @@
<span v-text="qrCodeDialog.data.success"></span><br />
<span v-if="qrCodeDialog.data.username">
<strong>Lightning Address: </strong>
<span v-text="qrCodeDialog.data.username + '@' + domain"></span>
<span v-text="lnaddress(qrCodeDialog.data)"></span>
<br />
</span>
</p>
Expand Down
30 changes: 20 additions & 10 deletions views_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@
update_lnurlp_settings,
update_pay_link,
)
from .helpers import lnurl_encode_link_id, parse_nostr_private_key
from .models import CreatePayLinkData, LnurlpSettings, PayLink
from .helpers import lnurl_encode_link, parse_nostr_private_key
from .models import CreatePayLinkData, LnurlpSettings, PayLink, PublicPayLink

lnurlp_api_router = APIRouter()


def check_lnurl_encode(req: Request, link_id: str) -> str:
def check_lnurl_encode(req: Request, link: PayLink) -> str:
try:
return lnurl_encode_link_id(req, link_id)
return lnurl_encode_link(req, link.id, link.domain)
except InvalidUrl as exc:
raise HTTPException(
detail=(
Expand Down Expand Up @@ -60,11 +60,11 @@ async def api_links(

links = await get_pay_links(wallet_ids)
for link in links:
link.lnurl = check_lnurl_encode(req=req, link_id=link.id)
link.lnurl = check_lnurl_encode(req, link)
return links


@lnurlp_api_router.get("/api/v1/links/{link_id}", status_code=HTTPStatus.OK)
@lnurlp_api_router.get("/api/v1/links/{link_id}")
async def api_link_retrieve(
req: Request, link_id: str, key_info: WalletTypeInfo = Depends(require_invoice_key)
) -> PayLink:
Expand All @@ -85,7 +85,18 @@ async def api_link_retrieve(
detail="Not your pay link.", status_code=HTTPStatus.FORBIDDEN
)

link.lnurl = check_lnurl_encode(req, link.id)
link.lnurl = check_lnurl_encode(req, link)
return link


@lnurlp_api_router.get("/api/v1/links/public/{link_id}", response_model=PublicPayLink)
async def api_link_public_retrieve(req: Request, link_id: str) -> PayLink:
link = await get_pay_link(link_id)
if not link:
raise HTTPException(
detail="Pay link does not exist.", status_code=HTTPStatus.NOT_FOUND
)
link.lnurl = lnurl_encode_link(req, link.id, link.domain)
return link


Expand Down Expand Up @@ -168,7 +179,7 @@ async def api_link_create_or_update(
detail="Wallet does not exist.", status_code=HTTPStatus.FORBIDDEN
)

# admins are allowed to create/edit paylinks beloging to regular users
# admins are allowed to create/edit paylinks belonging to regular users
user = await get_user(key_info.wallet.user)
admin_user = user.admin if user else False
if not admin_user and new_wallet.user != key_info.wallet.user:
Expand Down Expand Up @@ -197,8 +208,7 @@ async def api_link_create_or_update(

link = await create_pay_link(data)

link.lnurl = check_lnurl_encode(req=req, link_id=link.id)

link.lnurl = check_lnurl_encode(req, link)
return link


Expand Down
4 changes: 2 additions & 2 deletions views_lnurl.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ async def api_lnurl_callback(
extra["nostr"] = nostr # put it here for later publishing in tasks.py

if link.username:
identifier = f"{link.username}@{request.url.netloc}"
identifier = f"{link.username}@{link.domain or request.url.netloc}"
text = f"Payment to {link.username}"
_metadata = [["text/plain", text], ["text/identifier", identifier]]
extra["lnaddress"] = identifier
Expand Down Expand Up @@ -173,7 +173,7 @@ async def api_lnurl_response(
callback_url = parse_obj_as(CallbackUrl, str(url))

if link.username:
identifier = f"{link.username}@{request.url.netloc}"
identifier = f"{link.username}@{link.domain or request.url.netloc}"
text = f"Payment to {link.username}"
metadata = [["text/plain", text], ["text/identifier", identifier]]
else:
Expand Down