mirror of
https://github.com/Cameri/nostream.git
synced 2025-03-17 21:31:48 +01:00
chore: verify incoming events
This commit is contained in:
parent
cce725774c
commit
b2a729c926
@ -16,6 +16,6 @@ module.exports = {
|
||||
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
|
||||
"no-console": "off",
|
||||
semi: ["error", "never"],
|
||||
quotes: ["error", "single"]
|
||||
quotes: ["error", "single", { avoidEscape: true }]
|
||||
},
|
||||
};
|
||||
|
30
README.md
30
README.md
@ -24,14 +24,44 @@ NIPs with a relay-specific implementation are listed here.
|
||||
- [ ] NIP-16: Event Treatment
|
||||
- [ ] NIP-25: Reactions
|
||||
|
||||
## Requirements
|
||||
|
||||
- PostgreSQL
|
||||
- Node
|
||||
- Typescript
|
||||
|
||||
## Quick Start
|
||||
|
||||
Set the following environment variables:
|
||||
|
||||
```
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
DB_NAME=nostr-ts-relay
|
||||
DB_USER=postgres
|
||||
DB_PASSWORD=postgres
|
||||
```
|
||||
|
||||
Create `nostr-ts-relay` database:
|
||||
|
||||
```
|
||||
$ psql -h $DB_HOST -p $DB_PORT -U $DB_USER -W
|
||||
postgres=# create database nostr-ts-relay;
|
||||
postgres=# quit
|
||||
```
|
||||
|
||||
Install dependencies:
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
Run migrations:
|
||||
|
||||
```
|
||||
npm run db:migrate
|
||||
```
|
||||
|
||||
To start in development mode:
|
||||
|
||||
```
|
||||
|
10
knexfile.js
10
knexfile.js
@ -1,11 +1,11 @@
|
||||
module.exports = {
|
||||
client: 'pg',
|
||||
connection: {
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
host: process.env.DB_HOST ?? 'localhost',
|
||||
port: process.env.DB_PORT ?? 5432,
|
||||
user: process.env.DB_USER ?? 'postgres',
|
||||
password: process.env.DB_PASSWORD ?? 'postgres',
|
||||
database: process.env.DB_NAME ?? 'nostr-ts-relay',
|
||||
},
|
||||
pool: { min: 0, max: 7 },
|
||||
seeds: {
|
||||
|
14
package-lock.json
generated
14
package-lock.json
generated
@ -9,7 +9,7 @@
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/secp256k1": "^1.5.5",
|
||||
"@noble/secp256k1": "1.6.3",
|
||||
"joi": "^17.6.0",
|
||||
"knex": "^2.0.0",
|
||||
"pg": "^8.7.3",
|
||||
@ -112,9 +112,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@noble/secp256k1": {
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.5.5.tgz",
|
||||
"integrity": "sha512-sZ1W6gQzYnu45wPrWx8D3kwI2/U29VYTx9OjbDAd7jwRItJ0cSTMPRL/C8AWZFn9kWFLQGqEXVEE86w4Z8LpIQ==",
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.6.3.tgz",
|
||||
"integrity": "sha512-T04e4iTurVy7I8Sw4+c5OSN9/RkPlo1uKxAomtxQNLq8j1uPAqnsqG1bqvY3Jv7c13gyr6dui0zmh/I3+f/JaQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@ -3160,9 +3160,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@noble/secp256k1": {
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.5.5.tgz",
|
||||
"integrity": "sha512-sZ1W6gQzYnu45wPrWx8D3kwI2/U29VYTx9OjbDAd7jwRItJ0cSTMPRL/C8AWZFn9kWFLQGqEXVEE86w4Z8LpIQ=="
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.6.3.tgz",
|
||||
"integrity": "sha512-T04e4iTurVy7I8Sw4+c5OSN9/RkPlo1uKxAomtxQNLq8j1uPAqnsqG1bqvY3Jv7c13gyr6dui0zmh/I3+f/JaQ=="
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
|
@ -52,7 +52,7 @@
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@noble/secp256k1": "^1.5.5",
|
||||
"@noble/secp256k1": "1.6.3",
|
||||
"joi": "^17.6.0",
|
||||
"knex": "^2.0.0",
|
||||
"pg": "^8.7.3",
|
||||
|
@ -83,7 +83,7 @@ export class WebSocketServerAdapter extends WebServerAdapter implements IWebSock
|
||||
this.onWebSocketClientClose(client)
|
||||
})
|
||||
|
||||
client.on('pong', () => this.onWebSocketClientPong.bind(this)(client))
|
||||
client.on('pong', () => this.onWebSocketClientPong.call(this, client))
|
||||
}
|
||||
|
||||
private async onWebSocketClientMessage(client: WebSocket, message: Message) {
|
@ -1,3 +1,4 @@
|
||||
import * as secp256k1 from '@noble/secp256k1'
|
||||
import { CanonicalEvent, Event } from './types/event'
|
||||
import { SubscriptionFilter } from './types/subscription'
|
||||
|
||||
@ -57,3 +58,7 @@ export const isEventMatchingFilter =
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export const isEventSignatureValid = async (event: Event): Promise<boolean> => {
|
||||
return secp256k1.schnorr.verify(event.sig, event.id, event.pubkey)
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { IMessageHandler } from '../types/message-handlers'
|
||||
import { MessageType, IncomingEventMessage } from '../types/messages'
|
||||
import { IWebSocketServerAdapter } from '../types/servers'
|
||||
import { IEventRepository } from '../types/repositories'
|
||||
import { isEventSignatureValid } from '../event'
|
||||
|
||||
export class EventMessageHandler implements IMessageHandler {
|
||||
public constructor(
|
||||
@ -14,11 +15,14 @@ export class EventMessageHandler implements IMessageHandler {
|
||||
}
|
||||
|
||||
public async handleMessage(message: IncomingEventMessage): Promise<boolean> {
|
||||
// TODO: validate
|
||||
if (!await isEventSignatureValid(message[1])) {
|
||||
console.warn(`Event ${message[1].id} from ${message[1].pubkey} with signature ${message[1].sig} is not valid`)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const count = await this.eventRepository.create(message[1])
|
||||
if (!count) {
|
||||
console.debug('Event already exists.')
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
import * as http from 'http'
|
||||
import { WebSocketServer } from 'ws'
|
||||
|
||||
import { getDbClient } from './database/client'
|
||||
import { EventRepository } from './repositories/event-repository'
|
||||
import { WebSocketServerAdapter } from './relay/web-socket-server-adapter'
|
||||
import { WebSocketServerAdapter } from './adapters/web-socket-server-adapter'
|
||||
import { SubscribeMessageHandler } from './handlers/subscribe-message-handler'
|
||||
import { UnsubscribeMessageHandler } from './handlers/unsubscribe-message-handler'
|
||||
import { EventMessageHandler } from './handlers/event-message-handler'
|
||||
|
@ -6,7 +6,3 @@ export interface IMessageHandler {
|
||||
canHandleMessageType(messageType: MessageType): boolean
|
||||
handleMessage(message: Message, client: WebSocket): Promise<boolean>
|
||||
}
|
||||
|
||||
export interface IMessageProcessor {
|
||||
process(message: Message, client: WebSocket): Promise<void>
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { expect } from 'chai'
|
||||
import { Event, CanonicalEvent } from '../../src/types/event'
|
||||
import { isEventMatchingFilter, serializeEvent } from '../../src/event'
|
||||
import { isEventMatchingFilter, isEventSignatureValid, serializeEvent } from '../../src/event'
|
||||
import { EventKinds } from '../../src/constants/base'
|
||||
|
||||
describe('serializeEvent', () => {
|
||||
@ -198,3 +198,33 @@ describe('isEventMatchingFilter', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('isEventSignatureValid', () => {
|
||||
let event: Event
|
||||
|
||||
beforeEach(() => {
|
||||
event = {
|
||||
'id': 'b1601d26958e6508b7b9df0af609c652346c09392b6534d93aead9819a51b4ef',
|
||||
'pubkey': '22e804d26ed16b68db5259e78449e96dab5d464c8f470bda3eb1a70467f2c793',
|
||||
'created_at': 1648339664,
|
||||
'kind': 1,
|
||||
'tags': [],
|
||||
'content': 'learning terraform rn!',
|
||||
'sig': 'ec8b2bc640c8c7e92fbc0e0a6f539da2635068a99809186f15106174d727456132977c78f3371d0ab01c108173df75750f33d8e04c4d7980bbb3fb70ba1e3848'
|
||||
}
|
||||
})
|
||||
|
||||
it('resolves with true if event has a valid signature', async () => {
|
||||
expect(
|
||||
await isEventSignatureValid(event)
|
||||
).to.be.true
|
||||
})
|
||||
|
||||
it('resolves with false if event has a valid signature', async () => {
|
||||
event.id = '1234567890123456789012345678901234567890123456789012345678901234'
|
||||
|
||||
expect(
|
||||
await isEventSignatureValid(event)
|
||||
).to.be.false
|
||||
})
|
||||
})
|
Loading…
x
Reference in New Issue
Block a user