chore: code format
This commit is contained in:
parent
366dae2082
commit
58723a387f
6 changed files with 52 additions and 42 deletions
|
|
@ -106,8 +106,6 @@ class NostrClientConnection:
|
||||||
] = None
|
] = None
|
||||||
self.get_client_config: Optional[Callable[[], RelaySpec]] = None
|
self.get_client_config: Optional[Callable[[], RelaySpec]] = None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def start(self):
|
async def start(self):
|
||||||
await self.websocket.accept()
|
await self.websocket.accept()
|
||||||
while True:
|
while True:
|
||||||
|
|
@ -177,14 +175,15 @@ class NostrClientConnection:
|
||||||
self.authenticated = True
|
self.authenticated = True
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
if not self.authenticated and self.client_config.event_requires_auth(e.kind):
|
if not self.authenticated and self.client_config.event_requires_auth(e.kind):
|
||||||
await self._send_msg(["AUTH", self._current_auth_challenge()])
|
await self._send_msg(["AUTH", self._current_auth_challenge()])
|
||||||
resp_nip20 += [False, f"restricted: Relay requires authentication for events of kind '{e.kind}'"]
|
resp_nip20 += [
|
||||||
|
False,
|
||||||
|
f"restricted: Relay requires authentication for events of kind '{e.kind}'",
|
||||||
|
]
|
||||||
await self._send_msg(resp_nip20)
|
await self._send_msg(resp_nip20)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
valid, message = await self._validate_write(e)
|
valid, message = await self._validate_write(e)
|
||||||
if not valid:
|
if not valid:
|
||||||
resp_nip20 += [valid, message]
|
resp_nip20 += [valid, message]
|
||||||
|
|
@ -259,7 +258,7 @@ class NostrClientConnection:
|
||||||
self._remove_filter(subscription_id)
|
self._remove_filter(subscription_id)
|
||||||
|
|
||||||
def _handle_auth(self):
|
def _handle_auth(self):
|
||||||
raise ValueError('Not supported')
|
raise ValueError("Not supported")
|
||||||
|
|
||||||
def _can_add_filter(self) -> bool:
|
def _can_add_filter(self) -> bool:
|
||||||
return (
|
return (
|
||||||
|
|
@ -276,7 +275,7 @@ class NostrClientConnection:
|
||||||
challenge_tag = e.tag_values("challenge")
|
challenge_tag = e.tag_values("challenge")
|
||||||
if len(relay_tag) == 0 or len(challenge_tag) == 0:
|
if len(relay_tag) == 0 or len(challenge_tag) == 0:
|
||||||
return False, "error: NIP42 tags are missing for auth event"
|
return False, "error: NIP42 tags are missing for auth event"
|
||||||
|
|
||||||
if self.client_config.domain != extract_domain(relay_tag[0]):
|
if self.client_config.domain != extract_domain(relay_tag[0]):
|
||||||
return False, "error: wrong relay domain for auth event"
|
return False, "error: wrong relay domain for auth event"
|
||||||
|
|
||||||
|
|
@ -317,10 +316,12 @@ class NostrClientConnection:
|
||||||
|
|
||||||
return True, ""
|
return True, ""
|
||||||
|
|
||||||
async def _validate_storage(self, pubkey: str, event_size_bytes: int) -> Tuple[bool, str]:
|
async def _validate_storage(
|
||||||
|
self, pubkey: str, event_size_bytes: int
|
||||||
|
) -> Tuple[bool, str]:
|
||||||
if self.client_config.is_read_only_relay:
|
if self.client_config.is_read_only_relay:
|
||||||
return False, "Cannot write event, relay is read-only"
|
return False, "Cannot write event, relay is read-only"
|
||||||
|
|
||||||
account = await get_account(self.relay_id, pubkey)
|
account = await get_account(self.relay_id, pubkey)
|
||||||
if not account:
|
if not account:
|
||||||
account = NostrAccount.null_account()
|
account = NostrAccount.null_account()
|
||||||
|
|
@ -329,7 +330,9 @@ class NostrClientConnection:
|
||||||
return False, f"This is a paid relay: '{self.relay_id}'"
|
return False, f"This is a paid relay: '{self.relay_id}'"
|
||||||
|
|
||||||
stored_bytes = await get_storage_for_public_key(self.relay_id, pubkey)
|
stored_bytes = await get_storage_for_public_key(self.relay_id, pubkey)
|
||||||
total_available_storage = account.storage + self.client_config.free_storage_bytes_value
|
total_available_storage = (
|
||||||
|
account.storage + self.client_config.free_storage_bytes_value
|
||||||
|
)
|
||||||
if (stored_bytes + event_size_bytes) <= total_available_storage:
|
if (stored_bytes + event_size_bytes) <= total_available_storage:
|
||||||
return True, ""
|
return True, ""
|
||||||
|
|
||||||
|
|
@ -375,11 +378,13 @@ class NostrClientConnection:
|
||||||
if self._auth_challenge_created_at == 0:
|
if self._auth_challenge_created_at == 0:
|
||||||
return True
|
return True
|
||||||
current_time_seconds = round(time.time())
|
current_time_seconds = round(time.time())
|
||||||
chanllenge_max_age_seconds = 300 # 5 min
|
chanllenge_max_age_seconds = 300 # 5 min
|
||||||
return (current_time_seconds - self._auth_challenge_created_at) >= chanllenge_max_age_seconds
|
return (
|
||||||
|
current_time_seconds - self._auth_challenge_created_at
|
||||||
|
) >= chanllenge_max_age_seconds
|
||||||
|
|
||||||
def _current_auth_challenge(self):
|
def _current_auth_challenge(self):
|
||||||
if self._auth_challenge_expired():
|
if self._auth_challenge_expired():
|
||||||
self._auth_challenge = self.relay_id + ":" + urlsafe_short_hash()
|
self._auth_challenge = self.relay_id + ":" + urlsafe_short_hash()
|
||||||
self._auth_challenge_created_at = round(time.time())
|
self._auth_challenge_created_at = round(time.time())
|
||||||
return self._auth_challenge
|
return self._auth_challenge
|
||||||
|
|
|
||||||
19
crud.py
19
crud.py
|
|
@ -13,6 +13,7 @@ from .models import (
|
||||||
|
|
||||||
########################## RELAYS ####################
|
########################## RELAYS ####################
|
||||||
|
|
||||||
|
|
||||||
async def create_relay(user_id: str, r: NostrRelay) -> NostrRelay:
|
async def create_relay(user_id: str, r: NostrRelay) -> NostrRelay:
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"""
|
"""
|
||||||
|
|
@ -326,9 +327,9 @@ def build_select_events_query(relay_id: str, filter: NostrFilter):
|
||||||
return query, values
|
return query, values
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
########################## ACCOUNTS ####################
|
########################## ACCOUNTS ####################
|
||||||
|
|
||||||
|
|
||||||
async def create_account(relay_id: str, a: NostrAccount) -> NostrAccount:
|
async def create_account(relay_id: str, a: NostrAccount) -> NostrAccount:
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"""
|
"""
|
||||||
|
|
@ -357,25 +358,19 @@ async def update_account(relay_id: str, a: NostrAccount) -> NostrAccount:
|
||||||
SET (sats, storage, paid_to_join, allowed, blocked) = (?, ?, ?, ?, ?)
|
SET (sats, storage, paid_to_join, allowed, blocked) = (?, ?, ?, ?, ?)
|
||||||
WHERE relay_id = ? AND pubkey = ?
|
WHERE relay_id = ? AND pubkey = ?
|
||||||
""",
|
""",
|
||||||
(
|
(a.sats, a.storage, a.paid_to_join, a.allowed, a.blocked, relay_id, a.pubkey),
|
||||||
a.sats,
|
|
||||||
a.storage,
|
|
||||||
a.paid_to_join,
|
|
||||||
a.allowed,
|
|
||||||
a.blocked,
|
|
||||||
relay_id,
|
|
||||||
a.pubkey
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return a
|
return a
|
||||||
|
|
||||||
|
|
||||||
async def get_account(relay_id: str, pubkey: str,) -> Optional[NostrAccount]:
|
async def get_account(
|
||||||
|
relay_id: str,
|
||||||
|
pubkey: str,
|
||||||
|
) -> Optional[NostrAccount]:
|
||||||
row = await db.fetchone(
|
row = await db.fetchone(
|
||||||
"SELECT * FROM nostrrelay.accounts WHERE relay_id = ? AND pubkey = ?",
|
"SELECT * FROM nostrrelay.accounts WHERE relay_id = ? AND pubkey = ?",
|
||||||
(relay_id, pubkey),
|
(relay_id, pubkey),
|
||||||
)
|
)
|
||||||
|
|
||||||
return NostrAccount.from_row(row) if row else None
|
return NostrAccount.from_row(row) if row else None
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,5 +20,6 @@ def normalize_public_key(pubkey: str) -> str:
|
||||||
int(pubkey, 16)
|
int(pubkey, 16)
|
||||||
return pubkey
|
return pubkey
|
||||||
|
|
||||||
|
|
||||||
def extract_domain(url: str) -> str:
|
def extract_domain(url: str) -> str:
|
||||||
return urlparse(url).netloc
|
return urlparse(url).netloc
|
||||||
|
|
|
||||||
14
models.py
14
models.py
|
|
@ -73,6 +73,7 @@ class AuthSpec(BaseModel):
|
||||||
return False
|
return False
|
||||||
return kind not in self.skiped_auth_events
|
return kind not in self.skiped_auth_events
|
||||||
|
|
||||||
|
|
||||||
class PaymentSpec(BaseModel):
|
class PaymentSpec(BaseModel):
|
||||||
is_paid_relay = Field(False, alias="isPaidRelay")
|
is_paid_relay = Field(False, alias="isPaidRelay")
|
||||||
cost_to_join = Field(0, alias="costToJoin")
|
cost_to_join = Field(0, alias="costToJoin")
|
||||||
|
|
@ -93,23 +94,23 @@ class AuthorSpec(Spec):
|
||||||
# todo: check payment
|
# todo: check payment
|
||||||
return p in self.allowed_public_keys
|
return p in self.allowed_public_keys
|
||||||
|
|
||||||
|
|
||||||
class WalletSpec(Spec):
|
class WalletSpec(Spec):
|
||||||
wallet = Field("")
|
wallet = Field("")
|
||||||
|
|
||||||
|
|
||||||
class RelayPublicSpec(FilterSpec, EventSpec, StorageSpec, PaymentSpec):
|
class RelayPublicSpec(FilterSpec, EventSpec, StorageSpec, PaymentSpec):
|
||||||
domain: str = ''
|
domain: str = ""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_read_only_relay(self):
|
def is_read_only_relay(self):
|
||||||
self.free_storage_value == 0 and not self.is_paid_relay
|
self.free_storage_value == 0 and not self.is_paid_relay
|
||||||
|
|
||||||
|
|
||||||
class RelaySpec(RelayPublicSpec, AuthorSpec, WalletSpec, AuthSpec):
|
class RelaySpec(RelayPublicSpec, AuthorSpec, WalletSpec, AuthSpec):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class NostrRelay(BaseModel):
|
class NostrRelay(BaseModel):
|
||||||
id: str
|
id: str
|
||||||
name: str
|
name: str
|
||||||
|
|
@ -183,7 +184,7 @@ class NostrEvent(BaseModel):
|
||||||
@property
|
@property
|
||||||
def is_auth_response_event(self) -> bool:
|
def is_auth_response_event(self) -> bool:
|
||||||
return self.kind == 22242
|
return self.kind == 22242
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_delete_event(self) -> bool:
|
def is_delete_event(self) -> bool:
|
||||||
return self.kind == 5
|
return self.kind == 5
|
||||||
|
|
@ -340,7 +341,8 @@ class BuyOrder(BaseModel):
|
||||||
units_to_buy = 0
|
units_to_buy = 0
|
||||||
|
|
||||||
def is_valid_action(self):
|
def is_valid_action(self):
|
||||||
return self.action in ['join', 'storage']
|
return self.action in ["join", "storage"]
|
||||||
|
|
||||||
|
|
||||||
class NostrAccount(BaseModel):
|
class NostrAccount(BaseModel):
|
||||||
pubkey: str
|
pubkey: str
|
||||||
|
|
@ -356,4 +358,4 @@ class NostrAccount(BaseModel):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_row(cls, row: Row) -> "NostrAccount":
|
def from_row(cls, row: Row) -> "NostrAccount":
|
||||||
return cls(**dict(row))
|
return cls(**dict(row))
|
||||||
|
|
|
||||||
15
tasks.py
15
tasks.py
|
|
@ -35,13 +35,16 @@ async def on_invoice_paid(payment: Payment):
|
||||||
await invoice_paid_for_storage(relay_id, pubkey, storage_to_buy)
|
await invoice_paid_for_storage(relay_id, pubkey, storage_to_buy)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
async def invoice_paid_to_join(relay_id: str, pubkey: str):
|
async def invoice_paid_to_join(relay_id: str, pubkey: str):
|
||||||
try:
|
try:
|
||||||
account = await get_account(relay_id, pubkey)
|
account = await get_account(relay_id, pubkey)
|
||||||
if not account:
|
if not account:
|
||||||
await create_account(relay_id, NostrAccount(pubkey=pubkey, paid_to_join=True))
|
await create_account(
|
||||||
|
relay_id, NostrAccount(pubkey=pubkey, paid_to_join=True)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
if account.blocked or account.paid_to_join:
|
if account.blocked or account.paid_to_join:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -56,9 +59,11 @@ async def invoice_paid_for_storage(relay_id: str, pubkey: str, storage_to_buy: i
|
||||||
try:
|
try:
|
||||||
account = await get_account(relay_id, pubkey)
|
account = await get_account(relay_id, pubkey)
|
||||||
if not account:
|
if not account:
|
||||||
await create_account(relay_id, NostrAccount(pubkey=pubkey, storage=storage_to_buy))
|
await create_account(
|
||||||
|
relay_id, NostrAccount(pubkey=pubkey, storage=storage_to_buy)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
if account.blocked:
|
if account.blocked:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -66,4 +71,4 @@ async def invoice_paid_for_storage(relay_id: str, pubkey: str, storage_to_buy: i
|
||||||
await update_account(relay_id, account)
|
await update_account(relay_id, account)
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logger.warning(ex)
|
logger.warning(ex)
|
||||||
|
|
|
||||||
10
views_api.py
10
views_api.py
|
|
@ -48,7 +48,9 @@ async def websocket_endpoint(relay_id: str, websocket: WebSocket):
|
||||||
|
|
||||||
@nostrrelay_ext.post("/api/v1/relay")
|
@nostrrelay_ext.post("/api/v1/relay")
|
||||||
async def api_create_relay(
|
async def api_create_relay(
|
||||||
data: NostrRelay, request: Request, wallet: WalletTypeInfo = Depends(require_admin_key)
|
data: NostrRelay,
|
||||||
|
request: Request,
|
||||||
|
wallet: WalletTypeInfo = Depends(require_admin_key),
|
||||||
) -> NostrRelay:
|
) -> NostrRelay:
|
||||||
if len(data.id):
|
if len(data.id):
|
||||||
await check_admin(UUID4(wallet.wallet.user))
|
await check_admin(UUID4(wallet.wallet.user))
|
||||||
|
|
@ -166,11 +168,11 @@ async def api_pay_to_join(data: BuyOrder):
|
||||||
detail="Relay not found",
|
detail="Relay not found",
|
||||||
)
|
)
|
||||||
|
|
||||||
if data.action == 'join' and relay.is_free_to_join:
|
if data.action == "join" and relay.is_free_to_join:
|
||||||
raise ValueError("Relay is free to join")
|
raise ValueError("Relay is free to join")
|
||||||
|
|
||||||
storage_to_buy = 0
|
storage_to_buy = 0
|
||||||
if data.action == 'storage':
|
if data.action == "storage":
|
||||||
if relay.config.storage_cost_value == 0:
|
if relay.config.storage_cost_value == 0:
|
||||||
raise ValueError("Relay storage cost is zero. Cannot buy!")
|
raise ValueError("Relay storage cost is zero. Cannot buy!")
|
||||||
if data.units_to_buy == 0:
|
if data.units_to_buy == 0:
|
||||||
|
|
@ -188,7 +190,7 @@ async def api_pay_to_join(data: BuyOrder):
|
||||||
"action": data.action,
|
"action": data.action,
|
||||||
"relay_id": relay.id,
|
"relay_id": relay.id,
|
||||||
"pubkey": pubkey,
|
"pubkey": pubkey,
|
||||||
"storage_to_buy": storage_to_buy
|
"storage_to_buy": storage_to_buy,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
print("### payment_request", payment_request)
|
print("### payment_request", payment_request)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue