fix: confirm invoice function ambiguous unit variable (#221)

* fix: dont crash when SECRET is not set

* docs: add semisol to contributors

* docs: improve readme

* docs: add payment info to readme

* docs: add zebedee_api_key to configuration.md

* fix: confirm_invoice unit var

* chore: remove unused code

* chore: improve error logging for payments

* chore: use  instead of changeme

* chore: fix typo

* chore: improve get invoice status ctrl

* fix: csp bug

* chore: remove rate limits

* chore: improve invoice page logging

* chore: prevent root with start_local

* chore: revert to redis 4.5.1
This commit is contained in:
Ricardo Arturo Cabral Mejía
2023-02-20 12:15:45 -05:00
committed by GitHub
parent e99ac5d02b
commit fd3294929a
16 changed files with 225 additions and 94 deletions

View File

@@ -6,6 +6,7 @@ The following environment variables can be set:
| Name | Description | Default |
|----------------------------------|--------------------------------|------------------------|
| SECRET | Long random secret. | changeme |
| RELAY_PORT | Relay's server port | 8008 |
| RELAY_PRIVATE_KEY | Relay's private key in hex | (auto-generated) |
| WORKER_COUNT | Number of workers override | No. of available CPUs |
@@ -38,6 +39,7 @@ The following environment variables can be set:
| REDIS_PASSWORD | Redis Password | nostr_ts_relay |
| NOSTR_CONFIG_DIR | Configuration directory | <project_root>/.nostr/ |
| DEBUG | Debugging filter | |
| ZEBEDEE_API_KEY | Zebedee Project API Key | |
# Settings

View File

@@ -50,6 +50,7 @@ NIPs with a relay-specific implementation are listed here.
- [x] NIP-04: Encrypted Direct Message
- [x] NIP-09: Event deletion
- [x] NIP-11: Relay information document
- [x] NIP-11a: Relay Information Document Extensions
- [x] NIP-12: Generic tag queries
- [x] NIP-13: Proof of Work
- [x] NIP-15: End of Stored Events Notice
@@ -60,7 +61,6 @@ NIPs with a relay-specific implementation are listed here.
- [x] NIP-28: Public Chat
- [x] NIP-33: Parameterized Replaceable Events
- [x] NIP-40: Expiration Timestamp
- [x] NIP-111: Relay Information Document Extensions
## Requirements
@@ -86,24 +86,6 @@ Install Docker from their [official guide](https://docs.docker.com/engine/instal
- [Set up a Paid Nostr relay with Nostream and ZBD](https://andreneves.xyz/p/how-to-setup-a-paid-nostr-relay) by [André Neves](https://snort.social/p/npub1rvg76s0gz535txd9ypg2dfqv0x7a80ar6e096j3v343xdxyrt4ksmkxrck) (CTO & Co-Founder at [ZEBEDEE](https://zebedee.io/))
- [Set up a Nostr relay in under 5 minutes](https://andreneves.xyz/p/set-up-a-nostr-relay-server-in-under) by [André Neves](https://twitter.com/andreneves) (CTO & Co-Founder at [ZEBEDEE](https://zebedee.io/))
## Local Quick Start (Docker Compose)
Install Docker Desktop following the [official guide](https://docs.docker.com/desktop/).
You may have to uninstall Docker on your machine if you installed it using a different guide.
Clone repository and enter directory:
```
git clone git@github.com:Cameri/nostream.git
cd nostream
```
Start:
```
./scripts/start_local
```
This will run in the foreground of the terminal until you stop it with Ctrl+C.
## Quick Start (Docker Compose)
Install Docker following the [official guide](https://docs.docker.com/engine/install/).
@@ -184,15 +166,17 @@ Set the following environment variables:
```
DB_URI="postgresql://postgres:postgres@localhost:5432/nostr_ts_relay_test"
DB_USER=postgres
```
or
```
DB_HOST=localhost
DB_PORT=5432
DB_NAME=nostr_ts_relay
DB_USER=postgres
DB_PASSWORD=postgres
```
```
REDIS_URI="redis://default:nostr_ts_relay@localhost:6379"
REDIS_HOST=localhost
@@ -201,6 +185,19 @@ Set the following environment variables:
REDIS_PASSWORD=nostr_ts_relay
```
If enabling payments, generate a long random secret and set SECRET:
You may want to use `openssl rand -hex 128` to generate a secret.
```
SECRET=aaabbbccc...dddeeefff
# Secret shortened for brevity
```
In addition, if using Zebedee for payments, you must also set ZEBEDEE_API_KEY with
an API Key from one of your projects in your Zebedee Developer Dashboard. Contact
@foxp2zeb on Telegram or npub1rvg76s0gz535txd9ypg2dfqv0x7a80ar6e096j3v343xdxyrt4ksmkxrck on Nostr requesting
access to the Zebedee Developer Dashboard.
Create `nostr_ts_relay` database:
```
@@ -261,6 +258,24 @@ To clean up the build, coverage and test reports run:
```
npm run clean
```
## Development Quick Start (Docker Compose)
Install Docker Desktop following the [official guide](https://docs.docker.com/desktop/).
You may have to uninstall Docker on your machine if you installed it using a different guide.
Clone repository and enter directory:
```
git clone git@github.com:Cameri/nostream.git
cd nostream
```
Start:
```
./scripts/start_local
```
This will run in the foreground of the terminal until you stop it with Ctrl+C.
## Tests
### Unit tests
@@ -391,6 +406,7 @@ I'm Cameri on most social networks. You can find me on Nostr by npub1qqqqqqyz0la
- Saransh Sharma
- swissrouting
- André Neves
- Semisol
## License

View File

@@ -3,7 +3,7 @@ services:
build: .
container_name: nostream
environment:
SECRET: changeme
SECRET: ${SECRET}
RELAY_PORT: 8008
# Master
NOSTR_CONFIG_DIR: /home/node/.nostr

View File

@@ -0,0 +1,62 @@
exports.up = function (knex) {
return knex.schema
.raw('DROP FUNCTION confirm_invoice(invoice_id UUID, amount_received BIGINT, confirmation_date TIMESTAMP WITHOUT TIME ZONE)')
.raw('DROP FUNCTION confirm_invoice(invoice_id TEXT, amount_received BIGINT, confirmation_date TIMESTAMP WITHOUT TIME ZONE)')
.raw(`CREATE OR REPLACE FUNCTION confirm_invoice(invoice_id TEXT, amount_received BIGINT, confirmation_date TIMESTAMP WITHOUT TIME ZONE)
RETURNS INTEGER
LANGUAGE plpgsql
AS $$
DECLARE
payee BYTEA;
confirmed_date TIMESTAMP WITHOUT TIME ZONE;
invoice_unit TEXT;
BEGIN
PERFORM ASSERT_SERIALIZED();
SELECT "pubkey", "confirmed_at", "unit" INTO payee, confirmed_date, invoice_unit FROM "invoices" WHERE id = invoice_id;
IF confirmed_date IS NULL THEN
UPDATE invoices
SET
"confirmed_at" = confirmation_date,
"amount_paid" = amount_received,
"updated_at" = now_utc()
WHERE id = invoice_id;
IF invoice_unit = 'sats' THEN
UPDATE users SET balance = balance + amount_received * 1000 WHERE "pubkey" = payee;
ELSIF invoice_unit = 'msats' THEN
UPDATE users SET balance = balance + amount_received WHERE "pubkey" = payee;
ELSIF invoice_unit = 'btc' THEN
UPDATE users SET balance = balance + amount_received * 100000000 * 1000 WHERE "pubkey" = payee;
END IF;
END IF;
RETURN 0;
END;
$$;`)
}
exports.down = function (knex) {
return knex.schema
.raw(`CREATE OR REPLACE FUNCTION confirm_invoice(invoice_id TEXT, amount_received BIGINT, confirmation_date TIMESTAMP WITHOUT TIME ZONE)
RETURNS INTEGER
LANGUAGE plpgsql
AS $$
DECLARE
payee BYTEA;
confirmed_date TIMESTAMP WITHOUT TIME ZONE;
BEGIN
PERFORM ASSERT_SERIALIZED();
SELECT "pubkey", "confirmed_at" INTO payee, confirmed_date FROM "invoices" WHERE id = invoice_id;
IF confirmed_date IS NULL THEN
UPDATE invoices
SET
"confirmed_at" = confirmation_date,
"amount_paid" = amount_received,
"updated_at" = now_utc()
WHERE id = invoice_id;
UPDATE users SET balance = balance + amount_received WHERE "pubkey" = payee;
END IF;
RETURN 0;
END;
$$;`)
}

96
package-lock.json generated
View File

@@ -10,7 +10,7 @@
"license": "MIT",
"dependencies": {
"@noble/secp256k1": "1.7.1",
"axios": "^1.2.6",
"axios": "1.2.6",
"bech32": "2.0.0",
"body-parser": "1.20.1",
"debug": "4.3.4",
@@ -24,7 +24,7 @@
"pg": "8.9.0",
"pg-query-stream": "4.3.0",
"ramda": "0.28.0",
"redis": "4.6.2",
"redis": "4.5.1",
"rxjs": "7.8.0",
"tor-control-ts": "^1.0.0",
"ws": "8.12.0"
@@ -1517,9 +1517,9 @@
}
},
"node_modules/@redis/bloom": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz",
"integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.1.0.tgz",
"integrity": "sha512-9QovlxmpRtvxVbN0UBcv8WfdSMudNZZTFqCsnBszcQXqaZb/TVe30ScgGEO7u1EAIacTPAo7/oCYjYAxiHLanQ==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
@@ -1528,6 +1528,7 @@
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.3.tgz",
"integrity": "sha512-kPad3QmWyRcmFj1gnb+SkzjXBV7oPpyTJmasVA+ocgNClxqZaTJjLFReqxm9cZQiCtqZK9vrcTISNrgzQXFpLg==",
"peer": true,
"dependencies": {
"cluster-key-slot": "1.1.2",
"generic-pool": "3.9.0",
@@ -1554,9 +1555,9 @@
}
},
"node_modules/@redis/search": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.1.tgz",
"integrity": "sha512-pqCXTc5e7wJJgUuJiC3hBgfoFRoPxYzwn0BEfKgejTM7M/9zP3IpUcqcjgfp8hF+LoV8rHZzcNTz7V+pEIY7LQ==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.0.tgz",
"integrity": "sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
@@ -3182,6 +3183,7 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -11209,18 +11211,39 @@
}
},
"node_modules/redis": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/redis/-/redis-4.6.2.tgz",
"integrity": "sha512-Xoh7UyU6YnT458xA8svaZAJu6ZunKeW7Z/7GXrLWGGwhVLTsDX6pr3u7ENAoV+DHBPO+9LwIu45ClwUwpIjAxw==",
"version": "4.5.1",
"resolved": "https://registry.npmjs.org/redis/-/redis-4.5.1.tgz",
"integrity": "sha512-oxXSoIqMJCQVBTfxP6BNTCtDMyh9G6Vi5wjdPdV/sRKkufyZslDqCScSGcOr6XGR/reAWZefz7E4leM31RgdBA==",
"dependencies": {
"@redis/bloom": "1.2.0",
"@redis/client": "1.5.3",
"@redis/bloom": "1.1.0",
"@redis/client": "1.4.2",
"@redis/graph": "1.1.0",
"@redis/json": "1.0.4",
"@redis/search": "1.1.1",
"@redis/search": "1.1.0",
"@redis/time-series": "1.0.4"
}
},
"node_modules/redis/node_modules/@redis/client": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/@redis/client/-/client-1.4.2.tgz",
"integrity": "sha512-oUdEjE0I7JS5AyaAjkD3aOXn9NhO7XKyPyXEyrgFDu++VrVBHUPnV6dgEya9TcMuj5nIJRuCzCm8ZP+c9zCHPw==",
"dependencies": {
"cluster-key-slot": "1.1.1",
"generic-pool": "3.9.0",
"yallist": "4.0.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/redis/node_modules/cluster-key-slot": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz",
"integrity": "sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/reflect-metadata": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
@@ -14389,15 +14412,16 @@
}
},
"@redis/bloom": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz",
"integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.1.0.tgz",
"integrity": "sha512-9QovlxmpRtvxVbN0UBcv8WfdSMudNZZTFqCsnBszcQXqaZb/TVe30ScgGEO7u1EAIacTPAo7/oCYjYAxiHLanQ==",
"requires": {}
},
"@redis/client": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.3.tgz",
"integrity": "sha512-kPad3QmWyRcmFj1gnb+SkzjXBV7oPpyTJmasVA+ocgNClxqZaTJjLFReqxm9cZQiCtqZK9vrcTISNrgzQXFpLg==",
"peer": true,
"requires": {
"cluster-key-slot": "1.1.2",
"generic-pool": "3.9.0",
@@ -14417,9 +14441,9 @@
"requires": {}
},
"@redis/search": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.1.tgz",
"integrity": "sha512-pqCXTc5e7wJJgUuJiC3hBgfoFRoPxYzwn0BEfKgejTM7M/9zP3IpUcqcjgfp8hF+LoV8rHZzcNTz7V+pEIY7LQ==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.0.tgz",
"integrity": "sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ==",
"requires": {}
},
"@redis/time-series": {
@@ -15673,7 +15697,8 @@
"cluster-key-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
"peer": true
},
"color-convert": {
"version": "2.0.1",
@@ -21627,16 +21652,33 @@
}
},
"redis": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/redis/-/redis-4.6.2.tgz",
"integrity": "sha512-Xoh7UyU6YnT458xA8svaZAJu6ZunKeW7Z/7GXrLWGGwhVLTsDX6pr3u7ENAoV+DHBPO+9LwIu45ClwUwpIjAxw==",
"version": "4.5.1",
"resolved": "https://registry.npmjs.org/redis/-/redis-4.5.1.tgz",
"integrity": "sha512-oxXSoIqMJCQVBTfxP6BNTCtDMyh9G6Vi5wjdPdV/sRKkufyZslDqCScSGcOr6XGR/reAWZefz7E4leM31RgdBA==",
"requires": {
"@redis/bloom": "1.2.0",
"@redis/client": "1.5.3",
"@redis/bloom": "1.1.0",
"@redis/client": "1.4.2",
"@redis/graph": "1.1.0",
"@redis/json": "1.0.4",
"@redis/search": "1.1.1",
"@redis/search": "1.1.0",
"@redis/time-series": "1.0.4"
},
"dependencies": {
"@redis/client": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/@redis/client/-/client-1.4.2.tgz",
"integrity": "sha512-oUdEjE0I7JS5AyaAjkD3aOXn9NhO7XKyPyXEyrgFDu++VrVBHUPnV6dgEya9TcMuj5nIJRuCzCm8ZP+c9zCHPw==",
"requires": {
"cluster-key-slot": "1.1.1",
"generic-pool": "3.9.0",
"yallist": "4.0.0"
}
},
"cluster-key-slot": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz",
"integrity": "sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw=="
}
}
},
"reflect-metadata": {

View File

@@ -130,10 +130,10 @@
"pg": "8.9.0",
"pg-query-stream": "4.3.0",
"ramda": "0.28.0",
"redis": "4.6.2",
"redis": "4.5.1",
"rxjs": "7.8.0",
"ws": "8.12.0",
"tor-control-ts": "^1.0.0"
"tor-control-ts": "^1.0.0",
"ws": "8.12.0"
},
"config": {
"commitizen": {

View File

@@ -36,9 +36,9 @@ limits:
invoice:
rateLimits:
- period: 60000
rate: 6
rate: 12
- period: 3600000
rate: 16
rate: 30
ipWhitelist:
- "::1"
- "10.10.10.1"
@@ -49,8 +49,6 @@ limits:
rate: 12
- period: 60000
rate: 48
- period: 3600000
rate: 300
ipWhitelist:
- "::1"
- "10.10.10.1"
@@ -101,14 +99,6 @@ limits:
- 42
period: 60000
rate: 12
- description: 360 events/hour for event kinds 1, 2, 4 and 42
kinds:
- 1
- 2
- 4
- 42
period: 3600000
rate: 360
- description: 30 events/min for event kind ranges 5-7 and 43-49
kinds:
- - 5
@@ -135,9 +125,6 @@ limits:
- description: 720 events/hour for all events
period: 3600000
rate: 720
- description: 2880 events/day for all events
period: 86400000
rate: 2880
whitelists:
pubkeys: []
ipAddresses:
@@ -153,9 +140,6 @@ limits:
- description: 240 raw messages/min
period: 60000
rate: 240
- description: 3600 raw messages/hour
period: 3600000
rate: 4800
ipWhitelist:
- "::1"
- "10.10.10.1"

View File

@@ -108,6 +108,8 @@
var paid = false
var fallbackTimeout
console.log('invoice id', reference)
function getBackoffTime() {
return 5000 + Math.floor(Math.random() * 5000)
}
@@ -125,6 +127,8 @@
hide('pending')
show('expired')
return
} else {
console.log('invoice status', status)
}
paid = true

View File

@@ -5,6 +5,11 @@ PROJECT_ROOT="$(dirname $(readlink -f "${BASH_SOURCE[0]}"))/.."
DOCKER_COMPOSE_FILE="${PROJECT_ROOT}/docker-compose.yml"
DOCKER_COMPOSE_LOCAL_FILE="${PROJECT_ROOT}/docker-compose.local.yml"
if [ "$EUID" -eq 0 ]
then echo "Error: Nostream should not be run as root."
exit 1
fi
if ! type "mkcert" &> /dev/null; then
echo "Could not find mkcert, which is required for generating locally-trusted TLS certificates. Follow the installation instructions at https://github.com/FiloSottile/mkcert, then run this script again."
exit 1

View File

@@ -59,10 +59,13 @@ export class App implements IRunnable {
}
logCentered(`v${packageJson.version}`, width)
logCentered(`NIPs implemented: ${packageJson.supportedNips}`, width)
logCentered(`Pay-to-relay ${pathEq(['payments', 'enabled'], true, settings) ? 'enabled' : 'disabled'}`, width)
logCentered(`Payments provider: ${path(['payments', 'processor'], settings)}`, width)
const paymentsEnabled = pathEq(['payments', 'enabled'], true, settings)
logCentered(`Pay-to-relay ${paymentsEnabled ? 'enabled' : 'disabled'}`, width)
if (paymentsEnabled) {
logCentered(`Payments provider: ${path(['payments', 'processor'], settings)}`, width)
}
if (typeof this.process.env.SECRET !== 'string' || this.process.env.SECRET === 'changeme') {
if (paymentsEnabled && (typeof this.process.env.SECRET !== 'string' || this.process.env.SECRET === '' || this.process.env.SECRET === 'changeme')) {
console.error('Please configure the secret using the SECRET environment variable.')
this.process.exit(1)
}
@@ -82,11 +85,13 @@ export class App implements IRunnable {
WORKER_TYPE: 'worker',
})
}
logCentered(`${workerCount} client workers started`, width)
createWorker({
WORKER_TYPE: 'maintenance',
})
logCentered('1 maintenance worker started', width)
const mirrors = settings?.mirroring?.static
if (Array.isArray(mirrors) && mirrors.length) {
@@ -96,11 +101,9 @@ export class App implements IRunnable {
MIRROR_INDEX: i.toString(),
})
}
logCentered(`${mirrors.length} maintenance worker started`, width)
}
logCentered(`${workerCount} client workers started`, width)
logCentered('1 maintenance worker started', width)
debug('settings: %O', settings)
const host = `${hostname()}:${port}`

View File

@@ -1,7 +1,10 @@
import { Request, Response } from 'express'
import { createLogger } from '../../factories/logger-factory'
import { IController } from '../../@types/controllers'
import { IInvoiceRepository } from '../../@types/repositories'
const debug = createLogger('get-invoice-status-controller')
export class GetInvoiceStatusController implements IController {
public constructor(
private readonly invoiceRepository: IInvoiceRepository,
@@ -12,22 +15,25 @@ export class GetInvoiceStatusController implements IController {
response: Response,
): Promise<void> {
const invoiceId = request.params.invoiceId
if (!invoiceId) {
if (typeof invoiceId !== 'string' || !invoiceId) {
debug('invalid invoice id: %s', invoiceId)
response
.status(400)
.setHeader('content-type', 'text/plain; charset=utf8')
.send('Invalid invoice')
.send({ id: invoiceId, status: 'invalid invoice' })
return
}
try {
const invoice = await this.invoiceRepository.findById(request.params.invoiceId)
debug('fetching invoice: %s', invoiceId)
const invoice = await this.invoiceRepository.findById(invoiceId)
if (!invoice) {
debug('invoice not found: %s', invoiceId)
response
.status(404)
.setHeader('content-type', 'text/plain; charset=utf8')
.send('Invoice not found')
.send({ id: invoiceId, status: 'not found' })
return
}
@@ -44,7 +50,7 @@ export class GetInvoiceStatusController implements IController {
response
.status(500)
.setHeader('content-type', 'text/plain; charset=utf8')
.send('Unable to get invoice status')
.send({ id: invoiceId, status: 'error' })
}
}
}

View File

@@ -10,11 +10,13 @@ import { PaymentsProcessor } from '../payments-processors/payments-procesor'
import { Settings } from '../@types/settings'
import { ZebedeePaymentsProcesor } from '../payments-processors/zebedee-payments-processor'
const debug = createLogger('create-zebedee-payments-processor')
const debug = createLogger('create-payments-processor')
const getZebedeeAxiosConfig = (settings: Settings): CreateAxiosDefaults<any> => {
if (!process.env.ZEBEDEE_API_KEY) {
throw new Error('ZEBEDEE_API_KEY must be set.')
const error = new Error('ZEBEDEE_API_KEY must be set.')
console.error('Unable to get Zebedee config.', error)
throw error
}
return {
@@ -45,14 +47,20 @@ const getLNbitsAxiosConfig = (settings: Settings): CreateAxiosDefaults<any> => {
const createZebedeePaymentsProcessor = (settings: Settings): IPaymentsProcessor => {
const callbackBaseURL = path(['paymentsProcessors', 'zebedee', 'callbackBaseURL'], settings) as string | undefined
if (typeof callbackBaseURL === 'undefined' || callbackBaseURL.indexOf('nostream.your-domain.com') >= 0) {
throw new Error('Unable to create payments processor: Setting paymentsProcessor.zebedee.callbackBaseURL is not configured.')
const error = new Error('Setting paymentsProcessor.zebedee.callbackBaseURL is not configured.')
console.error('Unable to create payments processor.', error)
throw error
}
if (
!Array.isArray(settings.paymentsProcessors?.zebedee?.ipWhitelist)
|| !settings.paymentsProcessors?.zebedee?.ipWhitelist?.length
) {
throw new Error('Unable to create payments processor: Setting paymentsProcessor.zebedee.ipWhitelist is empty.')
const error = new Error('Setting paymentsProcessor.zebedee.ipWhitelist is empty.')
console.error('Unable to create payments processor.', error)
throw error
}
const config = getZebedeeAxiosConfig(settings)
@@ -67,7 +75,10 @@ const createZebedeePaymentsProcessor = (settings: Settings): IPaymentsProcessor
const createLNbitsPaymentProcessor = (settings: Settings): IPaymentsProcessor => {
const callbackBaseURL = path(['paymentsProcessors', 'lnbits', 'callbackBaseURL'], settings) as string | undefined
if (typeof callbackBaseURL === 'undefined' || callbackBaseURL.indexOf('nostream.your-domain.com') >= 0) {
throw new Error('Unable to create payments processor: Setting paymentsProcessor.lnbits.callbackBaseURL is not configured.')
const error = new Error('Setting paymentsProcessor.lnbits.callbackBaseURL is not configured.')
console.error('Unable to create payments processor.', error)
throw error
}
const config = getLNbitsAxiosConfig(settings)
@@ -80,12 +91,12 @@ const createLNbitsPaymentProcessor = (settings: Settings): IPaymentsProcessor =>
}
export const createPaymentsProcessor = (): IPaymentsProcessor => {
debug('create payments processor')
const settings = createSettings()
if (!settings.payments?.enabled) {
return new NullPaymentsProcessor()
}
switch (settings.payments?.processor) {
case 'zebedee':
return createZebedeePaymentsProcessor(settings)

View File

@@ -24,7 +24,7 @@ export const createWebApp = () => {
*/
'img-src': ["'self'", 'data:', 'https://cdn.zebedee.io/an/nostr/'],
'connect-src': ["'self'", settings.info.relay_url as string, webRelayUrl.toString()],
'default-src': ['"self"'],
'default-src': ["'self'"],
'script-src-attr': ["'unsafe-inline'"],
'script-src': ["'self'", "'unsafe-inline'", 'https://cdn.jsdelivr.net/npm/', 'https://unpkg.com/', 'https://cdnjs.cloudflare.com/ajax/libs/'],
'style-src': ["'self'", 'https://cdn.jsdelivr.net/npm/'],

View File

@@ -10,6 +10,7 @@ export const postInvoiceRequestHandler = async (
try {
await controller.handleRequest(req, res)
} catch (error) {
console.error('Unable handle request.', error)
res
.status(500)
.setHeader('content-type', 'text-plain')

View File

@@ -56,7 +56,7 @@ export const rootRequestHandler = (request: Request, response: Response, next: N
}
response
.setHeader('conten-type', 'application/nostr+json')
.setHeader('content-type', 'application/nostr+json')
.setHeader('access-control-allow-origin', '*')
.status(200)
.send(relayInformationDocument)

View File

@@ -1,5 +1,4 @@
import { Router, urlencoded } from 'express'
import { createPaymentsProcessor } from '../../factories/payments-processor-factory'
import { getInvoiceRequestHandler } from '../../handlers/request-handlers/get-invoice-request-handler'
import { getInvoiceStatusRequestHandler } from '../../handlers/request-handlers/get-invoice-status-request-handler'
@@ -8,10 +7,6 @@ import { postInvoiceRequestHandler } from '../../handlers/request-handlers/post-
const invoiceRouter = Router()
invoiceRouter
.use((req, _res, next) => {
req['paymentsProcessor'] = createPaymentsProcessor()
next()
})
.get('/', getInvoiceRequestHandler)
.get('/:invoiceId/status', getInvoiceStatusRequestHandler)
.post('/', urlencoded({ extended: true }), postInvoiceRequestHandler)