This repository has been archived on 2022-11-26. You can view files and clone it, but cannot push or open issues or pull requests.
teemant-old/teemant.js

233 lines
6.4 KiB
JavaScript
Executable File

#!/usr/bin/env node
'use strict'
import express from 'express'
import path from 'path'
import sockio from 'socket.io'
import dns from 'dns'
import pkginfo from './package.json'
import irclib from './server/irc'
import webirc from './server/webirc'
import config from './server/config'
import logger from './server/logger'
const app = express()
const router = express.Router()
const pubdir = path.join(__dirname, 'build')
const port = config.server.port || 8080
const cacheAge = 365 * 24 * 60 * 60 * 1000
let runtimeStats = {
connectionsMade: 0
}
let connections = {}
let customCTCPs = {
VERSION: function (data, connection) {
return `TeemantIRC ver. ${pkginfo.version} - ${pkginfo.description} - https://teemant.icynet.eu/`
},
SOURCE: function (data, connection) {
return 'https://gitlab.icynet.eu/IcyNetwork/teemant'
}
}
process.stdin.resume()
router.get('/', function (req, res) {
res.sendFile(path.join(pubdir, '/document/index.html'))
})
router.get('/:server?*', function (req, res) {
res.sendFile(path.join(pubdir, '/document/index.html'))
})
app.use('/', express.static(pubdir, { maxAge: cacheAge }))
app.use('/', express.static(path.join(pubdir, 'icons'), { maxAge: cacheAge }))
app.use('/', express.static(path.join(__dirname, 'static'), { maxAge: cacheAge }))
app.use('/:server', express.static(pubdir, { maxAge: cacheAge }))
app.use('/:server', express.static(path.join(pubdir, 'icons'), { maxAge: cacheAge }))
app.use('/:server', express.static(path.join(pubdir, 'static'), { maxAge: cacheAge }))
app.use('/', router)
const io = sockio.listen(app.listen(port, function () {
logger.log(`*** Listening on http://localhost:${port}/`)
setInterval(() => {
logger.printRuntimeStats(runtimeStats, connections)
}, 3600000)
}))
function resolveHostname (ipaddr) {
return new Promise(function (resolve, reject) {
dns.reverse(ipaddr, function (err, hostnames) {
if (err != null) return reject(err)
resolve(hostnames)
})
})
}
io.sockets.on('connection', function (socket) {
let userip = socket.handshake.headers['x-real-ip'] || socket.handshake.headers['x-forwarded-for'] ||
socket.request.connection._peername.address || '127.0.0.1'
if (userip.indexOf('::ffff:') === 0) {
userip = userip.substring(7)
}
logger.debugLog(`clientID: ${socket.id} from: ${userip}`)
socket.emit('defaults', {
server: config.client.default_server,
port: config.client.default_port,
ssl: config.client.secure_by_default
})
// New object for connections
connections[socket.id] = {
host: {
ipaddr: userip,
hostname: userip
}
}
// Get the hostname of the connecting user
let hostQuery = resolveHostname(userip)
hostQuery.then((arr) => {
if (arr.length > 0) {
connections[socket.id].host.hostname = arr[0]
}
logger.debugLog(`Hostname of ${socket.id} was determined to be ${connections[socket.id].host.hostname}`)
}).catch((err) => {
logger.debugLog(`Host resolve for ${socket.id} failed:`, err.message)
})
socket.on('disconnect', function () {
for (let d in connections[socket.id]) {
if (connections[socket.id][d].ipaddr) continue
if (connections[socket.id][d].connected === true) {
connections[socket.id][d].disconnect()
}
}
delete connections[socket.id]
logger.debugLog('clientID: {0} disconnect'.format(socket.id))
})
socket.on('error', (e) => {
logger.errorLog(e, 'Socket error')
})
socket.on('userinput', (data) => {
let serv = connections[socket.id][data.server]
if (!serv) return
if (serv.authenticated === false) return
logger.debugLog(`[${socket.id}] ->`, data)
serv.handler.handleUserLine(data)
})
socket.on('irc_create', function (connectiondata) {
logger.debugLog(`${socket.id} created irc connection: `, connectiondata)
socket.emit('act_client', { type: 'connect_message', message: 'Connecting to server..', error: false })
if (connectiondata.port === null || connectiondata.server === null) {
return socket.emit('act_client', {
type: 'connect_message',
server: connectiondata.server,
message: 'Failed to connect to the server!',
error: true
})
}
let newConnection = new irclib.IRCConnection(connectiondata, config.client,
{
authenticationSteps: [
new webirc.Authenticator(connections[socket.id].host)
],
ctcps: customCTCPs
})
newConnection.connect()
connections[socket.id][connectiondata.server] = newConnection
newConnection.on('authenticated', () => {
socket.emit('act_client', {
type: 'event_connect',
address: connectiondata.server,
network: newConnection.data.network,
supportedModes: newConnection.data.supportedModes,
nickname: newConnection.config.nickname,
max_channel_length: newConnection.data.max_channel_length
})
runtimeStats.connectionsMade += 1
})
if (config.server.debug) {
newConnection.on('line', function (line) {
logger.debugLog(`[${socket.id}] <-`, line)
})
newConnection.on('debug_log', function (data) {
logger.debugLog(`[${socket.id}] <-`, data)
})
}
newConnection.on('connerror', (data) => {
logger.debugLog(data)
if (newConnection.authenticated === false) {
socket.emit('act_client', {
type: 'connect_message',
server: connectiondata.server,
message: 'Failed to connect to the server!',
error: true
})
}
})
newConnection.on('pass_to_client', (data) => {
socket.emit('act_client', data)
})
newConnection.on('closed', (data) => {
logger.debugLog(data)
if (newConnection.authenticated === false) {
socket.emit('act_client', {
type: 'connect_message',
server: connectiondata.server,
message: 'Failed to connect to the server!',
error: true
})
} else {
socket.emit('act_client', {
type: 'event_server_quit',
server: connectiondata.server
})
}
})
})
})
process.on('SIGINT', () => {
logger.log('!!! Received SIGINT; Terminating all IRC connections and exiting.. !!!')
logger.printRuntimeStats(runtimeStats, connections)
for (let c in connections) {
for (let ircconn in connections[c]) {
if (connections[c][ircconn].ipaddr) continue
connections[c][ircconn].disconnect()
}
}
process.exit(0)
})