feat: massive update

Signed-off-by: Ricardo Arturo Cabral Mejía <me@ricardocabral.io>
This commit is contained in:
Ricardo Arturo Cabral Mejía
2023-01-27 02:57:20 -05:00
parent 55561847e8
commit f9c53eeeb8
80 changed files with 2131 additions and 682 deletions

View File

@@ -1,11 +1,11 @@
import { expect } from 'chai'
import { IEventRepository, IUserRepository } from '../../../src/@types/repositories'
import { IncomingMessage, MessageType } from '../../../src/@types/messages'
import { DelegatedEventMessageHandler } from '../../../src/handlers/delegated-event-message-handler'
import { Event } from '../../../src/@types/event'
import { EventMessageHandler } from '../../../src/handlers/event-message-handler'
import { EventTags } from '../../../src/constants/base'
import { IEventRepository } from '../../../src/@types/repositories'
import { IWebSocketAdapter } from '../../../src/@types/adapters'
import { messageHandlerFactory } from '../../../src/factories/message-handler-factory'
import { SubscribeMessageHandler } from '../../../src/handlers/subscribe-message-handler'
@@ -14,17 +14,19 @@ import { UnsubscribeMessageHandler } from '../../../src/handlers/unsubscribe-mes
describe('messageHandlerFactory', () => {
let event: Event
let eventRepository: IEventRepository
let userRepository: IUserRepository
let message: IncomingMessage
let adapter: IWebSocketAdapter
let factory
beforeEach(() => {
eventRepository = {} as any
userRepository = {} as any
adapter = {} as any
event = {
tags: [],
} as any
factory = messageHandlerFactory(eventRepository)
factory = messageHandlerFactory(eventRepository, userRepository)
})
it('returns EventMessageHandler when given an EVENT message', () => {

View File

@@ -3,7 +3,7 @@ import { IncomingMessage } from 'http'
import Sinon from 'sinon'
import WebSocket from 'ws'
import { IEventRepository } from '../../../src/@types/repositories'
import { IEventRepository, IUserRepository } from '../../../src/@types/repositories'
import { IWebSocketServerAdapter } from '../../../src/@types/adapters'
import { WebSocketAdapter } from '../../../src/adapters/web-socket-adapter'
import { webSocketAdapterFactory } from '../../../src/factories/websocket-adapter-factory'
@@ -21,6 +21,7 @@ describe('webSocketAdapterFactory', () => {
it('returns a WebSocketAdapter', () => {
const eventRepository: IEventRepository = {} as any
const userRepository: IUserRepository = {} as any
const client: WebSocket = {
on: onStub,
@@ -37,7 +38,7 @@ describe('webSocketAdapterFactory', () => {
const webSocketServerAdapter: IWebSocketServerAdapter = {} as any
expect(
webSocketAdapterFactory(eventRepository)([client, request, webSocketServerAdapter])
webSocketAdapterFactory(eventRepository, userRepository)([client, request, webSocketServerAdapter])
).to.be.an.instanceOf(WebSocketAdapter)
})
})

View File

@@ -6,6 +6,7 @@ import * as databaseClientModule from '../../../src/database/client'
import { AppWorker } from '../../../src/app/worker'
import { workerFactory } from '../../../src/factories/worker-factory'
describe('workerFactory', () => {
let getMasterDbClientStub: Sinon.SinonStub
let getReadReplicaDbClientStub: Sinon.SinonStub

View File

@@ -11,6 +11,7 @@ import { IncomingEventMessage, MessageType } from '../../../src/@types/messages'
import { DelegatedEventMessageHandler } from '../../../src/handlers/delegated-event-message-handler'
import { Event } from '../../../src/@types/event'
import { EventMessageHandler } from '../../../src/handlers/event-message-handler'
import { IUserRepository } from '../../../src/@types/repositories'
import { WebSocketAdapterEvent } from '../../../src/constants/adapter'
const { expect } = chai
@@ -18,11 +19,12 @@ const { expect } = chai
describe('DelegatedEventMessageHandler', () => {
let webSocket: EventEmitter
let handler: DelegatedEventMessageHandler
let userRepository: IUserRepository
let event: Event
let message: IncomingEventMessage
let sandbox: Sinon.SinonSandbox
let originalConsoleWarn: (message?: any, ...optionalParams: any[]) => void | undefined = undefined
let originalConsoleWarn: any = undefined
beforeEach(() => {
sandbox = Sinon.createSandbox()
@@ -53,10 +55,12 @@ describe('DelegatedEventMessageHandler', () => {
let onMessageSpy: Sinon.SinonSpy
let strategyExecuteStub: Sinon.SinonStub
let isRateLimitedStub: Sinon.SinonStub
let isUserAdmitted: Sinon.SinonStub
beforeEach(() => {
canAcceptEventStub = sandbox.stub(DelegatedEventMessageHandler.prototype, 'canAcceptEvent' as any)
isEventValidStub = sandbox.stub(DelegatedEventMessageHandler.prototype, 'isEventValid' as any)
isUserAdmitted = sandbox.stub(EventMessageHandler.prototype, 'isUserAdmitted' as any)
strategyExecuteStub = sandbox.stub()
strategyFactoryStub = sandbox.stub().returns({
execute: strategyExecuteStub,
@@ -69,6 +73,7 @@ describe('DelegatedEventMessageHandler', () => {
handler = new DelegatedEventMessageHandler(
webSocket as any,
strategyFactoryStub,
userRepository,
() => ({}) as any,
() => ({ hit: async () => false }),
)
@@ -119,6 +124,21 @@ describe('DelegatedEventMessageHandler', () => {
expect(strategyFactoryStub).not.to.have.been.called
})
it('rejects event is user is not admitted', async () => {
isUserAdmitted.resolves('not admitted')
await handler.handleMessage(message)
expect(isRateLimitedStub).to.have.been.calledOnceWithExactly(event)
expect(isUserAdmitted).to.have.been.calledOnceWithExactly(event)
expect(onMessageSpy).to.have.been.calledOnceWithExactly([
MessageType.OK,
event.id,
false,
'not admitted',
])
})
it('does not call strategy if none given', async () => {
isEventValidStub.returns(undefined)
canAcceptEventStub.returns(undefined)

View File

@@ -3,14 +3,17 @@ import EventEmitter from 'events'
import Sinon, { SinonFakeTimers, SinonStub } from 'sinon'
import chai from 'chai'
import chaiAsPromised from 'chai-as-promised'
import sinonChai from 'sinon-chai'
chai.use(sinonChai)
chai.use(chaiAsPromised)
import { EventLimits, ISettings } from '../../../src/@types/settings'
import { EventLimits, Settings } from '../../../src/@types/settings'
import { IncomingEventMessage, MessageType } from '../../../src/@types/messages'
import { Event } from '../../../src/@types/event'
import { EventKinds } from '../../../src/constants/base'
import { EventMessageHandler } from '../../../src/handlers/event-message-handler'
import { IUserRepository } from '../../../src/@types/repositories'
import { IWebSocketAdapter } from '../../../src/@types/adapters'
import { WebSocketAdapterEvent } from '../../../src/constants/adapter'
@@ -19,6 +22,7 @@ const { expect } = chai
describe('EventMessageHandler', () => {
let webSocket: IWebSocketAdapter
let handler: EventMessageHandler
let userRepository: IUserRepository
let event: Event
let message: IncomingEventMessage
let sandbox: Sinon.SinonSandbox
@@ -52,10 +56,12 @@ describe('EventMessageHandler', () => {
let onMessageSpy: Sinon.SinonSpy
let strategyExecuteStub: Sinon.SinonStub
let isRateLimitedStub: Sinon.SinonStub
let isUserAdmitted: Sinon.SinonStub
beforeEach(() => {
canAcceptEventStub = sandbox.stub(EventMessageHandler.prototype, 'canAcceptEvent' as any)
isEventValidStub = sandbox.stub(EventMessageHandler.prototype, 'isEventValid' as any)
isUserAdmitted = sandbox.stub(EventMessageHandler.prototype, 'isUserAdmitted' as any)
strategyExecuteStub = sandbox.stub()
strategyFactoryStub = sandbox.stub().returns({
execute: strategyExecuteStub,
@@ -68,6 +74,7 @@ describe('EventMessageHandler', () => {
handler = new EventMessageHandler(
webSocket as any,
strategyFactoryStub,
userRepository,
() => ({}) as any,
() => ({ hit: async () => false })
)
@@ -113,6 +120,15 @@ describe('EventMessageHandler', () => {
expect(strategyFactoryStub).not.to.have.been.called
})
it('rejects event if user is not admitted', async () => {
isUserAdmitted.resolves('reason')
await handler.handleMessage(message)
expect(isUserAdmitted).to.have.been.calledWithExactly(event)
expect(strategyFactoryStub).not.to.have.been.called
})
it('does not call strategy if none given', async () => {
isEventValidStub.returns(undefined)
canAcceptEventStub.returns(undefined)
@@ -156,7 +172,7 @@ describe('EventMessageHandler', () => {
describe('canAcceptEvent', () => {
let eventLimits: EventLimits
let settings: ISettings
let settings: Settings
let clock: SinonFakeTimers
beforeEach(() => {
@@ -175,7 +191,7 @@ describe('EventMessageHandler', () => {
whitelist: [],
},
pubkey: {
minBalanceMsats: 0,
minBalance: 0n,
minLeadingZeroBits: 0,
blacklist: [],
whitelist: [],
@@ -192,6 +208,7 @@ describe('EventMessageHandler', () => {
handler = new EventMessageHandler(
{} as any,
() => null,
userRepository,
() => settings,
() => ({ hit: async () => false })
)
@@ -640,8 +657,9 @@ describe('EventMessageHandler', () => {
describe('isRateLimited', () => {
let eventLimits: EventLimits
let settings: ISettings
let settings: Settings
let rateLimiterHitStub: SinonStub
let userRepository: IUserRepository
let getClientAddressStub: Sinon.SinonStub
let webSocket: IWebSocketAdapter
@@ -662,6 +680,7 @@ describe('EventMessageHandler', () => {
handler = new EventMessageHandler(
webSocket,
() => null,
userRepository,
() => settings,
() => ({ hit: rateLimiterHitStub })
)

View File

@@ -11,8 +11,8 @@ chai.use(sinonChai)
const { expect } = chai
import { ContextMetadataKey, EventDeduplicationMetadataKey } from '../../../src/constants/base'
import { DatabaseClient } from '../../../src/@types/base'
import { EventDeduplicationMetadataKey } from '../../../src/constants/base'
import { EventRepository } from '../../../src/repositories/event-repository'
describe('EventRepository', () => {
@@ -35,6 +35,7 @@ describe('EventRepository', () => {
})
afterEach(() => {
dbClient.destroy()
sandbox.restore()
})
@@ -46,10 +47,6 @@ describe('EventRepository', () => {
expect(repository.findByFilters([{}])).to.have.property('finally')
})
it('throws error if filters is not an array', () => {
expect(() => repository.findByFilters('' as any)).to.throw(Error, 'Filters cannot be empty')
})
it('throws error if filters is empty', () => {
expect(() => repository.findByFilters([])).to.throw(Error, 'Filters cannot be empty')
})
@@ -60,7 +57,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" order by "event_created_at" asc')
expect(query).to.equal('select * from "events" order by "event_created_at" asc limit 500')
})
describe('authors', () => {
@@ -69,7 +66,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where (1 = 0) order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where (1 = 0) order by "event_created_at" asc limit 500')
})
it('selects events by one author', () => {
@@ -77,7 +74,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where ("event_pubkey" in (X\'22e804d26ed16b68db5259e78449e96dab5d464c8f470bda3eb1a70467f2c793\') or "event_delegator" in (X\'22e804d26ed16b68db5259e78449e96dab5d464c8f470bda3eb1a70467f2c793\')) order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where ("event_pubkey" in (X\'22e804d26ed16b68db5259e78449e96dab5d464c8f470bda3eb1a70467f2c793\') or "event_delegator" in (X\'22e804d26ed16b68db5259e78449e96dab5d464c8f470bda3eb1a70467f2c793\')) order by "event_created_at" asc limit 500')
})
it('selects events by two authors', () => {
@@ -92,7 +89,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where ("event_pubkey" in (X\'22e804d26ed16b68db5259e78449e96dab5d464c8f470bda3eb1a70467f2c793\', X\'32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245\') or "event_delegator" in (X\'22e804d26ed16b68db5259e78449e96dab5d464c8f470bda3eb1a70467f2c793\', X\'32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245\')) order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where ("event_pubkey" in (X\'22e804d26ed16b68db5259e78449e96dab5d464c8f470bda3eb1a70467f2c793\', X\'32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245\') or "event_delegator" in (X\'22e804d26ed16b68db5259e78449e96dab5d464c8f470bda3eb1a70467f2c793\', X\'32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245\')) order by "event_created_at" asc limit 500')
})
it('selects events by one author prefix (even length)', () => {
@@ -106,7 +103,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where (substring("event_pubkey" from 1 for 3) = X\'22e804\' or substring("event_delegator" from 1 for 3) = X\'22e804\') order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where (substring("event_pubkey" from 1 for 3) = X\'22e804\' or substring("event_delegator" from 1 for 3) = X\'22e804\') order by "event_created_at" asc limit 500')
})
it('selects events by one author prefix (odd length)', () => {
@@ -120,7 +117,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where (substring("event_pubkey" from 1 for 4) BETWEEN E\'\\\\x22e804f0\' AND E\'\\\\x22e804ff\' or substring("event_delegator" from 1 for 4) BETWEEN E\'\\\\x22e804f0\' AND E\'\\\\x22e804ff\') order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where (substring("event_pubkey" from 1 for 4) BETWEEN E\'\\\\x22e804f0\' AND E\'\\\\x22e804ff\' or substring("event_delegator" from 1 for 4) BETWEEN E\'\\\\x22e804f0\' AND E\'\\\\x22e804ff\') order by "event_created_at" asc limit 500')
})
it('selects events by two author prefix (first even, second odd)', () => {
@@ -135,7 +132,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where (substring("event_pubkey" from 1 for 3) = X\'22e804\' or substring("event_delegator" from 1 for 3) = X\'22e804\' or substring("event_pubkey" from 1 for 4) BETWEEN E\'\\\\x32e18270\' AND E\'\\\\x32e1827f\' or substring("event_delegator" from 1 for 4) BETWEEN E\'\\\\x32e18270\' AND E\'\\\\x32e1827f\') order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where (substring("event_pubkey" from 1 for 3) = X\'22e804\' or substring("event_delegator" from 1 for 3) = X\'22e804\' or substring("event_pubkey" from 1 for 4) BETWEEN E\'\\\\x32e18270\' AND E\'\\\\x32e1827f\' or substring("event_delegator" from 1 for 4) BETWEEN E\'\\\\x32e18270\' AND E\'\\\\x32e1827f\') order by "event_created_at" asc limit 500')
})
})
@@ -145,7 +142,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where (1 = 0) order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where (1 = 0) order by "event_created_at" asc limit 500')
})
it('selects events by one id', () => {
@@ -153,7 +150,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where ("event_id" in (X\'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\')) order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where ("event_id" in (X\'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\')) order by "event_created_at" asc limit 500')
})
it('selects events by two ids', () => {
@@ -168,7 +165,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where ("event_id" in (X\'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\', X\'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\')) order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where ("event_id" in (X\'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\', X\'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\')) order by "event_created_at" asc limit 500')
})
it('selects events by one id prefix (even length)', () => {
@@ -182,7 +179,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where (substring("event_id" from 1 for 2) = X\'abcd\') order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where (substring("event_id" from 1 for 2) = X\'abcd\') order by "event_created_at" asc limit 500')
})
it('selects events by one id prefix (odd length)', () => {
@@ -196,7 +193,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where (substring("event_id" from 1 for 2) BETWEEN E\'\\\\xabc0\' AND E\'\\\\xabcf\') order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where (substring("event_id" from 1 for 2) BETWEEN E\'\\\\xabc0\' AND E\'\\\\xabcf\') order by "event_created_at" asc limit 500')
})
it('selects events by two id prefix (first even, second odd)', () => {
@@ -211,7 +208,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where (substring("event_id" from 1 for 3) = X\'abcdef\' or substring("event_id" from 1 for 2) BETWEEN E\'\\\\xabc0\' AND E\'\\\\xabcf\') order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where (substring("event_id" from 1 for 3) = X\'abcdef\' or substring("event_id" from 1 for 2) BETWEEN E\'\\\\xabc0\' AND E\'\\\\xabcf\') order by "event_created_at" asc limit 500')
})
})
@@ -221,7 +218,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where 1 = 0 order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where 1 = 0 order by "event_created_at" asc limit 500')
})
it('selects events by one kind', () => {
@@ -229,7 +226,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where "event_kind" in (1) order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where "event_kind" in (1) order by "event_created_at" asc limit 500')
})
it('selects events by two kinds', () => {
@@ -237,7 +234,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where "event_kind" in (1, 2) order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where "event_kind" in (1, 2) order by "event_created_at" asc limit 500')
})
})
@@ -247,7 +244,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where "event_created_at" >= 1000 order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where "event_created_at" >= 1000 order by "event_created_at" asc limit 500')
})
})
@@ -257,7 +254,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where "event_created_at" <= 1000 order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where "event_created_at" <= 1000 order by "event_created_at" asc limit 500')
})
})
@@ -277,7 +274,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where (1 = 0) order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where (1 = 0) order by "event_created_at" asc limit 500')
})
it('selects events by one #e tag', () => {
@@ -285,7 +282,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where ("event_tags" @> \'[["e","aaaaaa"]]\') order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where ("event_tags" @> \'[["e","aaaaaa"]]\') order by "event_created_at" asc limit 500')
})
it('selects events by two #e tag', () => {
@@ -293,7 +290,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where ("event_tags" @> \'[["e","aaaaaa"]]\' or "event_tags" @> \'[["e","bbbbbb"]]\') order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where ("event_tags" @> \'[["e","aaaaaa"]]\' or "event_tags" @> \'[["e","bbbbbb"]]\') order by "event_created_at" asc limit 500')
})
})
@@ -303,7 +300,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where (1 = 0) order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where (1 = 0) order by "event_created_at" asc limit 500')
})
it('selects events by one #p tag', () => {
@@ -311,7 +308,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where ("event_tags" @> \'[["p","aaaaaa"]]\') order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where ("event_tags" @> \'[["p","aaaaaa"]]\') order by "event_created_at" asc limit 500')
})
it('selects events by two #p tag', () => {
@@ -319,7 +316,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where ("event_tags" @> \'[["p","aaaaaa"]]\' or "event_tags" @> \'[["p","bbbbbb"]]\') order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where ("event_tags" @> \'[["p","aaaaaa"]]\' or "event_tags" @> \'[["p","bbbbbb"]]\') order by "event_created_at" asc limit 500')
})
})
@@ -329,7 +326,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where (1 = 0) order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where (1 = 0) order by "event_created_at" asc limit 500')
})
it('selects events by one #r tag', () => {
@@ -337,7 +334,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where ("event_tags" @> \'[["r","aaaaaa"]]\') order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where ("event_tags" @> \'[["r","aaaaaa"]]\') order by "event_created_at" asc limit 500')
})
it('selects events by two #r tag', () => {
@@ -345,7 +342,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('select * from "events" where ("event_tags" @> \'[["r","aaaaaa"]]\' or "event_tags" @> \'[["r","bbbbbb"]]\') order by "event_created_at" asc')
expect(query).to.equal('select * from "events" where ("event_tags" @> \'[["r","aaaaaa"]]\' or "event_tags" @> \'[["r","bbbbbb"]]\') order by "event_created_at" asc limit 500')
})
})
})
@@ -356,7 +353,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('(select * from "events") union (select * from "events" order by "event_created_at" asc) order by "event_created_at" asc')
expect(query).to.equal('(select * from "events") union (select * from "events" order by "event_created_at" asc limit 500) order by "event_created_at" asc limit 500')
})
})
@@ -366,7 +363,7 @@ describe('EventRepository', () => {
const query = repository.findByFilters(filters).toString()
expect(query).to.equal('(select * from "events" where "event_kind" in (1)) union (select * from "events" where (substring("event_id" from 1 for 3) BETWEEN E\'\\\\xaaaaa0\' AND E\'\\\\xaaaaaf\') order by "event_created_at" asc) union (select * from "events" where (substring("event_pubkey" from 1 for 3) BETWEEN E\'\\\\xbbbbb0\' AND E\'\\\\xbbbbbf\' or substring("event_delegator" from 1 for 3) BETWEEN E\'\\\\xbbbbb0\' AND E\'\\\\xbbbbbf\') order by "event_created_at" asc) union (select * from "events" where "event_created_at" >= 1000 order by "event_created_at" asc) union (select * from "events" where "event_created_at" <= 1000 order by "event_created_at" asc) union (select * from "events" order by "event_created_at" DESC limit 1000) order by "event_created_at" asc')
expect(query).to.equal('(select * from "events" where "event_kind" in (1)) union (select * from "events" where (substring("event_id" from 1 for 3) BETWEEN E\'\\\\xaaaaa0\' AND E\'\\\\xaaaaaf\') order by "event_created_at" asc limit 500) union (select * from "events" where (substring("event_pubkey" from 1 for 3) BETWEEN E\'\\\\xbbbbb0\' AND E\'\\\\xbbbbbf\' or substring("event_delegator" from 1 for 3) BETWEEN E\'\\\\xbbbbb0\' AND E\'\\\\xbbbbbf\') order by "event_created_at" asc limit 500) union (select * from "events" where "event_created_at" >= 1000 order by "event_created_at" asc limit 500) union (select * from "events" where "event_created_at" <= 1000 order by "event_created_at" asc limit 500) union (select * from "events" order by "event_created_at" DESC limit 1000) order by "event_created_at" asc limit 500')
})
})
})
@@ -433,11 +430,12 @@ describe('EventRepository', () => {
content:
"I've set up mirroring between relays: https://i.imgur.com/HxCDipB.png",
sig: 'b37adfed0e6398546d623536f9ddc92b95b7dc71927e1123266332659253ecd0ffa91ddf2c0a82a8426c5b363139d28534d6cac893b8a810149557a3f6d36768',
[ContextMetadataKey]: { remoteAddress: { address: '::1' } as any },
}
const query = (repository as any).insert(event).toString()
expect(query).to.equal('insert into "events" ("event_content", "event_created_at", "event_delegator", "event_id", "event_kind", "event_pubkey", "event_signature", "event_tags") values (\'I\'\'ve set up mirroring between relays: https://i.imgur.com/HxCDipB.png\', 1648351380, NULL, X\'6b3cdd0302ded8068ad3f0269c74423ca4fee460f800f3d90103b63f14400407\', 1, X\'22e804d26ed16b68db5259e78449e96dab5d464c8f470bda3eb1a70467f2c793\', X\'b37adfed0e6398546d623536f9ddc92b95b7dc71927e1123266332659253ecd0ffa91ddf2c0a82a8426c5b363139d28534d6cac893b8a810149557a3f6d36768\', \'[["p","8355095016fddbe31fcf1453b26f613553e9758cf2263e190eac8fd96a3d3de9","wss://nostr-pub.wellorder.net"],["e","7377fa81fc6c7ae7f7f4ef8938d4a603f7bf98183b35ab128235cc92d4bebf96","wss://nostr-relay.untethr.me"]]\') on conflict do nothing')
expect(query).to.equal('insert into "events" ("event_content", "event_created_at", "event_delegator", "event_id", "event_kind", "event_pubkey", "event_signature", "event_tags", "remote_address") values (\'I\'\'ve set up mirroring between relays: https://i.imgur.com/HxCDipB.png\', 1648351380, NULL, X\'6b3cdd0302ded8068ad3f0269c74423ca4fee460f800f3d90103b63f14400407\', 1, X\'22e804d26ed16b68db5259e78449e96dab5d464c8f470bda3eb1a70467f2c793\', X\'b37adfed0e6398546d623536f9ddc92b95b7dc71927e1123266332659253ecd0ffa91ddf2c0a82a8426c5b363139d28534d6cac893b8a810149557a3f6d36768\', \'[["p","8355095016fddbe31fcf1453b26f613553e9758cf2263e190eac8fd96a3d3de9","wss://nostr-pub.wellorder.net"],["e","7377fa81fc6c7ae7f7f4ef8938d4a603f7bf98183b35ab128235cc92d4bebf96","wss://nostr-relay.untethr.me"]]\', \'::1\') on conflict do nothing')
})
})
@@ -477,11 +475,12 @@ describe('EventRepository', () => {
'tags': [],
'content': '{"name":"ottman@minds.io","about":"","picture":"https://feat-2311-nostr.minds.io/icon/1002952989368913934/medium/1564498626/1564498626/1653379539"}',
'sig': 'd1de98733de2b412549aa64454722d9b66ab3c68e9e0d0f9c5d42e7bd54c30a06174364b683d2c8dbb386ff47f31e6cb7e2f3c3498d8819ee80421216c8309a9',
[ContextMetadataKey]: { remoteAddress: { address: '::1' } as any },
}
const query = repository.upsert(event).toString()
expect(query).to.equal('insert into "events" ("event_content", "event_created_at", "event_deduplication", "event_delegator", "event_id", "event_kind", "event_pubkey", "event_signature", "event_tags") values (\'{"name":"ottman@minds.io","about":"","picture":"https://feat-2311-nostr.minds.io/icon/1002952989368913934/medium/1564498626/1564498626/1653379539"}\', 1564498626, \'["55b702c167c85eb1c2d5ab35d68bedd1a35b94c01147364d2395c2f66f35a503",0]\', NULL, X\'e527fe8b0f64a38c6877f943a9e8841074056ba72aceb31a4c85e6d10b27095a\', 0, X\'55b702c167c85eb1c2d5ab35d68bedd1a35b94c01147364d2395c2f66f35a503\', X\'d1de98733de2b412549aa64454722d9b66ab3c68e9e0d0f9c5d42e7bd54c30a06174364b683d2c8dbb386ff47f31e6cb7e2f3c3498d8819ee80421216c8309a9\', \'[]\') on conflict (event_pubkey, event_kind, event_deduplication) WHERE (event_kind = 0 OR event_kind = 3 OR event_kind = 41 OR (event_kind >= 10000 AND event_kind < 20000)) OR (event_kind >= 30000 AND event_kind < 40000) do update set "event_id" = X\'e527fe8b0f64a38c6877f943a9e8841074056ba72aceb31a4c85e6d10b27095a\',"event_created_at" = 1564498626,"event_tags" = \'[]\',"event_content" = \'{"name":"ottman@minds.io","about":"","picture":"https://feat-2311-nostr.minds.io/icon/1002952989368913934/medium/1564498626/1564498626/1653379539"}\',"event_signature" = X\'d1de98733de2b412549aa64454722d9b66ab3c68e9e0d0f9c5d42e7bd54c30a06174364b683d2c8dbb386ff47f31e6cb7e2f3c3498d8819ee80421216c8309a9\',"event_delegator" = NULL where "events"."event_created_at" < 1564498626')
expect(query).to.equal('insert into "events" ("event_content", "event_created_at", "event_deduplication", "event_delegator", "event_id", "event_kind", "event_pubkey", "event_signature", "event_tags", "remote_address") values (\'{"name":"ottman@minds.io","about":"","picture":"https://feat-2311-nostr.minds.io/icon/1002952989368913934/medium/1564498626/1564498626/1653379539"}\', 1564498626, \'["55b702c167c85eb1c2d5ab35d68bedd1a35b94c01147364d2395c2f66f35a503",0]\', NULL, X\'e527fe8b0f64a38c6877f943a9e8841074056ba72aceb31a4c85e6d10b27095a\', 0, X\'55b702c167c85eb1c2d5ab35d68bedd1a35b94c01147364d2395c2f66f35a503\', X\'d1de98733de2b412549aa64454722d9b66ab3c68e9e0d0f9c5d42e7bd54c30a06174364b683d2c8dbb386ff47f31e6cb7e2f3c3498d8819ee80421216c8309a9\', \'[]\', \'::1\') on conflict (event_pubkey, event_kind, event_deduplication) WHERE (event_kind = 0 OR event_kind = 3 OR event_kind = 41 OR (event_kind >= 10000 AND event_kind < 20000)) OR (event_kind >= 30000 AND event_kind < 40000) do update set "event_id" = X\'e527fe8b0f64a38c6877f943a9e8841074056ba72aceb31a4c85e6d10b27095a\',"event_created_at" = 1564498626,"event_tags" = \'[]\',"event_content" = \'{"name":"ottman@minds.io","about":"","picture":"https://feat-2311-nostr.minds.io/icon/1002952989368913934/medium/1564498626/1564498626/1653379539"}\',"event_signature" = X\'d1de98733de2b412549aa64454722d9b66ab3c68e9e0d0f9c5d42e7bd54c30a06174364b683d2c8dbb386ff47f31e6cb7e2f3c3498d8819ee80421216c8309a9\',"event_delegator" = NULL,"remote_address" = \'::1\' where "events"."event_created_at" < 1564498626')
})
it('replaces event based on event_pubkey, event_kind and event_deduplication', () => {
@@ -492,13 +491,14 @@ describe('EventRepository', () => {
'kind': 0,
'tags': [],
[EventDeduplicationMetadataKey]: ['deduplication'],
[ContextMetadataKey]: { remoteAddress: { address: '::1' } as any },
'content': '{"name":"ottman@minds.io","about":"","picture":"https://feat-2311-nostr.minds.io/icon/1002952989368913934/medium/1564498626/1564498626/1653379539"}',
'sig': 'd1de98733de2b412549aa64454722d9b66ab3c68e9e0d0f9c5d42e7bd54c30a06174364b683d2c8dbb386ff47f31e6cb7e2f3c3498d8819ee80421216c8309a9',
}
const query = repository.upsert(event).toString()
expect(query).to.equal('insert into "events" ("event_content", "event_created_at", "event_deduplication", "event_delegator", "event_id", "event_kind", "event_pubkey", "event_signature", "event_tags") values (\'{"name":"ottman@minds.io","about":"","picture":"https://feat-2311-nostr.minds.io/icon/1002952989368913934/medium/1564498626/1564498626/1653379539"}\', 1564498626, \'["deduplication"]\', NULL, X\'e527fe8b0f64a38c6877f943a9e8841074056ba72aceb31a4c85e6d10b27095a\', 0, X\'55b702c167c85eb1c2d5ab35d68bedd1a35b94c01147364d2395c2f66f35a503\', X\'d1de98733de2b412549aa64454722d9b66ab3c68e9e0d0f9c5d42e7bd54c30a06174364b683d2c8dbb386ff47f31e6cb7e2f3c3498d8819ee80421216c8309a9\', \'[]\') on conflict (event_pubkey, event_kind, event_deduplication) WHERE (event_kind = 0 OR event_kind = 3 OR event_kind = 41 OR (event_kind >= 10000 AND event_kind < 20000)) OR (event_kind >= 30000 AND event_kind < 40000) do update set "event_id" = X\'e527fe8b0f64a38c6877f943a9e8841074056ba72aceb31a4c85e6d10b27095a\',"event_created_at" = 1564498626,"event_tags" = \'[]\',"event_content" = \'{"name":"ottman@minds.io","about":"","picture":"https://feat-2311-nostr.minds.io/icon/1002952989368913934/medium/1564498626/1564498626/1653379539"}\',"event_signature" = X\'d1de98733de2b412549aa64454722d9b66ab3c68e9e0d0f9c5d42e7bd54c30a06174364b683d2c8dbb386ff47f31e6cb7e2f3c3498d8819ee80421216c8309a9\',"event_delegator" = NULL where "events"."event_created_at" < 1564498626')
expect(query).to.equal('insert into "events" ("event_content", "event_created_at", "event_deduplication", "event_delegator", "event_id", "event_kind", "event_pubkey", "event_signature", "event_tags", "remote_address") values (\'{"name":"ottman@minds.io","about":"","picture":"https://feat-2311-nostr.minds.io/icon/1002952989368913934/medium/1564498626/1564498626/1653379539"}\', 1564498626, \'["deduplication"]\', NULL, X\'e527fe8b0f64a38c6877f943a9e8841074056ba72aceb31a4c85e6d10b27095a\', 0, X\'55b702c167c85eb1c2d5ab35d68bedd1a35b94c01147364d2395c2f66f35a503\', X\'d1de98733de2b412549aa64454722d9b66ab3c68e9e0d0f9c5d42e7bd54c30a06174364b683d2c8dbb386ff47f31e6cb7e2f3c3498d8819ee80421216c8309a9\', \'[]\', \'::1\') on conflict (event_pubkey, event_kind, event_deduplication) WHERE (event_kind = 0 OR event_kind = 3 OR event_kind = 41 OR (event_kind >= 10000 AND event_kind < 20000)) OR (event_kind >= 30000 AND event_kind < 40000) do update set "event_id" = X\'e527fe8b0f64a38c6877f943a9e8841074056ba72aceb31a4c85e6d10b27095a\',"event_created_at" = 1564498626,"event_tags" = \'[]\',"event_content" = \'{"name":"ottman@minds.io","about":"","picture":"https://feat-2311-nostr.minds.io/icon/1002952989368913934/medium/1564498626/1564498626/1653379539"}\',"event_signature" = X\'d1de98733de2b412549aa64454722d9b66ab3c68e9e0d0f9c5d42e7bd54c30a06174364b683d2c8dbb386ff47f31e6cb7e2f3c3498d8819ee80421216c8309a9\',"event_delegator" = NULL,"remote_address" = \'::1\' where "events"."event_created_at" < 1564498626')
})
})
})

View File

@@ -47,22 +47,4 @@ describe('getRemoteAddress', () => {
)
).to.equal(socketAddress)
})
it('returns undefined if unable to find header', () => {
expect(
getRemoteAddress(
{ ...request, socket: {} } as any,
{ network: {} } as any,
)
).to.be.undefined
})
it('returns undefined if header setting is unset', () => {
expect(
getRemoteAddress(
{ ...request, socket: {} } as any,
{} as any,
)
).to.be.undefined
})
})

View File

@@ -14,6 +14,9 @@ describe('SlidingWindowRateLimiter', () => {
let addToSortedSetStub: Sinon.SinonStub
let getRangeFromSortedSetStub: Sinon.SinonStub
let setKeyExpiryStub: Sinon.SinonStub
let getKeyStub: Sinon.SinonStub
let hasKeyStub: Sinon.SinonStub
let setKeyStub: Sinon.SinonStub
let sandbox: Sinon.SinonSandbox
@@ -24,11 +27,17 @@ describe('SlidingWindowRateLimiter', () => {
addToSortedSetStub = sandbox.stub()
getRangeFromSortedSetStub = sandbox.stub()
setKeyExpiryStub = sandbox.stub()
getKeyStub = sandbox.stub()
hasKeyStub = sandbox.stub()
setKeyStub = sandbox.stub()
cache = {
removeRangeByScoreFromSortedSet: removeRangeByScoreFromSortedSetStub,
addToSortedSet: addToSortedSetStub,
getRangeFromSortedSet: getRangeFromSortedSetStub,
setKeyExpiry: setKeyExpiryStub,
getKey: getKeyStub,
hasKey: hasKeyStub,
setKey: setKeyStub,
}
rateLimiter = new SlidingWindowRateLimiter(cache)
})