672 lines
22 KiB
HTML
672 lines
22 KiB
HTML
<div>
|
|
<q-tabs v-model="tab" no-caps class="bg-dark text-white shadow-2">
|
|
<q-tab name="info" label="Relay Info"></q-tab>
|
|
<q-tab name="payment" label="Payment"></q-tab>
|
|
<q-tab name="config" label="Config"></q-tab>
|
|
<q-tab name="accounts" label="Accounts"></q-tab>
|
|
</q-tabs>
|
|
<q-tab-panels v-model="tab">
|
|
<q-tab-panel name="info">
|
|
<div v-if="relay">
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-3 q-pr-lg">Name:</div>
|
|
<div class="col-6 col-sm-8 q-pr-lg">
|
|
<q-input
|
|
filled
|
|
dense
|
|
v-model.trim="relay.name"
|
|
type="text"
|
|
></q-input>
|
|
</div>
|
|
<div class="col-3 col-sm-1"></div>
|
|
</div>
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-3 q-pr-lg">Description:</div>
|
|
<div class="col-6 col-sm-8 q-pr-lg">
|
|
<q-input
|
|
filled
|
|
dense
|
|
v-model.trim="relay.description"
|
|
type="text"
|
|
></q-input>
|
|
</div>
|
|
<div class="col-3 col-sm-1"></div>
|
|
</div>
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-3 q-pr-lg">Relay Public Key:</div>
|
|
<div class="col-6 col-sm-8 q-pr-lg">
|
|
<q-input
|
|
filled
|
|
dense
|
|
v-model.trim="relay.pubkey"
|
|
type="text"
|
|
></q-input>
|
|
</div>
|
|
<div class="col-3 col-sm-1"></div>
|
|
</div>
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-3 q-pr-lg">Contact:</div>
|
|
<div class="col-6 col-sm-8 q-pr-lg">
|
|
<q-input
|
|
filled
|
|
dense
|
|
v-model.trim="relay.contact"
|
|
type="text"
|
|
></q-input>
|
|
</div>
|
|
<div class="col-3 col-sm-1"></div>
|
|
</div>
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-3 q-pr-lg">Domain:</div>
|
|
<div class="col-6 col-sm-8 q-pr-lg">
|
|
<q-input
|
|
filled
|
|
dense
|
|
v-model.trim="relay.config.domain"
|
|
type="text"
|
|
></q-input>
|
|
</div>
|
|
<div class="col-3 col-sm-1"></div>
|
|
</div>
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-3 q-pr-lg">Web Socket Link:</div>
|
|
<div class="col-6 col-sm-8 q-pr-lg">
|
|
<q-input
|
|
filled
|
|
dense
|
|
v-model.trim="wssLink"
|
|
type="text"
|
|
readonly
|
|
></q-input>
|
|
</div>
|
|
<div class="col-3 col-sm-1">
|
|
<q-btn
|
|
outline
|
|
color="grey"
|
|
@click="copyText(disclaimerDialog.location.href)"
|
|
>Copy</q-btn
|
|
>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</q-tab-panel>
|
|
<q-tab-panel name="payment">
|
|
<div v-if="relay">
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-3 q-pr-lg q-pb-md">Free Storage:</div>
|
|
<div class="col-md-2 col-sm-4 q-pr-lg">
|
|
<q-input
|
|
filled
|
|
dense
|
|
v-model.trim="relay.config.freeStorageValue"
|
|
type="number"
|
|
hint="Value"
|
|
min="0"
|
|
></q-input>
|
|
</div>
|
|
<div class="col-md-2 col-sm-4 q-pr-lg">
|
|
<q-select
|
|
filled
|
|
dense
|
|
v-model="relay.config.freeStorageUnit"
|
|
type="text"
|
|
hint="Unit"
|
|
:options="storageUnits"
|
|
></q-select>
|
|
</div>
|
|
<div class="col-1 q-pr-lg">
|
|
<q-icon name="info" class="cursor-pointer q-pb-md">
|
|
<q-tooltip>
|
|
How much data a client can store. This can be extended with the
|
|
Paid Plan.
|
|
</q-tooltip></q-icon
|
|
>
|
|
</div>
|
|
<div class="col-md-4 col-sm-2">
|
|
<q-badge
|
|
v-if="relay.config.freeStorageValue == 0"
|
|
color="orange"
|
|
class="float-right q-mb-md"
|
|
><span>No free storage</span>
|
|
</q-badge>
|
|
</div>
|
|
</div>
|
|
<q-separator></q-separator>
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-3 q-pr-lg">Paid Plan:</div>
|
|
<div class="col-md-3 q-pr-lg">
|
|
<q-toggle
|
|
color="secodary"
|
|
v-model="relay.config.isPaidRelay"
|
|
@input="togglePaidRelay"
|
|
></q-toggle>
|
|
</div>
|
|
<div class="col-6">
|
|
<q-badge
|
|
v-if="!relay.config.isPaidRelay && relay.config.freeStorageValue == 0"
|
|
color="orange"
|
|
class="float-right q-mb-md"
|
|
><span>No data will be stored. Read-only relay.</span>
|
|
</q-badge>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="relay.config.isPaidRelay && relay.config.wallet">
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-3 q-pr-lg">Wallet:</div>
|
|
<div class="col-md-6 col-sm-8 q-pr-lg">
|
|
<q-select
|
|
filled
|
|
dense
|
|
emit-value
|
|
v-model="relay.config.wallet"
|
|
:options="walletOptions"
|
|
label="Wallet *"
|
|
>
|
|
</q-select>
|
|
</div>
|
|
<div class="col-md-3 col-sm-1">
|
|
<q-icon name="info" class="cursor-pointer">
|
|
<q-tooltip>
|
|
Wallet where the paiments will be sent to.
|
|
</q-tooltip></q-icon
|
|
>
|
|
</div>
|
|
</div>
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-3 q-pr-lg">Cost to join (sats):</div>
|
|
<div class="col-md-2 col-sm-4 q-pr-lg">
|
|
<q-input
|
|
filled
|
|
dense
|
|
v-model.trim="relay.config.costToJoin"
|
|
type="number"
|
|
hint="sats"
|
|
min="0"
|
|
></q-input>
|
|
</div>
|
|
<div class="col-1 q-pr-lg">
|
|
<q-icon name="info" class="cursor-pointer q-pb-md">
|
|
<q-tooltip>
|
|
Ask a fee for clients to join. Expected to be paid only once.
|
|
</q-tooltip></q-icon
|
|
>
|
|
</div>
|
|
<div class="col-md-6 col-sm-4">
|
|
<q-badge
|
|
v-if="relay.config.costToJoin == 0"
|
|
color="green"
|
|
class="float-right"
|
|
><span>Free to join</span>
|
|
</q-badge>
|
|
</div>
|
|
</div>
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-3 q-pr-lg">Storage Cost (sats):</div>
|
|
<div class="col-md-2 col-sm-4 q-pr-lg">
|
|
<q-input
|
|
filled
|
|
dense
|
|
v-model.trim="relay.config.storageCostValue"
|
|
type="number"
|
|
hint="sats"
|
|
min="0"
|
|
></q-input>
|
|
</div>
|
|
<div class="col-md-2 col-sm-4 q-pr-lg">
|
|
<q-select
|
|
filled
|
|
dense
|
|
v-model="relay.config.storageCostUnit"
|
|
type="text"
|
|
hint="Unit"
|
|
:options="storageUnits"
|
|
></q-select>
|
|
</div>
|
|
<div class="col-1 q-pr-lg">
|
|
<q-icon name="info" class="cursor-pointer q-pb-md">
|
|
<q-tooltip>
|
|
Cost for clients to buy additional storage.
|
|
</q-tooltip></q-icon
|
|
>
|
|
</div>
|
|
<div class="col-md-4 col-sm-0">
|
|
<q-badge
|
|
v-if="relay.config.storageCostValue == 0"
|
|
color="green"
|
|
class="float-right"
|
|
><span>Unlimited storage</span>
|
|
</q-badge>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</q-tab-panel>
|
|
<q-tab-panel name="config">
|
|
<div v-if="relay">
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-3 q-pr-lg">Created At in Past:</div>
|
|
<div class="col-2 q-pr-lg">
|
|
<q-input
|
|
filled
|
|
dense
|
|
v-model.trim="relay.config.createdAtDaysPast"
|
|
type="number"
|
|
min="0"
|
|
hint="Days"
|
|
></q-input>
|
|
</div>
|
|
<div class="col-2 q-pr-lg">
|
|
<q-select
|
|
filled
|
|
dense
|
|
v-model="relay.config.createdAtHoursPast"
|
|
type="number"
|
|
hint="Hours"
|
|
:options="hours"
|
|
></q-select>
|
|
</div>
|
|
<div class="col-2 q-pr-lg">
|
|
<q-select
|
|
filled
|
|
dense
|
|
v-model="relay.config.createdAtMinutesPast"
|
|
type="number"
|
|
hint="Minutes"
|
|
:options="range60"
|
|
></q-select>
|
|
</div>
|
|
<div class="col-2 q-pr-lg">
|
|
<q-select
|
|
filled
|
|
dense
|
|
v-model="relay.config.createdAtSecondsPast"
|
|
type="number"
|
|
hint="Seconds"
|
|
:options="range60"
|
|
></q-select>
|
|
</div>
|
|
<div class="col-1 q-pb-md">
|
|
<q-icon name="info" class="cursor-pointer">
|
|
<q-tooltip>
|
|
NIP 22: Lower limit within which a relay will consider an
|
|
event's created_at to be acceptable.
|
|
</q-tooltip></q-icon
|
|
>
|
|
</div>
|
|
</div>
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-3 q-pr-lg">Created At in Future:</div>
|
|
<div class="col-2 q-pr-lg">
|
|
<q-input
|
|
filled
|
|
dense
|
|
v-model.trim="relay.config.createdAtDaysFuture"
|
|
type="number"
|
|
min="0"
|
|
hint="Days"
|
|
></q-input>
|
|
</div>
|
|
<div class="col-2 q-pr-lg">
|
|
<q-select
|
|
filled
|
|
dense
|
|
v-model="relay.config.createdAtHoursFuture"
|
|
type="number"
|
|
hint="Hours"
|
|
:options="hours"
|
|
></q-select>
|
|
</div>
|
|
<div class="col-2 q-pr-lg">
|
|
<q-select
|
|
filled
|
|
dense
|
|
v-model="relay.config.createdAtMinutesFuture"
|
|
type="number"
|
|
hint="Minutes"
|
|
:options="range60"
|
|
></q-select>
|
|
</div>
|
|
<div class="col-2 q-pr-lg">
|
|
<q-select
|
|
filled
|
|
dense
|
|
v-model="relay.config.createdAtSecondsFuture"
|
|
type="number"
|
|
hint="Seconds"
|
|
:options="range60"
|
|
></q-select>
|
|
</div>
|
|
<div class="col-1 q-pb-md">
|
|
<q-icon name="info" class="cursor-pointer">
|
|
<q-tooltip>
|
|
NIP 22: Upper limit within which a relay will consider an
|
|
event's created_at to be acceptable.
|
|
</q-tooltip></q-icon
|
|
>
|
|
</div>
|
|
</div>
|
|
<q-separator></q-separator>
|
|
<div class="row items-center no-wrap q-mb-md q-mt-md">
|
|
<div class="col-3 q-pr-lg">Require Auth :</div>
|
|
<div class="col-2 col-sm-4 q-pr-lg">
|
|
<q-toggle
|
|
color="secodary"
|
|
class="q-ml-md q-mr-md"
|
|
v-model="relay.config.requireAuthFilter"
|
|
>For Filters</q-toggle
|
|
>
|
|
</div>
|
|
<div class="col-2 col-sm-4 q-pr-lg">
|
|
<q-toggle
|
|
color="secodary"
|
|
class="q-ml-md q-mr-md"
|
|
v-model="relay.config.requireAuthEvents"
|
|
>For All Events</q-toggle
|
|
>
|
|
</div>
|
|
<div class="col-5 col-sm-5">
|
|
<q-icon name="info" class="cursor-pointer">
|
|
<q-tooltip>
|
|
Require client authentication for accessing different types of
|
|
resources.
|
|
</q-tooltip></q-icon
|
|
>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-if="relay.config.requireAuthEvents"
|
|
class="row items-center no-wrap q-mb-md q-mt-md"
|
|
>
|
|
<div class="col-3 q-pr-lg">Skip Auth For Events:</div>
|
|
<div class="col-1">
|
|
<q-input
|
|
filled
|
|
dense
|
|
v-model.trim="skipEventKind"
|
|
type="number"
|
|
min="0"
|
|
></q-input>
|
|
</div>
|
|
<div class="col-1">
|
|
<q-btn
|
|
unelevated
|
|
color="secondary"
|
|
icon="add"
|
|
@click="addSkipAuthForEvent()"
|
|
></q-btn>
|
|
</div>
|
|
<div class="col-7">
|
|
<q-chip
|
|
v-for="e in relay.config.skipedAuthEvents"
|
|
:key="e"
|
|
removable
|
|
@remove="removeSkipAuthForEvent(e)"
|
|
color="primary"
|
|
text-color="white"
|
|
>
|
|
{{ e }}
|
|
</q-chip>
|
|
</div>
|
|
</div>
|
|
<div v-else class="row items-center no-wrap q-mb-md q-mt-md">
|
|
<div class="col-3 q-pr-lg">Force Auth For Events:</div>
|
|
<div class="col-1">
|
|
<q-input
|
|
filled
|
|
dense
|
|
v-model.trim="forceEventKind"
|
|
type="number"
|
|
min="0"
|
|
></q-input>
|
|
</div>
|
|
<div class="col-1">
|
|
<q-btn
|
|
unelevated
|
|
color="secondary"
|
|
icon="add"
|
|
@click="addForceAuthForEvent()"
|
|
></q-btn>
|
|
</div>
|
|
<div class="col-7">
|
|
<q-chip
|
|
v-for="e in relay.config.forcedAuthEvents"
|
|
:key="e"
|
|
removable
|
|
@remove="removeForceAuthForEvent(e)"
|
|
color="primary"
|
|
text-color="white"
|
|
>
|
|
{{ e }}
|
|
</q-chip>
|
|
</div>
|
|
</div>
|
|
<q-separator></q-separator>
|
|
<div class="row items-center no-wrap q-mb-md q-mt-md">
|
|
<div class="col-3 q-pr-lg">Full Storage Action:</div>
|
|
<div class="col-3 col-sm-4 q-pr-lg">
|
|
<q-select
|
|
filled
|
|
dense
|
|
emit-value
|
|
v-model="relay.config.fullStorageAction"
|
|
type="text"
|
|
:options="fullStorageActions"
|
|
></q-select>
|
|
</div>
|
|
<div class="col-6 col-sm-5">
|
|
<q-icon name="info" class="cursor-pointer">
|
|
<q-tooltip>
|
|
Action to be taken when the storage limit (if any) has been
|
|
reached.
|
|
</q-tooltip></q-icon
|
|
>
|
|
</div>
|
|
</div>
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-3 q-pr-lg">Limit per filter:</div>
|
|
<div class="col-3 col-sm-4 q-pr-lg">
|
|
<q-input
|
|
filled
|
|
dense
|
|
v-model.trim="relay.config.limitPerFilter"
|
|
type="number"
|
|
min="0"
|
|
></q-input>
|
|
</div>
|
|
<div class="col-6 col-sm-5">
|
|
<q-icon name="info" class="cursor-pointer">
|
|
<q-tooltip>
|
|
Maximum number of events to be returned in the initial query
|
|
(default 1000)
|
|
</q-tooltip></q-icon
|
|
>
|
|
<q-badge
|
|
v-if="relay.config.limitPerFilter == 0"
|
|
color="green"
|
|
class="float-right"
|
|
><span>No Limit</span>
|
|
</q-badge>
|
|
</div>
|
|
</div>
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-3 q-pr-lg">Max Filters (per client):</div>
|
|
<div class="col-3 col-sm-4 q-pr-lg">
|
|
<q-input
|
|
filled
|
|
dense
|
|
v-model.trim="relay.config.maxClientFilters"
|
|
type="number"
|
|
min="0"
|
|
></q-input>
|
|
</div>
|
|
<div class="col-6 col-sm-5">
|
|
<q-icon name="info" class="cursor-pointer">
|
|
<q-tooltip>
|
|
Limit the number of filters that a client can have. Prevents
|
|
relay from being abused by clients with extremly high number of
|
|
fiters.
|
|
</q-tooltip></q-icon
|
|
>
|
|
<q-badge
|
|
v-if="relay.config.maxClientFilters == 0"
|
|
color="green"
|
|
class="float-right"
|
|
><span>Unlimited Filters</span>
|
|
</q-badge>
|
|
</div>
|
|
</div>
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-3 q-pr-lg">Max events per hour:</div>
|
|
<div class="col-3 col-sm-4 q-pr-lg">
|
|
<q-input
|
|
filled
|
|
dense
|
|
v-model.trim="relay.config.maxEventsPerHour"
|
|
type="number"
|
|
min="0"
|
|
></q-input>
|
|
</div>
|
|
<div class="col-6 col-sm-5">
|
|
<q-icon name="info" class="cursor-pointer">
|
|
<q-tooltip>
|
|
Limits the rate at which events are accepted by the relay.
|
|
Prevent clients from clogging the relay.
|
|
</q-tooltip></q-icon
|
|
>
|
|
<q-badge
|
|
v-if="relay.config.maxEventsPerHour == 0"
|
|
color="green"
|
|
class="float-right"
|
|
><span>No Limit</span>
|
|
</q-badge>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</q-tab-panel>
|
|
<q-tab-panel name="accounts">
|
|
<div v-if="relay">
|
|
<q-card class="q-mr-lg q-mb-md"
|
|
><q-card-section>
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-2 q-pr-lg">Public Key:</div>
|
|
<div class="col-6 q-pr-lg">
|
|
<q-input
|
|
filled
|
|
dense
|
|
v-model.trim="accountPubkey"
|
|
type="text"
|
|
></q-input>
|
|
</div>
|
|
<div class="col-2 q-pr-md">
|
|
<q-btn
|
|
unelevated
|
|
color="green"
|
|
class="float-right"
|
|
@click="allowPublicKey(accountPubkey, true)"
|
|
>Allow</q-btn
|
|
>
|
|
</div>
|
|
<div class="col-2">
|
|
<q-btn
|
|
unelevated
|
|
color="pink"
|
|
class="float-right"
|
|
@click="blockPublicKey(accountPubkey, true)"
|
|
>Block</q-btn
|
|
>
|
|
</div>
|
|
</div>
|
|
</q-card-section>
|
|
</q-card>
|
|
<q-card class="q-mr-lg q-mb-dm"
|
|
><q-card-section>
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-3 q-pr-lg">Filter:</div>
|
|
<div class="col-9 q-pr-lg">
|
|
<q-toggle
|
|
size="sm"
|
|
color="secodary"
|
|
class="q-mr-lg"
|
|
v-model="showAllowedAccounts"
|
|
@input="getAccounts()"
|
|
>Show Allowed Account</q-toggle
|
|
>
|
|
<q-toggle
|
|
size="sm"
|
|
color="secodary"
|
|
class="q-mr-lg"
|
|
v-model="showBlockedAccounts"
|
|
@input="getAccounts()"
|
|
>
|
|
Show Blocked Accounts</q-toggle
|
|
>
|
|
</div>
|
|
</div>
|
|
</q-card-section></q-card
|
|
>
|
|
<div class="row items-center no-wrap q-mb-md">
|
|
<div class="col-12 q-pr-lg">
|
|
<q-table
|
|
flat
|
|
dense
|
|
:data="accounts"
|
|
row-key="pubkey"
|
|
:columns="accountsTable.columns"
|
|
:pagination.sync="accountsTable.pagination"
|
|
:filter="accountsFilter"
|
|
>
|
|
<template v-slot:body="props">
|
|
<q-tr :props="props">
|
|
<q-td key="pubkey" :props="props">
|
|
{{props.row.pubkey}}
|
|
</q-td>
|
|
<q-td key="allowed" :props="props">
|
|
<q-toggle
|
|
size="sm"
|
|
color="secodary"
|
|
v-model="props.row.allowed"
|
|
@input="togglePublicKey(props.row, 'allow')"
|
|
></q-toggle>
|
|
</q-td>
|
|
<q-td key="blocked" :props="props">
|
|
<q-toggle
|
|
size="sm"
|
|
color="secodary"
|
|
v-model="props.row.blocked"
|
|
@input="togglePublicKey(props.row, 'block')"
|
|
></q-toggle>
|
|
</q-td>
|
|
<q-td auto-width> {{props.row.paid_to_join}} </q-td>
|
|
<q-td auto-width> {{props.row.sats}} </q-td>
|
|
<q-td auto-width> {{props.row.storage}} </q-td>
|
|
</q-tr>
|
|
</template>
|
|
</q-table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</q-tab-panel>
|
|
</q-tab-panels>
|
|
<div class="row items-center q-mt-md q-mb-lg">
|
|
<div class="col-6 q-pr-lg">
|
|
<q-btn
|
|
unelevated
|
|
color="secondary"
|
|
class="float-left"
|
|
@click="updateRelay()"
|
|
>Update Relay</q-btn
|
|
>
|
|
</div>
|
|
<div class="col-6">
|
|
<q-btn
|
|
unelevated
|
|
color="pink"
|
|
icon="cancel"
|
|
class="float-right"
|
|
@click="deleteRelay()"
|
|
>Delete Relay</q-btn
|
|
>
|
|
</div>
|
|
</div>
|
|
</div>
|