mirror of
https://github.com/Cameri/nostream.git
synced 2025-06-14 10:40:50 +02:00
feat: allow lightning zap receipts on paid relays (#303)
* chore: add event_kinds whitelist for fee schedules * chore: fix identation in default-settings.yml * chore: waive admission fee for specific event kinds * docs: add payment settings to CONFIGURATION.md * docs: improve read replica docs
This commit is contained in:
parent
565f67c5f6
commit
14bc96f516
@ -20,14 +20,31 @@ The following environment variables can be set:
|
|||||||
| DB_MAX_POOL_SIZE | Max. connections per worker | 32 |
|
| DB_MAX_POOL_SIZE | Max. connections per worker | 32 |
|
||||||
| DB_ACQUIRE_CONNECTION_TIMEOUT | New connection timeout (ms) | 60000 |
|
| DB_ACQUIRE_CONNECTION_TIMEOUT | New connection timeout (ms) | 60000 |
|
||||||
| READ_REPLICA_ENABLED | Read Replica (RR) Toggle | 'false' |
|
| READ_REPLICA_ENABLED | Read Replica (RR) Toggle | 'false' |
|
||||||
| RR_DB_HOST | PostgresSQL Hostname (RR) | |
|
| READ_REPLICAS | Number of read replicas (RR0, RR1, ..., RRn) | 2 |
|
||||||
| RR_DB_PORT | PostgreSQL Port (RR) | 5432 |
|
| RR0_DB_HOST | PostgresSQL Hostname (RR) | |
|
||||||
| RR_DB_USER | PostgreSQL Username (RR) | nostr_ts_relay |
|
| RR0_DB_PORT | PostgreSQL Port (RR) | 5432 |
|
||||||
| RR_DB_PASSWORD | PostgreSQL Password (RR) | nostr_ts_relay |
|
| RR0_DB_USER | PostgreSQL Username (RR) | nostr_ts_relay |
|
||||||
| RR_DB_NAME | PostgreSQL Database name (RR) | nostr_ts_relay |
|
| RR0_DB_PASSWORD | PostgreSQL Password (RR) | nostr_ts_relay |
|
||||||
| RR_DB_MIN_POOL_SIZE | Min. connections per worker (RR) | 16 |
|
| RR0_DB_NAME | PostgreSQL Database name (RR) | nostr_ts_relay |
|
||||||
| RR_DB_MAX_POOL_SIZE | Max. connections per worker (RR) | 32 |
|
| RR0_DB_MIN_POOL_SIZE | Min. connections per worker (RR) | 16 |
|
||||||
| RR_DB_ACQUIRE_CONNECTION_TIMEOUT | New connection timeout (ms) (RR) | 60000 |
|
| RR0_DB_MAX_POOL_SIZE | Max. connections per worker (RR) | 32 |
|
||||||
|
| RR0_DB_ACQUIRE_CONNECTION_TIMEOUT| New connection timeout (ms) (RR) | 60000 |
|
||||||
|
| RR1_DB_HOST | PostgresSQL Hostname (RR) | |
|
||||||
|
| RR1_DB_PORT | PostgreSQL Port (RR) | 5432 |
|
||||||
|
| RR1_DB_USER | PostgreSQL Username (RR) | nostr_ts_relay |
|
||||||
|
| RR1_DB_PASSWORD | PostgreSQL Password (RR) | nostr_ts_relay |
|
||||||
|
| RR1_DB_NAME | PostgreSQL Database name (RR) | nostr_ts_relay |
|
||||||
|
| RR1_DB_MIN_POOL_SIZE | Min. connections per worker (RR) | 16 |
|
||||||
|
| RR1_DB_MAX_POOL_SIZE | Max. connections per worker (RR) | 32 |
|
||||||
|
| RR1_DB_ACQUIRE_CONNECTION_TIMEOUT| New connection timeout (ms) (RR) | 60000 |
|
||||||
|
| RRn_DB_HOST | PostgresSQL Hostname (RR) | |
|
||||||
|
| RRn_DB_PORT | PostgreSQL Port (RR) | 5432 |
|
||||||
|
| RRn_DB_USER | PostgreSQL Username (RR) | nostr_ts_relay |
|
||||||
|
| RRn_DB_PASSWORD | PostgreSQL Password (RR) | nostr_ts_relay |
|
||||||
|
| RRn_DB_NAME | PostgreSQL Database name (RR) | nostr_ts_relay |
|
||||||
|
| RRn_DB_MIN_POOL_SIZE | Min. connections per worker (RR) | 16 |
|
||||||
|
| RRn_DB_MAX_POOL_SIZE | Max. connections per worker (RR) | 32 |
|
||||||
|
| RRn_DB_ACQUIRE_CONNECTION_TIMEOUT| New connection timeout (ms) (RR) | 60000 |
|
||||||
| TOR_HOST | Tor Hostname | |
|
| TOR_HOST | Tor Hostname | |
|
||||||
| TOR_CONTROL_PORT | Tor control Port | 9051 |
|
| TOR_CONTROL_PORT | Tor control Port | 9051 |
|
||||||
| TOR_PASSWORD | Tor control password | nostr_ts_relay |
|
| TOR_PASSWORD | Tor control password | nostr_ts_relay |
|
||||||
@ -41,6 +58,8 @@ The following environment variables can be set:
|
|||||||
| DEBUG | Debugging filter | |
|
| DEBUG | Debugging filter | |
|
||||||
| ZEBEDEE_API_KEY | Zebedee Project API Key | |
|
| ZEBEDEE_API_KEY | Zebedee Project API Key | |
|
||||||
|
|
||||||
|
If you've set READ_REPLICAS to 4, you should configure RR0_ through RR3_.
|
||||||
|
|
||||||
# Settings
|
# Settings
|
||||||
|
|
||||||
Running `nostream` for the first time creates the settings file in `<project_root>/.nostr/settings.yaml`. If the file is not created and an error is thrown ensure that the `<project_root>/.nostr` folder exists. The configuration directory can be changed by setting the `NOSTR_CONFIG_DIR` environment variable.
|
Running `nostream` for the first time creates the settings file in `<project_root>/.nostr/settings.yaml`. If the file is not created and an error is thrown ensure that the `<project_root>/.nostr` folder exists. The configuration directory can be changed by setting the `NOSTR_CONFIG_DIR` environment variable.
|
||||||
@ -54,6 +73,18 @@ Running `nostream` for the first time creates the settings file in `<project_roo
|
|||||||
| info.contact | Relay operator's contact. (e.g. mailto:operator@relay-your-domain.com) |
|
| info.contact | Relay operator's contact. (e.g. mailto:operator@relay-your-domain.com) |
|
||||||
| network.maxPayloadSize | Maximum number of bytes accepted per WebSocket frame |
|
| network.maxPayloadSize | Maximum number of bytes accepted per WebSocket frame |
|
||||||
| network.remoteIpHeader | HTTP header from proxy containing IP address from client. |
|
| network.remoteIpHeader | HTTP header from proxy containing IP address from client. |
|
||||||
|
| payments.enabled | Enabled payments. Defaults to false. |
|
||||||
|
| payments.processor | Either `zebedee`, `lnbits`, `lnurl`. |
|
||||||
|
| payments.feeSchedules.admission[].enabled | Enables admission fee. Defaults to false. |
|
||||||
|
| payments.feeSchedules.admission[].amount | Admission fee amount in msats. |
|
||||||
|
| payments.feeSchedules.admission[].whitelists.pubkeys | List of pubkeys to waive admission fee. |
|
||||||
|
| payments.feeSchedules.admission[].whitelists.event_kinds | List of event kinds to waive admission fee. Use `[min, max]` for ranges. |
|
||||||
|
| paymentProcessors.zebedee.baseURL | Zebedee's API base URL. |
|
||||||
|
| paymentProcessors.zebedee.callbackBaseURL | Public-facing Nostream's Zebedee Callback URL (e.g. https://relay.your-domain.com/callbacks/zebedee) |
|
||||||
|
| paymentProcessors.zebedee.ipWhitelist | List with Zebedee's API Production IPs. See [ZBD API Documentation](https://api-reference.zebedee.io/#c7e18276-6935-4cca-89ae-ad949efe9a6a) for more info. |
|
||||||
|
| paymentProcessors.lnbits.baseURL | Base URL of your Lnbits instance. |
|
||||||
|
| paymentProcessors.lnbits.callbackBaseURL | Public-facing Nostream's Lnbits Callback URL. (e.g. https://relay.your-domain.com/callbacks/lnbits) |
|
||||||
|
| paymentProcessors.lnurl.invoiceURL | [LUD-06 Pay Request](https://github.com/lnurl/luds/blob/luds/06.md) provider URL. (e.g. https://getalby.com/lnurlp/your-username) |
|
||||||
| mirroring.static[].address | Address of mirrored relay. (e.g. ws://100.100.100.100:8008) |
|
| mirroring.static[].address | Address of mirrored relay. (e.g. ws://100.100.100.100:8008) |
|
||||||
| mirroring.static[].filters | Subscription filters used to mirror. |
|
| mirroring.static[].filters | Subscription filters used to mirror. |
|
||||||
| mirroring.static[].secret | Secret to pass to relays. Nostream relays only. Optional. |
|
| mirroring.static[].secret | Secret to pass to relays. Nostream relays only. Optional. |
|
||||||
|
@ -16,7 +16,7 @@ services:
|
|||||||
DB_MAX_POOL_SIZE: 64
|
DB_MAX_POOL_SIZE: 64
|
||||||
DB_ACQUIRE_CONNECTION_TIMEOUT: 60000
|
DB_ACQUIRE_CONNECTION_TIMEOUT: 60000
|
||||||
# Read Replica
|
# Read Replica
|
||||||
READ_REPLICAS: 1
|
READ_REPLICAS: 2
|
||||||
READ_REPLICA_ENABLED: 'false'
|
READ_REPLICA_ENABLED: 'false'
|
||||||
# Read Replica No. 1
|
# Read Replica No. 1
|
||||||
RR0_DB_HOST: db
|
RR0_DB_HOST: db
|
||||||
@ -36,6 +36,7 @@ services:
|
|||||||
RR1_DB_MIN_POOL_SIZE: 16
|
RR1_DB_MIN_POOL_SIZE: 16
|
||||||
RR1_DB_MAX_POOL_SIZE: 64
|
RR1_DB_MAX_POOL_SIZE: 64
|
||||||
RR1_DB_ACQUIRE_CONNECTION_TIMEOUT: 10000
|
RR1_DB_ACQUIRE_CONNECTION_TIMEOUT: 10000
|
||||||
|
# Add RR2, RR3, etc. to configure more read replicas
|
||||||
# Redis
|
# Redis
|
||||||
REDIS_HOST: nostream-cache
|
REDIS_HOST: nostream-cache
|
||||||
REDIS_PORT: 6379
|
REDIS_PORT: 6379
|
||||||
|
@ -15,9 +15,8 @@ payments:
|
|||||||
whitelists:
|
whitelists:
|
||||||
pubkeys:
|
pubkeys:
|
||||||
- replace-with-your-pubkey-in-hex
|
- replace-with-your-pubkey-in-hex
|
||||||
# Allow the following Zap providers:
|
event_kinds:
|
||||||
# LightningTipBot by Calle
|
- 9735 # Nip-57 Lightning Zap Receipts
|
||||||
- "fcd720c38d9ee337188f47aac845dcd8f590ccdb4a928b76dde18187b4c9d37d"
|
|
||||||
paymentsProcessors:
|
paymentsProcessors:
|
||||||
zebedee:
|
zebedee:
|
||||||
baseURL: https://api.zebedee.io/
|
baseURL: https://api.zebedee.io/
|
||||||
@ -77,19 +76,19 @@ limits:
|
|||||||
maxNegativeDelta: 0
|
maxNegativeDelta: 0
|
||||||
content:
|
content:
|
||||||
- description: 64 KB for event kind ranges 0-10 and 40-49
|
- description: 64 KB for event kind ranges 0-10 and 40-49
|
||||||
|
maxLength: 102400
|
||||||
kinds:
|
kinds:
|
||||||
- - 0
|
- - 0
|
||||||
- 10
|
- 10
|
||||||
- - 40
|
- - 40
|
||||||
- 49
|
- 49
|
||||||
maxLength: 102400
|
|
||||||
- description: 96 KB for event kind ranges 11-39 and 50-max
|
- description: 96 KB for event kind ranges 11-39 and 50-max
|
||||||
|
maxLength: 102400
|
||||||
kinds:
|
kinds:
|
||||||
- - 11
|
- - 11
|
||||||
- 39
|
- 39
|
||||||
- - 50
|
- - 50
|
||||||
- 9007199254740991
|
- 9007199254740991
|
||||||
maxLength: 102400
|
|
||||||
rateLimits:
|
rateLimits:
|
||||||
- description: 6 events/min for event kinds 0, 3, 40 and 41
|
- description: 6 events/min for event kinds 0, 3, 40 and 41
|
||||||
kinds:
|
kinds:
|
||||||
|
@ -126,6 +126,7 @@ export interface Worker {
|
|||||||
|
|
||||||
export interface FeeScheduleWhitelists {
|
export interface FeeScheduleWhitelists {
|
||||||
pubkeys?: Pubkey[]
|
pubkeys?: Pubkey[]
|
||||||
|
event_kinds?: (EventKinds | [EventKinds, EventKinds])[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FeeSchedule {
|
export interface FeeSchedule {
|
||||||
|
@ -5,6 +5,7 @@ export enum EventKinds {
|
|||||||
CONTACT_LIST = 3,
|
CONTACT_LIST = 3,
|
||||||
ENCRYPTED_DIRECT_MESSAGE = 4,
|
ENCRYPTED_DIRECT_MESSAGE = 4,
|
||||||
DELETE = 5,
|
DELETE = 5,
|
||||||
|
REPOST = 6,
|
||||||
REACTION = 7,
|
REACTION = 7,
|
||||||
// Channels
|
// Channels
|
||||||
CHANNEL_CREATION = 40,
|
CHANNEL_CREATION = 40,
|
||||||
@ -17,6 +18,9 @@ export enum EventKinds {
|
|||||||
// Relay-only
|
// Relay-only
|
||||||
RELAY_INVITE = 50,
|
RELAY_INVITE = 50,
|
||||||
INVOICE_UPDATE = 402,
|
INVOICE_UPDATE = 402,
|
||||||
|
// Lightning zaps
|
||||||
|
ZAP_REQUEST = 9734,
|
||||||
|
ZAP_RECEIPT = 9735,
|
||||||
// Replaceable events
|
// Replaceable events
|
||||||
REPLACEABLE_FIRST = 10000,
|
REPLACEABLE_FIRST = 10000,
|
||||||
REPLACEABLE_LAST = 19999,
|
REPLACEABLE_LAST = 19999,
|
||||||
|
@ -268,6 +268,7 @@ export class EventMessageHandler implements IMessageHandler {
|
|||||||
const isApplicableFee = (feeSchedule: FeeSchedule) =>
|
const isApplicableFee = (feeSchedule: FeeSchedule) =>
|
||||||
feeSchedule.enabled
|
feeSchedule.enabled
|
||||||
&& !feeSchedule.whitelists?.pubkeys?.some((prefix) => event.pubkey.startsWith(prefix))
|
&& !feeSchedule.whitelists?.pubkeys?.some((prefix) => event.pubkey.startsWith(prefix))
|
||||||
|
&& !feeSchedule.whitelists?.event_kinds?.some(isEventKindOrRangeMatch(event))
|
||||||
|
|
||||||
const feeSchedules = currentSettings.payments?.feeSchedules?.admission?.filter(isApplicableFee)
|
const feeSchedules = currentSettings.payments?.feeSchedules?.admission?.filter(isApplicableFee)
|
||||||
if (!Array.isArray(feeSchedules) || !feeSchedules.length) {
|
if (!Array.isArray(feeSchedules) || !feeSchedules.length) {
|
||||||
|
@ -585,7 +585,7 @@ describe('EventMessageHandler', () => {
|
|||||||
|
|
||||||
it('returns undefined if kind is not blacklisted in range', () => {
|
it('returns undefined if kind is not blacklisted in range', () => {
|
||||||
eventLimits.kind.blacklist = [[1, 5]]
|
eventLimits.kind.blacklist = [[1, 5]]
|
||||||
event.kind = 6
|
event.kind = EventKinds.REACTION
|
||||||
expect(
|
expect(
|
||||||
(handler as any).canAcceptEvent(event)
|
(handler as any).canAcceptEvent(event)
|
||||||
).to.be.undefined
|
).to.be.undefined
|
||||||
@ -652,10 +652,10 @@ describe('EventMessageHandler', () => {
|
|||||||
|
|
||||||
it('returns reason if kind is not whitelisted in range', () => {
|
it('returns reason if kind is not whitelisted in range', () => {
|
||||||
eventLimits.kind.whitelist = [[1, 5]]
|
eventLimits.kind.whitelist = [[1, 5]]
|
||||||
event.kind = 6
|
event.kind = EventKinds.REACTION
|
||||||
expect(
|
expect(
|
||||||
(handler as any).canAcceptEvent(event)
|
(handler as any).canAcceptEvent(event)
|
||||||
).to.equal('blocked: event kind 6 not allowed')
|
).to.equal('blocked: event kind 7 not allowed')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -867,11 +867,6 @@ describe('EventMessageHandler', () => {
|
|||||||
period: 60000,
|
period: 60000,
|
||||||
rate: 2,
|
rate: 2,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
kinds: [[10, 20]],
|
|
||||||
period: 86400000,
|
|
||||||
rate: 3,
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
|
|
||||||
rateLimiterHitStub.resolves(false)
|
rateLimiterHitStub.resolves(false)
|
||||||
@ -931,4 +926,167 @@ describe('EventMessageHandler', () => {
|
|||||||
expect(actualResult).to.be.true
|
expect(actualResult).to.be.true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('isUserAdmitted', () => {
|
||||||
|
let settings: Settings
|
||||||
|
let userRepository: IUserRepository
|
||||||
|
let getClientAddressStub: SinonStub
|
||||||
|
let webSocket: IWebSocketAdapter
|
||||||
|
let getRelayPublicKeyStub: SinonStub
|
||||||
|
let userRepositoryFindByPubkeyStub: SinonStub
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
settings = {
|
||||||
|
info: {
|
||||||
|
relay_url: 'relay_url',
|
||||||
|
},
|
||||||
|
payments: {
|
||||||
|
enabled: true,
|
||||||
|
feeSchedules: {
|
||||||
|
admission: [
|
||||||
|
{
|
||||||
|
enabled: true,
|
||||||
|
amount: 1000n,
|
||||||
|
whitelists: {
|
||||||
|
pubkeys: [],
|
||||||
|
event_kinds: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
limits: {
|
||||||
|
event: {
|
||||||
|
pubkey: {
|
||||||
|
minBalance: 0n,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as any
|
||||||
|
event = {
|
||||||
|
content: 'hello',
|
||||||
|
created_at: 1665546189,
|
||||||
|
id: 'f'.repeat(64),
|
||||||
|
kind: 1,
|
||||||
|
pubkey: 'f'.repeat(64),
|
||||||
|
sig: 'f'.repeat(128),
|
||||||
|
tags: [],
|
||||||
|
}
|
||||||
|
getRelayPublicKeyStub = sandbox.stub(EventMessageHandler.prototype, 'getRelayPublicKey' as any)
|
||||||
|
getClientAddressStub = sandbox.stub()
|
||||||
|
userRepositoryFindByPubkeyStub = sandbox.stub()
|
||||||
|
webSocket = {
|
||||||
|
getClientAddress: getClientAddressStub,
|
||||||
|
} as any
|
||||||
|
userRepository = {
|
||||||
|
findByPubkey: userRepositoryFindByPubkeyStub,
|
||||||
|
} as any
|
||||||
|
handler = new EventMessageHandler(
|
||||||
|
webSocket,
|
||||||
|
() => null,
|
||||||
|
userRepository,
|
||||||
|
() => settings,
|
||||||
|
() => ({ hit: async () => false })
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it ('fulfills with undefined if payments are disabled', async () => {
|
||||||
|
settings.payments.enabled = false
|
||||||
|
|
||||||
|
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fulfills with undefined if event pubkey equals relay\'s own public key', async () => {
|
||||||
|
getRelayPublicKeyStub.returns(event.pubkey)
|
||||||
|
|
||||||
|
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fulfills with undefined if fee schedules are not set', async () => {
|
||||||
|
settings.payments.feeSchedules = undefined
|
||||||
|
|
||||||
|
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fulfills with undefined if admission fee schedules are not set', async () => {
|
||||||
|
settings.payments.feeSchedules.admission = undefined
|
||||||
|
|
||||||
|
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fulfills with undefined if there are no admission fee schedules', async () => {
|
||||||
|
settings.payments.feeSchedules.admission = []
|
||||||
|
|
||||||
|
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fulfills with undefined if there are no enabled admission fee schedules', async () => {
|
||||||
|
settings.payments.feeSchedules.admission[0].enabled = false
|
||||||
|
|
||||||
|
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fulfills with undefined if admission fee schedule is waived for pubkey', async () => {
|
||||||
|
settings.payments.feeSchedules.admission[0].whitelists.pubkeys.push(event.pubkey)
|
||||||
|
|
||||||
|
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fulfills with undefined if admission fee schedule is waived for event kind', async () => {
|
||||||
|
event.kind = EventKinds.ZAP_RECEIPT
|
||||||
|
settings.payments.feeSchedules.admission[0].whitelists.event_kinds.push(EventKinds.ZAP_RECEIPT)
|
||||||
|
|
||||||
|
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fulfills with undefined if admission fee schedule is waived for event kind range', async () => {
|
||||||
|
event.kind = EventKinds.TEXT_NOTE
|
||||||
|
settings.payments.feeSchedules.admission[0].whitelists.event_kinds.push([
|
||||||
|
EventKinds.SET_METADATA,
|
||||||
|
EventKinds.RECOMMEND_SERVER,
|
||||||
|
])
|
||||||
|
|
||||||
|
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fulfills with reason if admission fee schedule is not waived for event kind range', async () => {
|
||||||
|
event.kind = EventKinds.CONTACT_LIST
|
||||||
|
settings.payments.feeSchedules.admission[0].whitelists.event_kinds.push([
|
||||||
|
EventKinds.SET_METADATA,
|
||||||
|
EventKinds.RECOMMEND_SERVER,
|
||||||
|
])
|
||||||
|
|
||||||
|
return expect((handler as any).isUserAdmitted(event)).to.eventually.equal('blocked: pubkey not admitted')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fulfills with reason if user is not found', async () => {
|
||||||
|
return expect((handler as any).isUserAdmitted(event)).to.eventually.equal('blocked: pubkey not admitted')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fulfills with reason if user is not admitted', async () => {
|
||||||
|
userRepositoryFindByPubkeyStub.resolves({ isAdmitted: false })
|
||||||
|
|
||||||
|
return expect((handler as any).isUserAdmitted(event)).to.eventually.equal('blocked: pubkey not admitted')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fulfills with reason if user is not admitted', async () => {
|
||||||
|
userRepositoryFindByPubkeyStub.resolves({ isAdmitted: false })
|
||||||
|
|
||||||
|
return expect((handler as any).isUserAdmitted(event)).to.eventually.equal('blocked: pubkey not admitted')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fulfills with reason if user does not meet minimum balance', async () => {
|
||||||
|
settings.limits.event.pubkey.minBalance = 1000n
|
||||||
|
userRepositoryFindByPubkeyStub.resolves({ isAdmitted: true, balance: 999n })
|
||||||
|
|
||||||
|
return expect((handler as any).isUserAdmitted(event)).to.eventually.equal('blocked: insufficient balance')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fulfills with undefined if user is admitted', async () => {
|
||||||
|
settings.limits.event.pubkey.minBalance = 0n
|
||||||
|
userRepositoryFindByPubkeyStub.resolves({ isAdmitted: true })
|
||||||
|
|
||||||
|
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user