233 lines
6.4 KiB
JavaScript
Executable File
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)
|
|
})
|