mirror of
https://github.com/glenndehaan/unifi-voucher-site.git
synced 2026-03-31 06:24:02 -04:00
621 lines
22 KiB
JavaScript
621 lines
22 KiB
JavaScript
/**
|
|
* Import base packages
|
|
*/
|
|
const fs = require('fs');
|
|
const os = require('os');
|
|
const express = require('express');
|
|
const multer = require('multer');
|
|
const cookieParser = require('cookie-parser');
|
|
const PDFDocument = require('pdfkit');
|
|
|
|
/**
|
|
* Import own modules
|
|
*/
|
|
const config = require('./modules/config');
|
|
const log = require('./modules/log');
|
|
const cache = require('./modules/cache');
|
|
const jwt = require('./modules/jwt');
|
|
const logo = require('./utils/logo');
|
|
const types = require('./utils/types');
|
|
const time = require('./utils/time');
|
|
const bytes = require('./utils/bytes');
|
|
const unifi = require('./modules/unifi');
|
|
const mail = require('./modules/mail');
|
|
const oidc = require('./modules/oidc');
|
|
|
|
/**
|
|
* Import own middlewares
|
|
*/
|
|
const authorization = require('./middlewares/authorization');
|
|
const flashMessage = require('./middlewares/flashMessage');
|
|
|
|
/**
|
|
* Import own utils
|
|
*/
|
|
const {updateCache} = require('./utils/cache');
|
|
|
|
/**
|
|
* Setup Express app
|
|
*/
|
|
const app = express();
|
|
|
|
/**
|
|
* Define global variables
|
|
*/
|
|
const voucherTypes = types(config('voucher_types') || process.env.VOUCHER_TYPES || '480,1,,,;');
|
|
const voucherCustom = config('voucher_custom') !== null ? config('voucher_custom') : process.env.VOUCHER_CUSTOM ? process.env.VOUCHER_CUSTOM !== 'false' : true;
|
|
const webService = process.env.SERVICE_WEB ? process.env.SERVICE_WEB !== 'false' : true;
|
|
const apiService = config('service_api') || (process.env.SERVICE_API === 'true') || false;
|
|
const authDisabled = (process.env.AUTH_DISABLE === 'true') || false;
|
|
const printerType = config('printer_type') || process.env.PRINTER_TYPE || '';
|
|
const smtpFrom = config('smtp_from') || process.env.SMTP_FROM || '';
|
|
const smtpHost = config('smtp_host') || process.env.SMTP_HOST || '';
|
|
const smtpPort = config('smtp_port') || process.env.SMTP_PORT || 25;
|
|
const oidcIssuerBaseUrl = process.env.AUTH_OIDC_ISSUER_BASE_URL || '';
|
|
const oidcAppBaseUrl = process.env.AUTH_OIDC_APP_BASE_URL || '';
|
|
const oidcClientId = process.env.AUTH_OIDC_CLIENT_ID || '';
|
|
|
|
/**
|
|
* Output logo
|
|
*/
|
|
logo();
|
|
|
|
/**
|
|
* Output build version
|
|
*/
|
|
if(fs.existsSync('/etc/unifi_voucher_site_build')) {
|
|
log.info(`[Version] ${fs.readFileSync('/etc/unifi_voucher_site_build', 'utf-8')}`);
|
|
} else {
|
|
log.info(`[Version] **DEVELOPMENT**`);
|
|
}
|
|
|
|
/**
|
|
* Log external config
|
|
*/
|
|
if (fs.existsSync('/data/options.json')) {
|
|
log.info('[Options] Found at /data/options.json');
|
|
}
|
|
if (fs.existsSync(`${__dirname}/.options.json`)) {
|
|
log.info(`[Options] Found at ${__dirname}/.options.json`);
|
|
}
|
|
|
|
/**
|
|
* Log service status
|
|
*/
|
|
log.info(`[Service][Web] ${webService ? 'Enabled!' : 'Disabled!'}`);
|
|
log.info(`[Service][Api] ${apiService ? 'Enabled!' : 'Disabled!'}`);
|
|
|
|
/**
|
|
* Log voucher types
|
|
*/
|
|
log.info('[Voucher] Loaded the following types:');
|
|
voucherTypes.forEach((type, key) => {
|
|
log.info(`[Voucher][Type][${key}] ${time(type.expiration)}, ${type.usage === '1' ? 'single-use' : 'multi-use'}${typeof type.upload === "undefined" && typeof type.download === "undefined" && typeof type.megabytes === "undefined" ? ', no limits' : `${typeof type.upload !== "undefined" ? `, upload bandwidth limit: ${type.upload} kb/s` : ''}${typeof type.download !== "undefined" ? `, download bandwidth limit: ${type.download} kb/s` : ''}${typeof type.megabytes !== "undefined" ? `, quota limit: ${type.megabytes} mb` : ''}`}`);
|
|
});
|
|
log.info(`[Voucher][Custom] ${voucherCustom ? 'Enabled!' : 'Disabled!'}`);
|
|
|
|
/**
|
|
* Log auth status
|
|
*/
|
|
log.info(`[Auth] ${authDisabled ? 'Disabled!' : 'Enabled!'}`);
|
|
|
|
/**
|
|
* Log printer status
|
|
*/
|
|
log.info(`[Printer] ${printerType !== '' ? `Enabled! Type: ${printerType}` : 'Disabled!'}`);
|
|
|
|
/**
|
|
* Log email status
|
|
*/
|
|
if(smtpFrom !== '' && smtpHost !== '' && smtpPort !== '') {
|
|
log.info(`[Email] Enabled! SMTP Server: ${smtpHost}:${smtpPort}`);
|
|
} else {
|
|
log.info(`[Email] Disabled!`);
|
|
}
|
|
|
|
/**
|
|
* Initialize JWT
|
|
*/
|
|
if(!authDisabled && (oidcIssuerBaseUrl === '' && oidcAppBaseUrl === '' && oidcClientId === '')) {
|
|
jwt.init();
|
|
}
|
|
|
|
/**
|
|
* Log controller
|
|
*/
|
|
log.info(`[UniFi] Using Controller on: ${config('unifi_ip') || process.env.UNIFI_IP || '192.168.1.1'}:${config('unifi_port') || process.env.UNIFI_PORT || 443} (Site ID: ${config('unifi_site_id') || process.env.UNIFI_SITE_ID || 'default'})`);
|
|
|
|
/**
|
|
* Trust proxy
|
|
*/
|
|
app.enable('trust proxy');
|
|
|
|
/**
|
|
* Set template engine
|
|
*/
|
|
app.set('view engine', 'ejs');
|
|
app.set('views', `${__dirname}/template`);
|
|
|
|
/**
|
|
* GET /_health - Health check page
|
|
*/
|
|
app.get('/_health', (req, res) => {
|
|
res.json({
|
|
status: 'UP',
|
|
host: os.hostname(),
|
|
load: process.cpuUsage(),
|
|
mem: process.memoryUsage(),
|
|
uptime: process.uptime()
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Initialize OIDC
|
|
*/
|
|
if(!authDisabled && (oidcIssuerBaseUrl !== '' && oidcAppBaseUrl !== '' && oidcClientId !== '')) {
|
|
oidc.init(app);
|
|
}
|
|
|
|
/**
|
|
* Enable multer
|
|
*/
|
|
app.use(multer().none());
|
|
|
|
/**
|
|
* Enable cookie-parser
|
|
*/
|
|
app.use(cookieParser());
|
|
|
|
/**
|
|
* Enable flash-message
|
|
*/
|
|
app.use(flashMessage);
|
|
|
|
/**
|
|
* Request logger
|
|
*/
|
|
app.use((req, res, next) => {
|
|
log.info(`[Web]: ${req.originalUrl}`);
|
|
next();
|
|
});
|
|
|
|
/**
|
|
* Serve static public dir
|
|
*/
|
|
app.use(express.static(`${__dirname}/public`));
|
|
|
|
/**
|
|
* Configure routers
|
|
*/
|
|
app.get('/', (req, res) => {
|
|
if(webService) {
|
|
res.redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`);
|
|
} else {
|
|
res.status(501).send();
|
|
}
|
|
});
|
|
|
|
// Check if web service is enabled
|
|
if(webService) {
|
|
if(oidcIssuerBaseUrl === '' && oidcAppBaseUrl === '' && oidcClientId === '') {
|
|
app.get('/login', (req, res) => {
|
|
// Check if authentication is disabled
|
|
if (authDisabled) {
|
|
res.redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`);
|
|
return;
|
|
}
|
|
|
|
const hour = new Date().getHours();
|
|
const timeHeader = hour < 12 ? 'Good Morning' : hour < 18 ? 'Good Afternoon' : 'Good Evening';
|
|
|
|
res.render('login', {
|
|
baseUrl: req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : '',
|
|
error: req.flashMessage.type === 'error',
|
|
error_text: req.flashMessage.message || '',
|
|
app_header: timeHeader
|
|
});
|
|
});
|
|
app.post('/login', async (req, res) => {
|
|
if (typeof req.body === "undefined") {
|
|
res.status(400).send();
|
|
return;
|
|
}
|
|
|
|
const passwordCheck = req.body.password === (process.env.AUTH_PASSWORD || "0000");
|
|
|
|
if (!passwordCheck) {
|
|
res.cookie('flashMessage', JSON.stringify({type: 'error', message: 'Password Invalid!'}), {httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000)}).redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/login`);
|
|
return;
|
|
}
|
|
|
|
res.cookie('authorization', jwt.sign(), {httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000)}).redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`);
|
|
});
|
|
}
|
|
app.post('/voucher', [authorization.web], async (req, res) => {
|
|
if (typeof req.body === "undefined") {
|
|
res.status(400).send();
|
|
return;
|
|
}
|
|
|
|
if(req.body['voucher-type'] !== 'custom') {
|
|
const typeCheck = (config('voucher_types') || process.env.VOUCHER_TYPES || '480,1,,,;').split(';').includes(req.body['voucher-type']);
|
|
|
|
if (!typeCheck) {
|
|
res.cookie('flashMessage', JSON.stringify({type: 'error', message: 'Unknown Type!'}), {httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000)}).redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Create voucher code
|
|
const voucherCode = await unifi.create(types(req.body['voucher-type'] === 'custom' ? `${req.body['voucher-duration']},${req.body['voucher-usage']},${req.body['voucher-upload-limit']},${req.body['voucher-download-limit']},${req.body['voucher-data-limit']};` : req.body['voucher-type'], true), parseInt(req.body['voucher-amount'])).catch((e) => {
|
|
res.cookie('flashMessage', JSON.stringify({type: 'error', message: e}), {httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000)}).redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`);
|
|
});
|
|
|
|
if(voucherCode) {
|
|
log.info('[Cache] Requesting UniFi Vouchers...');
|
|
|
|
const vouchers = await unifi.list().catch((e) => {
|
|
log.error('[Cache] Error requesting vouchers!');
|
|
res.cookie('flashMessage', JSON.stringify({type: 'error', message: e}), {httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000)}).redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`);
|
|
});
|
|
|
|
if(vouchers) {
|
|
cache.vouchers = vouchers;
|
|
cache.updated = new Date().getTime();
|
|
log.info(`[Cache] Saved ${vouchers.length} voucher(s)`);
|
|
|
|
res.cookie('flashMessage', JSON.stringify({type: 'info', message: parseInt(req.body['voucher-amount']) > 1 ? `${req.body['voucher-amount']} Vouchers Created!` : `Voucher Created: ${voucherCode}`}), {httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000)}).redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`);
|
|
}
|
|
}
|
|
});
|
|
app.get('/voucher/:id/remove', [authorization.web], async (req, res) => {
|
|
// Revoke voucher code
|
|
const response = await unifi.remove(req.params.id).catch((e) => {
|
|
res.cookie('flashMessage', JSON.stringify({type: 'error', message: e}), {httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000)}).redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`);
|
|
});
|
|
|
|
if(response) {
|
|
log.info('[Cache] Requesting UniFi Vouchers...');
|
|
|
|
const vouchers = await unifi.list().catch((e) => {
|
|
log.error('[Cache] Error requesting vouchers!');
|
|
res.cookie('flashMessage', JSON.stringify({type: 'error', message: e}), {httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000)}).redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`);
|
|
});
|
|
|
|
if(vouchers) {
|
|
cache.vouchers = vouchers;
|
|
cache.updated = new Date().getTime();
|
|
log.info(`[Cache] Saved ${vouchers.length} voucher(s)`);
|
|
|
|
res.cookie('flashMessage', JSON.stringify({type: 'info', message: `Voucher Removed!`}), {httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000)}).redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`);
|
|
}
|
|
}
|
|
});
|
|
app.get('/voucher/:id/print', [authorization.web], async (req, res) => {
|
|
const voucher = cache.vouchers.find((e) => {
|
|
return e._id === req.params.id;
|
|
});
|
|
|
|
if(voucher) {
|
|
const doc = new PDFDocument({
|
|
bufferPages: true,
|
|
size: [226.77165354330398, 290],
|
|
margins : {
|
|
top: 20,
|
|
bottom: 20,
|
|
left: 20,
|
|
right: 20
|
|
}
|
|
});
|
|
|
|
const buffers = [];
|
|
doc.on('data', buffers.push.bind(buffers));
|
|
doc.on('end', () => {
|
|
let pdfData = Buffer.concat(buffers);
|
|
res.writeHead(200, {
|
|
'Content-Length': Buffer.byteLength(pdfData),
|
|
'Content-Type': 'application/pdf',
|
|
'Content-Disposition': `attachment;filename=voucher_${req.params.id}.pdf`
|
|
}).end(pdfData);
|
|
});
|
|
|
|
doc.image('public/images/logo_grayscale.png', 75, 15, {fit: [75, 75], align: 'center', valign: 'center'});
|
|
|
|
doc.moveDown(6);
|
|
|
|
doc.font('Helvetica-Bold')
|
|
.fontSize(20)
|
|
.text(`WiFi Voucher Code`, {
|
|
align: 'center'
|
|
});
|
|
doc.font('Helvetica-Bold')
|
|
.fontSize(15)
|
|
.text(`${voucher.code.slice(0, 5)}-${voucher.code.slice(5)}`, {
|
|
align: 'center'
|
|
});
|
|
|
|
doc.moveDown(2);
|
|
|
|
doc.font('Helvetica-Bold')
|
|
.fontSize(12)
|
|
.text(`Voucher Details`);
|
|
|
|
doc.font('Helvetica-Bold')
|
|
.fontSize(10)
|
|
.text(`--------------------------------------------------------`);
|
|
|
|
doc.font('Helvetica-Bold')
|
|
.fontSize(10)
|
|
.text(`Type: `, {
|
|
continued: true
|
|
});
|
|
doc.font('Helvetica')
|
|
.fontSize(10)
|
|
.text(voucher.quota === 0 ? 'Multi-use' : 'Single-use');
|
|
|
|
doc.font('Helvetica-Bold')
|
|
.fontSize(10)
|
|
.text(`Duration: `, {
|
|
continued: true
|
|
});
|
|
doc.font('Helvetica')
|
|
.fontSize(10)
|
|
.text(time(voucher.duration));
|
|
|
|
if(voucher.qos_usage_quota) {
|
|
doc.font('Helvetica-Bold')
|
|
.fontSize(10)
|
|
.text(`Data Limit: `, {
|
|
continued: true
|
|
});
|
|
doc.font('Helvetica')
|
|
.fontSize(10)
|
|
.text(`${bytes(voucher.qos_usage_quota, 2)}`);
|
|
}
|
|
|
|
if(voucher.qos_rate_max_down) {
|
|
doc.font('Helvetica-Bold')
|
|
.fontSize(10)
|
|
.text(`Download Limit: `, {
|
|
continued: true
|
|
});
|
|
doc.font('Helvetica')
|
|
.fontSize(10)
|
|
.text(`${bytes(voucher.qos_rate_max_down, 1, true)}`);
|
|
}
|
|
|
|
if(voucher.qos_rate_max_up) {
|
|
doc.font('Helvetica-Bold')
|
|
.fontSize(10)
|
|
.text(`Upload Limit: `, {
|
|
continued: true
|
|
});
|
|
doc.font('Helvetica')
|
|
.fontSize(10)
|
|
.text(`${bytes(voucher.qos_rate_max_up, 1, true)}`);
|
|
}
|
|
|
|
doc.end();
|
|
} else {
|
|
res.status(404);
|
|
res.render('404', {
|
|
baseUrl: req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''
|
|
});
|
|
}
|
|
});
|
|
app.get('/voucher/:id/email', [authorization.web], async (req, res) => {
|
|
const voucher = cache.vouchers.find((e) => {
|
|
return e._id === req.params.id;
|
|
});
|
|
|
|
if(voucher) {
|
|
res.render('components/email', {
|
|
baseUrl: req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : '',
|
|
timeConvert: time,
|
|
bytesConvert: bytes,
|
|
voucher,
|
|
updated: cache.updated
|
|
});
|
|
} else {
|
|
res.status(404);
|
|
res.render('404', {
|
|
baseUrl: req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''
|
|
});
|
|
}
|
|
});
|
|
app.post('/voucher/:id/email', [authorization.web], async (req, res) => {
|
|
if (typeof req.body === "undefined") {
|
|
res.status(400).send();
|
|
return;
|
|
}
|
|
|
|
const voucher = cache.vouchers.find((e) => {
|
|
return e._id === req.params.id;
|
|
});
|
|
|
|
if(voucher) {
|
|
await mail.send(req.body.email, voucher);
|
|
res.cookie('flashMessage', JSON.stringify({type: 'info', message: 'Email has been send!'}), {httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000)}).redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`);
|
|
} else {
|
|
res.status(404);
|
|
res.render('404', {
|
|
baseUrl: req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''
|
|
});
|
|
}
|
|
});
|
|
app.get('/vouchers', [authorization.web], async (req, res) => {
|
|
if(req.query.refresh) {
|
|
log.info('[Cache] Requesting UniFi Vouchers...');
|
|
|
|
const vouchers = await unifi.list().catch((e) => {
|
|
log.error('[Cache] Error requesting vouchers!');
|
|
res.cookie('flashMessage', JSON.stringify({type: 'error', message: e}), {httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000)}).redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`);
|
|
});
|
|
|
|
log.info('[Cache] Requesting UniFi Guests...');
|
|
|
|
const guests = await unifi.guests().catch((e) => {
|
|
log.error('[Cache] Error requesting guests!');
|
|
res.cookie('flashMessage', JSON.stringify({type: 'error', message: e}), {httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000)}).redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`);
|
|
});
|
|
|
|
if(vouchers && guests) {
|
|
cache.vouchers = vouchers;
|
|
cache.guests = guests;
|
|
cache.updated = new Date().getTime();
|
|
log.info(`[Cache] Saved ${vouchers.length} voucher(s)`);
|
|
log.info(`[Cache] Saved ${guests.length} guest(s)`);
|
|
|
|
res.cookie('flashMessage', JSON.stringify({type: 'info', message: 'Synced Vouchers & Guests!'}), {httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000)}).redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
res.render('voucher', {
|
|
baseUrl: req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : '',
|
|
info: req.flashMessage.type === 'info',
|
|
info_text: req.flashMessage.message || '',
|
|
error: req.flashMessage.type === 'error',
|
|
error_text: req.flashMessage.message || '',
|
|
timeConvert: time,
|
|
bytesConvert: bytes,
|
|
email_enabled: smtpFrom !== '' && smtpHost !== '' && smtpPort !== '',
|
|
printer_enabled: printerType !== '',
|
|
voucher_types: voucherTypes,
|
|
voucher_custom: voucherCustom,
|
|
vouchers: cache.vouchers,
|
|
updated: cache.updated
|
|
});
|
|
});
|
|
app.get('/voucher/:id', [authorization.web], async (req, res) => {
|
|
const voucher = cache.vouchers.find((e) => {
|
|
return e._id === req.params.id;
|
|
});
|
|
const guests = cache.guests.filter((e) => {
|
|
return e.voucher_id === req.params.id;
|
|
});
|
|
|
|
if(voucher) {
|
|
res.render('components/details', {
|
|
baseUrl: req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : '',
|
|
timeConvert: time,
|
|
bytesConvert: bytes,
|
|
voucher,
|
|
guests,
|
|
updated: cache.updated
|
|
});
|
|
} else {
|
|
res.status(404);
|
|
res.render('404', {
|
|
baseUrl: req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
if(apiService) {
|
|
app.get('/api', (req, res) => {
|
|
res.json({
|
|
error: null,
|
|
data: {
|
|
message: 'OK',
|
|
endpoints: [
|
|
'/api',
|
|
'/api/types',
|
|
'/api/voucher/:type',
|
|
'/api/vouchers'
|
|
]
|
|
}
|
|
});
|
|
});
|
|
app.get('/api/types', (req, res) => {
|
|
res.json({
|
|
error: null,
|
|
data: {
|
|
message: 'OK',
|
|
types: voucherTypes
|
|
}
|
|
});
|
|
});
|
|
app.get('/api/voucher/:type', [authorization.api], async (req, res) => {
|
|
const typeCheck = (process.env.VOUCHER_TYPES || '480,1,,,;').split(';').includes(req.params.type);
|
|
|
|
if(!typeCheck) {
|
|
res.json({
|
|
error: 'Unknown Type!',
|
|
data: {}
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Create voucher code
|
|
const voucherCode = await unifi.create(types(req.params.type, true)).catch((e) => {
|
|
res.json({
|
|
error: e,
|
|
data: {}
|
|
});
|
|
});
|
|
|
|
await updateCache();
|
|
|
|
if(voucherCode) {
|
|
res.json({
|
|
error: null,
|
|
data: {
|
|
message: 'OK',
|
|
voucher: voucherCode
|
|
}
|
|
});
|
|
}
|
|
});
|
|
app.get('/api/vouchers', [authorization.api], async (req, res) => {
|
|
res.json({
|
|
error: null,
|
|
data: {
|
|
message: 'OK',
|
|
vouchers: cache.vouchers.map((voucher) => {
|
|
return {
|
|
code: `${voucher.code.slice(0, 5)}-${voucher.code.slice(5)}`,
|
|
type: voucher.quota === 0 ? 'multi' : 'single',
|
|
duration: voucher.duration,
|
|
data_limit: voucher.qos_usage_quota ? voucher.qos_usage_quota : null,
|
|
download_limit: voucher.qos_rate_max_down ? voucher.qos_rate_max_down : null,
|
|
upload_limit: voucher.qos_rate_max_up ? voucher.qos_rate_max_up : null
|
|
};
|
|
}),
|
|
updated: cache.updated
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Setup default 404 message
|
|
*/
|
|
app.use((req, res) => {
|
|
res.status(404);
|
|
res.render('404', {
|
|
baseUrl: req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Disable powered by header for security reasons
|
|
*/
|
|
app.disable('x-powered-by');
|
|
|
|
/**
|
|
* Start listening on port
|
|
*/
|
|
app.listen(3000, '0.0.0.0', async () => {
|
|
log.info(`[App] Running on: 0.0.0.0:3000`);
|
|
await updateCache();
|
|
|
|
// Run auto sync every 15 minutes
|
|
setInterval(async () => {
|
|
log.info('[Auto Sync] Starting Sync...');
|
|
await updateCache();
|
|
}, 900000);
|
|
});
|