chore: code format

This commit is contained in:
Vlad Stan
2026-07-01 16:57:20 +03:00
parent d591dc65a1
commit d0ed95fe42
3 changed files with 143 additions and 151 deletions
+2 -1
View File
@@ -332,9 +332,10 @@ def _add_wasm_extension_frame_route(
response.headers["Cache-Control"] = "no-store" response.headers["Cache-Control"] = "no-store"
response.headers["Cross-Origin-Opener-Policy"] = "same-origin" response.headers["Cross-Origin-Opener-Policy"] = "same-origin"
response.headers["Cross-Origin-Resource-Policy"] = "same-origin" response.headers["Cross-Origin-Resource-Policy"] = "same-origin"
# for access will use the bridge API, but we don't want to allow any other access
response.headers["Permissions-Policy"] = ( response.headers["Permissions-Policy"] = (
"camera=(), microphone=(), geolocation=(), payment=(), " "camera=(), microphone=(), geolocation=(), payment=(), "
"clipboard-read=(), clipboard-write=(), usb=()" "clipboard-read=(), usb=()"
) )
response.headers["Referrer-Policy"] = "no-referrer" response.headers["Referrer-Policy"] = "no-referrer"
response.headers["X-Content-Type-Options"] = "nosniff" response.headers["X-Content-Type-Options"] = "nosniff"
@@ -37,10 +37,7 @@
><span v-text="extension.name"></span> ><span v-text="extension.name"></span>
</q-item-label> </q-item-label>
</q-item-section> </q-item-section>
<q-item-section <q-item-section side v-show="extensionActive(extension)">
side
v-show="extensionActive(extension)"
>
<q-icon name="chevron_right" color="grey-5" size="md"></q-icon> <q-icon name="chevron_right" color="grey-5" size="md"></q-icon>
</q-item-section> </q-item-section>
</q-item> </q-item>
+140 -146
View File
@@ -1,164 +1,158 @@
{% extends "base.html" %} {% extends "base.html" %} {% block styles %}
<style>
.wasm-extension-frame {
border: 0;
display: block;
height: calc(100vh - 56px);
min-height: calc(100vh - 56px);
width: 100%;
}
</style>
{% endblock %} {% block page_container %}
<q-page-container>
<q-page class="q-pa-none">
<iframe
id="lnbits-wasm-extension-frame"
class="wasm-extension-frame"
src="{{ frame_url }}"
title="{{ extension.name }}"
sandbox="allow-scripts allow-forms"
referrerpolicy="no-referrer"
></iframe>
</q-page>
</q-page-container>
{% endblock %} {% block scripts %}
<script>
;(() => {
const bridge = {{ bridge | tojson | safe }}
{% block styles %} function extensionFrameWindow() {
<style> return document.getElementById('lnbits-wasm-extension-frame')
.wasm-extension-frame { ?.contentWindow
border: 0;
display: block;
height: calc(100vh - 56px);
min-height: calc(100vh - 56px);
width: 100%;
} }
</style>
{% endblock %}
{% block page_container %} function sendResponse(targetWindow, id, payload) {
<q-page-container> targetWindow?.postMessage(
<q-page class="q-pa-none"> {
<iframe type: 'lnbits-extension:response',
id="lnbits-wasm-extension-frame" id,
class="wasm-extension-frame" ...payload
src="{{ frame_url }}" },
title="{{ extension.name }}" '*'
sandbox="allow-scripts allow-forms" )
referrerpolicy="no-referrer" }
></iframe>
</q-page>
</q-page-container>
{% endblock %}
{% block scripts %} function allowedApiRoute(method, path) {
<script> let url
;(() => { try {
const bridge = {{ bridge | tojson | safe }} url = new URL(path, window.location.origin)
} catch (_error) {
return false
}
if (url.origin !== window.location.origin) return false
function extensionFrameWindow() { method = String(method || 'GET').toUpperCase()
return document.getElementById('lnbits-wasm-extension-frame') return bridge.apiRoutes.some(route => {
?.contentWindow return (
route.method === method &&
new RegExp(route.pattern).test(url.pathname)
)
})
}
async function callApi(message) {
const method = String(message.method || 'GET').toUpperCase()
const path = String(message.path || '')
if (!allowedApiRoute(method, path)) {
throw new Error('Extension API route is not allowed.')
} }
function sendResponse(targetWindow, id, payload) { const options = {
targetWindow?.postMessage( method,
{ headers: {},
type: 'lnbits-extension:response', credentials: 'same-origin'
id, }
...payload if (message.body !== undefined && message.body !== null) {
}, options.headers['content-type'] = 'application/json'
'*' options.body = JSON.stringify(message.body)
}
const response = await fetch(path, options)
const text = await response.text()
let data = text
if (text) {
try {
data = JSON.parse(text)
} catch (_error) {
data = text
}
}
if (!response.ok) {
throw new Error(
typeof data === 'object' && data.detail ? data.detail : text
) )
} }
return data
}
function allowedApiRoute(method, path) { function notify(message) {
let url const level = ['positive', 'negative', 'warning', 'info'].includes(
try { message.level
url = new URL(path, window.location.origin) )
} catch (_error) { ? message.level
return false : 'info'
} if (window.Quasar?.Notify) {
if (url.origin !== window.location.origin) return false window.Quasar.Notify.create({
color: level,
method = String(method || 'GET').toUpperCase() message: String(message.message || '')
return bridge.apiRoutes.some(route => {
return (
route.method === method &&
new RegExp(route.pattern).test(url.pathname)
)
}) })
} }
}
async function callApi(message) { window.addEventListener('message', async event => {
const method = String(message.method || 'GET').toUpperCase() if (event.source !== extensionFrameWindow()) return
const path = String(message.path || '') const message = event.data
if (!allowedApiRoute(method, path)) { if (!message || message.type !== 'lnbits-extension:request') return
throw new Error('Extension API route is not allowed.')
}
const options = { try {
method, if (message.action === 'context') {
headers: {},
credentials: 'same-origin'
}
if (message.body !== undefined && message.body !== null) {
options.headers['content-type'] = 'application/json'
options.body = JSON.stringify(message.body)
}
const response = await fetch(path, options)
const text = await response.text()
let data = text
if (text) {
try {
data = JSON.parse(text)
} catch (_error) {
data = text
}
}
if (!response.ok) {
throw new Error(
typeof data === 'object' && data.detail ? data.detail : text
)
}
return data
}
function notify(message) {
const level = ['positive', 'negative', 'warning', 'info'].includes(
message.level
)
? message.level
: 'info'
if (window.Quasar?.Notify) {
window.Quasar.Notify.create({
color: level,
message: String(message.message || '')
})
}
}
window.addEventListener('message', async event => {
if (event.source !== extensionFrameWindow()) return
const message = event.data
if (!message || message.type !== 'lnbits-extension:request') return
try {
if (message.action === 'context') {
sendResponse(event.source, message.id, {
ok: true,
data: {
extensionId: bridge.extensionId,
public: bridge.public,
routeParams: bridge.routeParams,
query: bridge.query
}
})
return
}
if (message.action === 'api') {
sendResponse(event.source, message.id, {
ok: true,
data: await callApi(message)
})
return
}
if (message.action === 'ui.notify') {
notify(message)
sendResponse(event.source, message.id, {
ok: true,
data: {ok: true}
})
return
}
throw new Error('Unknown extension bridge action.')
} catch (error) {
sendResponse(event.source, message.id, { sendResponse(event.source, message.id, {
ok: false, ok: true,
error: error instanceof Error ? error.message : String(error) data: {
extensionId: bridge.extensionId,
public: bridge.public,
routeParams: bridge.routeParams,
query: bridge.query
}
}) })
return
} }
})
})() if (message.action === 'api') {
</script> sendResponse(event.source, message.id, {
ok: true,
data: await callApi(message)
})
return
}
if (message.action === 'ui.notify') {
notify(message)
sendResponse(event.source, message.id, {
ok: true,
data: {ok: true}
})
return
}
throw new Error('Unknown extension bridge action.')
} catch (error) {
sendResponse(event.source, message.id, {
ok: false,
error: error instanceof Error ? error.message : String(error)
})
}
})
})()
</script>
{% endblock %} {% endblock %}