mirror of
https://github.com/Cameri/nostream.git
synced 2025-03-17 21:31:48 +01:00
feat: automatic onion services
This commit is contained in:
parent
7d9ef0e216
commit
3731d03230
@ -1,6 +1,7 @@
|
||||
FROM node:18-alpine3.16 as build
|
||||
|
||||
WORKDIR /build
|
||||
RUN apk add --no-cache --update git
|
||||
|
||||
COPY ["package.json", "package-lock.json", "./"]
|
||||
|
||||
@ -26,6 +27,8 @@ ENV DB_USER=nostr-ts-relay
|
||||
ENV DB_PASSWORD=nostr-ts-relay
|
||||
|
||||
WORKDIR /app
|
||||
RUN apk add --no-cache --update git
|
||||
RUN mkdir /app/.nostr && chown 1000:1000 /app/.nostr
|
||||
|
||||
COPY --from=build /build/dist .
|
||||
|
||||
|
@ -16,6 +16,10 @@ services:
|
||||
REDIS_PORT: 6379
|
||||
REDIS_USER: default
|
||||
REDIS_PASSWORD: nostr_ts_relay
|
||||
TOR_HOST: tor_proxy
|
||||
TOR_CONTROL_PORT: 9051
|
||||
TOR_PASSWORD: nostr_ts_relay
|
||||
HIDDEN_SERVICE_PORT: 80
|
||||
# Enable DEBUG for troubleshooting. Examples:
|
||||
# DEBUG: "worker:*"
|
||||
# DEBUG: "knex:query"
|
||||
@ -31,13 +35,14 @@ services:
|
||||
condition: service_healthy
|
||||
migrations:
|
||||
condition: service_completed_successfully
|
||||
tor_proxy:
|
||||
condition: service_healthy
|
||||
restart: on-failure
|
||||
networks:
|
||||
default:
|
||||
ipv4_address: 10.10.10.2
|
||||
db:
|
||||
image: postgres
|
||||
container_name: db
|
||||
environment:
|
||||
POSTGRES_DB: nostr_ts_relay
|
||||
POSTGRES_USER: nostr_ts_relay
|
||||
@ -62,7 +67,6 @@ services:
|
||||
start_period: 360s
|
||||
cache:
|
||||
image: redis:7.0.5-alpine3.16
|
||||
container_name: cache
|
||||
volumes:
|
||||
- cache:/data
|
||||
command: redis-server --save 20 1 --loglevel warning --requirepass nostr_ts_relay
|
||||
@ -77,7 +81,6 @@ services:
|
||||
retries: 5
|
||||
migrations:
|
||||
image: node:18-alpine3.16
|
||||
container_name: migrations
|
||||
environment:
|
||||
DB_HOST: db
|
||||
DB_PORT: 5432
|
||||
@ -97,7 +100,19 @@ services:
|
||||
networks:
|
||||
default:
|
||||
ipv4_address: 10.10.10.254
|
||||
|
||||
tor_proxy:
|
||||
image: dperson/torproxy
|
||||
restart: on-failure
|
||||
environment:
|
||||
PASSWORD: nostr_ts_relay
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
networks:
|
||||
default:
|
||||
ipv4_address: 10.10.10.5
|
||||
networks:
|
||||
default:
|
||||
name: nostr-ts-relay
|
||||
|
11
package-lock.json
generated
11
package-lock.json
generated
@ -18,6 +18,7 @@
|
||||
"pg-query-stream": "4.2.4",
|
||||
"ramda": "0.28.0",
|
||||
"redis": "4.5.1",
|
||||
"tor-control-ts": "^1.0.0",
|
||||
"ws": "8.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -11806,6 +11807,11 @@
|
||||
"integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tor-control-ts": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tor-control-ts/-/tor-control-ts-1.0.0.tgz",
|
||||
"integrity": "sha512-uV+swAIQuH0QP+SJcQwlj2xrv0XqKa9V1HQOkU+NONR7/8+JM/4uIxzDJDsVtiK6cNq+x5Nt6deh3nx16XK1Yg=="
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
@ -21408,6 +21414,11 @@
|
||||
"integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==",
|
||||
"dev": true
|
||||
},
|
||||
"tor-control-ts": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tor-control-ts/-/tor-control-ts-1.0.0.tgz",
|
||||
"integrity": "sha512-uV+swAIQuH0QP+SJcQwlj2xrv0XqKa9V1HQOkU+NONR7/8+JM/4uIxzDJDsVtiK6cNq+x5Nt6deh3nx16XK1Yg=="
|
||||
},
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
|
@ -117,6 +117,7 @@
|
||||
"pg-query-stream": "4.2.4",
|
||||
"ramda": "0.28.0",
|
||||
"redis": "4.5.1",
|
||||
"tor-control-ts": "^1.0.0",
|
||||
"ws": "8.11.0"
|
||||
},
|
||||
"config": {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Cluster, Worker } from 'cluster'
|
||||
import { cpus } from 'os'
|
||||
import { cpus, hostname } from 'os'
|
||||
|
||||
import { addOnion } from '../tor/client'
|
||||
import { createLogger } from '../factories/logger-factory'
|
||||
import { IRunnable } from '../@types/base'
|
||||
import { ISettings } from '../@types/settings'
|
||||
@ -39,6 +40,9 @@ export class App implements IRunnable {
|
||||
░ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░░ ░ ░ ░ ▒ ░ ░
|
||||
░ ░ ░ ░ ░ ░ ░ ░ ░ ░`)
|
||||
const width = 74
|
||||
const torHiddenServicePort = process.env.HIDDEN_SERVICE_PORT ? Number(process.env.HIDDEN_SERVICE_PORT) : 80
|
||||
const port = process.env.RELAY_PORT ? Number(process.env.RELAY_PORT) : 8008
|
||||
|
||||
const logCentered = (input: string, width: number) => {
|
||||
const start = (width >> 1) - (input.length >> 1)
|
||||
console.log(' '.repeat(start), input)
|
||||
@ -58,6 +62,13 @@ export class App implements IRunnable {
|
||||
logCentered(`${workerCount} workers started`, width)
|
||||
|
||||
debug('settings: %O', this.settingsFactory())
|
||||
|
||||
const host = `${hostname()}:${port}}`
|
||||
addOnion(torHiddenServicePort, host).then(value=>{
|
||||
debug('tor hidden service address: %s:%d', value, torHiddenServicePort)
|
||||
}, (error) => {
|
||||
console.error('Unable to add Tor hidden service. Skipping.', error)
|
||||
})
|
||||
}
|
||||
|
||||
private onClusterMessage(source: Worker, message: Serializable) {
|
||||
|
83
src/tor/client.ts
Normal file
83
src/tor/client.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import {Tor} from "tor-control-ts"
|
||||
import { createLogger } from '../factories/logger-factory'
|
||||
import {readFile,writeFile} from 'fs/promises';
|
||||
import { homedir } from "os";
|
||||
import { join } from "path";
|
||||
|
||||
|
||||
interface torParams{
|
||||
host:string;
|
||||
port:number;
|
||||
password:string;
|
||||
}
|
||||
|
||||
const debug = createLogger('tor-client')
|
||||
|
||||
const getPrivKeyFile = ()=>{
|
||||
return join(process.env.NOSTR_CONFIG_DIR ?? join(homedir(), '.nostr'),"v3_onion_private_key");
|
||||
}
|
||||
|
||||
const createTorConfig = ():torParams => {
|
||||
return {
|
||||
host:process.env.TOR_HOST,
|
||||
port:Number(process.env.TOR_CONTROL_PORT),
|
||||
password:process.env.TOR_PASSWORD
|
||||
};
|
||||
}
|
||||
|
||||
let client:any = null;
|
||||
|
||||
export const getTorClient = async () => {
|
||||
if (!client) {
|
||||
const config = createTorConfig();
|
||||
debug('config: %o', config);
|
||||
//client = knex(config)
|
||||
if(config.port){
|
||||
debug('connecting');
|
||||
client = new Tor(config);
|
||||
await client.connect();
|
||||
debug('connected to tor');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return client
|
||||
}
|
||||
export const addOnion = async (port:number,host?:string):Promise<string>=>{
|
||||
let privateKey = null;
|
||||
|
||||
try {
|
||||
|
||||
let data = await readFile(getPrivKeyFile(),{
|
||||
encoding:"utf-8"
|
||||
});
|
||||
if(data && data.length){
|
||||
privateKey = data;
|
||||
}
|
||||
debug('privateKey: %o', privateKey);
|
||||
} catch (error) {
|
||||
debug('addOnion catch: %o', error);
|
||||
}
|
||||
|
||||
try {
|
||||
await getTorClient();
|
||||
if(client){
|
||||
let hs = await client.addOnion(port,host,privateKey);
|
||||
if(hs && hs.PrivateKey){
|
||||
await writeFile(getPrivKeyFile(),hs.PrivateKey,{
|
||||
encoding:"utf-8"
|
||||
});
|
||||
}
|
||||
|
||||
debug('hs: %o', hs);
|
||||
debug('hidden service: ', hs.ServiceID+":"+port);
|
||||
return hs.ServiceID;
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
debug('addOnion catch: %o', error);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user