feat: send simple DM
This commit is contained in:
parent
77f7c0b18f
commit
5d906c1fda
4 changed files with 122 additions and 6 deletions
19
helpers.py
Normal file
19
helpers.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
from bech32 import bech32_decode, convertbits
|
||||
|
||||
|
||||
def normalize_public_key(pubkey: str) -> str:
|
||||
if pubkey.startswith("npub1"):
|
||||
_, decoded_data = bech32_decode(pubkey)
|
||||
if not decoded_data:
|
||||
raise ValueError("Public Key is not valid npub")
|
||||
|
||||
decoded_data_bits = convertbits(decoded_data, 5, 8, False)
|
||||
if not decoded_data_bits:
|
||||
raise ValueError("Public Key is not valid npub")
|
||||
return bytes(decoded_data_bits).hex()
|
||||
|
||||
# check if valid hex
|
||||
if len(pubkey) != 64:
|
||||
raise ValueError("Public Key is not valid hex")
|
||||
int(pubkey, 16)
|
||||
return pubkey
|
||||
|
|
@ -58,7 +58,7 @@ class TestMessage(BaseModel):
|
|||
class TestMessageResponse(BaseModel):
|
||||
private_key: str
|
||||
public_key: str
|
||||
event: Event
|
||||
event_json: str
|
||||
|
||||
# class nostrKeys(BaseModel):
|
||||
# pubkey: str
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@
|
|||
filled
|
||||
rows="3"
|
||||
type="textarea"
|
||||
label="Test Message"
|
||||
label="Test Message *"
|
||||
></q-input>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -181,7 +181,7 @@
|
|||
<div class="col-3"></div>
|
||||
<div class="col-9">
|
||||
<q-badge color="yellow" text-color="black">
|
||||
<span>This is the recipient of the message</span>
|
||||
<span>This is the recipient of the message. Field required.</span>
|
||||
</q-badge>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -189,6 +189,7 @@
|
|||
<div class="col-12">
|
||||
<q-btn
|
||||
:disabled="!testData.recieverPublicKey || !testData.message"
|
||||
@click="sendTestMessage"
|
||||
unelevated
|
||||
color="primary"
|
||||
class="float-right"
|
||||
|
|
@ -197,6 +198,25 @@
|
|||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-separator></q-separator>
|
||||
<q-card-section>
|
||||
<div class="row q-mt-md">
|
||||
<div class="col-3">
|
||||
<span>Sent Data:</span>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<q-input
|
||||
outlined
|
||||
v-model="testData.sentData"
|
||||
dense
|
||||
filled
|
||||
readonly
|
||||
rows="5"
|
||||
type="textarea"
|
||||
></q-input>
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
|
||||
|
|
@ -258,9 +278,12 @@
|
|||
nostrrelayLinks: [],
|
||||
filter: '',
|
||||
testData: {
|
||||
wsConnection: null,
|
||||
senderPrivateKey: null,
|
||||
recieverPublicKey: null,
|
||||
message: null
|
||||
message: null,
|
||||
sentData: '',
|
||||
receivedData: ''
|
||||
},
|
||||
relayTable: {
|
||||
columns: [
|
||||
|
|
@ -368,6 +391,64 @@
|
|||
LNbits.utils.notifyApiError(error)
|
||||
})
|
||||
},
|
||||
sendTestMessage: async function(){
|
||||
try {
|
||||
const {data} = await LNbits.api.request(
|
||||
'PUT',
|
||||
'/nostrclient/api/v1/relay/test?usr=' + this.g.user.id,
|
||||
this.g.user.wallets[0].adminkey,
|
||||
{
|
||||
sender_private_key: this.testData.senderPrivateKey,
|
||||
reciever_public_key: this.testData.recieverPublicKey,
|
||||
message: this.testData.message
|
||||
}
|
||||
)
|
||||
console.log('### data', data)
|
||||
this.testData.senderPrivateKey = data.private_key
|
||||
this.$q.localStorage.set('lnbits.nostrclient.senderPrivateKey', data.private_key || '')
|
||||
const event = JSON.parse(data.event_json)[1]
|
||||
console.log('### event', event)
|
||||
this.sendDataToWebSocket(data.event_json)
|
||||
} catch (error) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
}
|
||||
},
|
||||
|
||||
sendDataToWebSocket: async function (data){
|
||||
try {
|
||||
if (!this.testData.wsConnection) {
|
||||
this.connectToWebsocket()
|
||||
}
|
||||
this.testData.wsConnection.send(data)
|
||||
this.testData.sentData = data + '\n' + this.testData.sentData
|
||||
} catch (error) {
|
||||
this.$q.notify({
|
||||
timeout: 5000,
|
||||
type: 'warning',
|
||||
message: 'Failed to connect to websocket',
|
||||
caption: `${error}`
|
||||
})
|
||||
}
|
||||
},
|
||||
connectToWebsocket: function () {
|
||||
const scheme = location.protocol === 'http:' ? 'ws' : 'wss'
|
||||
const port = location.port ? `:${location.port}` : ''
|
||||
const wsUrl = `${scheme}://${document.domain}${port}/nostrclient/api/v1/relay`
|
||||
this.testData.wsConnection = new WebSocket(wsUrl)
|
||||
wsConnection.onmessage = async e => {
|
||||
// const data = JSON.parse(e.data)
|
||||
console.log('### onmessage', e.data)
|
||||
}
|
||||
wsConnection.onerror = async e => {
|
||||
// const data = JSON.parse(e.data)
|
||||
console.log('### onerror', e.data)
|
||||
}
|
||||
wsConnection.onclose = async e => {
|
||||
// const data = JSON.parse(e.data)
|
||||
console.log('### onclose', e.data)
|
||||
}
|
||||
|
||||
},
|
||||
exportlnurldeviceCSV: function () {
|
||||
var self = this
|
||||
LNbits.utils.exportCSV(self.relayTable.columns, this.nostrLinks)
|
||||
|
|
@ -377,6 +458,7 @@
|
|||
var self = this
|
||||
this.getRelays()
|
||||
setInterval(this.getRelays, 5000)
|
||||
this.testData.senderPrivateKey = this.$q.localStorage.getItem('lnbits.nostrclient.senderPrivateKey') || ''
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
19
views_api.py
19
views_api.py
|
|
@ -1,4 +1,5 @@
|
|||
import asyncio
|
||||
import json
|
||||
from http import HTTPStatus
|
||||
from typing import Optional
|
||||
|
||||
|
|
@ -11,7 +12,9 @@ from lnbits.helpers import urlsafe_short_hash
|
|||
|
||||
from . import nostrclient_ext, scheduled_tasks
|
||||
from .crud import add_relay, delete_relay, get_relays
|
||||
from .helpers import normalize_public_key
|
||||
from .models import Relay, RelayList, TestMessage, TestMessageResponse
|
||||
from .nostr.key import EncryptedDirectMessage, PrivateKey
|
||||
from .services import NostrRouter, nostr
|
||||
from .tasks import init_relays
|
||||
|
||||
|
|
@ -78,9 +81,21 @@ async def api_delete_relay(relay: Relay) -> None:
|
|||
@nostrclient_ext.put(
|
||||
"/api/v1/relay/test", status_code=HTTPStatus.OK, dependencies=[Depends(check_admin)]
|
||||
)
|
||||
async def api_test_endpoint(test_message: TestMessage) -> TestMessageResponse:
|
||||
async def api_test_endpoint(data: TestMessage) -> TestMessageResponse:
|
||||
try:
|
||||
print("### api_test_endpoint", test_message)
|
||||
to_public_key = normalize_public_key(data.reciever_public_key)
|
||||
|
||||
pk = bytes.fromhex(data.sender_private_key) if data.sender_private_key else None
|
||||
private_key = PrivateKey(pk)
|
||||
|
||||
dm = EncryptedDirectMessage(
|
||||
recipient_pubkey=to_public_key, cleartext_content=data.message
|
||||
)
|
||||
private_key.sign_event(dm)
|
||||
|
||||
print("### api_test_endpoint", data)
|
||||
|
||||
return TestMessageResponse(private_key=private_key.hex(), public_key=to_public_key, event_json=dm.to_message())
|
||||
except (ValueError, AssertionError) as ex:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue