diff --git a/modules/unifi.js b/modules/unifi.js index dbb08b5..472aafb 100644 --- a/modules/unifi.js +++ b/modules/unifi.js @@ -22,6 +22,53 @@ const config = { } }; +/** + * Controller session + */ +let controller = null; + +/** + * Start a UniFi controller reusable session + * + * @return {Promise} + */ +const startSession = () => { + return new Promise((resolve, reject) => { + // Check if we have a current session already + if(controller !== null) { + resolve(); + return; + } + + // Create new UniFi controller object + controller = new unifi.Controller({ + host: config.unifi.ip, + port: config.unifi.port, + site: config.unifi.siteID, + sslverify: false + }); + + // Login to UniFi Controller + controller.login(config.unifi.username, config.unifi.password).then(() => { + log.info('[UniFi] Login successful!'); + resolve(); + + // Clear session after about 1 hour (bearer token will expire after 2 hours) + setTimeout(async () => { + log.info('[UniFi] Controller session timeout reached! Cleanup controller...'); + await controller.logout(); + controller = null; + }, 3600000); + }).catch((e) => { + // Something went wrong so clear the current controller so a user can retry + controller = null; + log.error('[UniFi] Error while logging in!'); + log.error(e); + reject('[UniFi] Error while logging in!'); + }); + }); +} + /** * Exports the UniFi voucher functions * @@ -32,72 +79,68 @@ module.exports = { * Creates a new UniFi Voucher * * @param type + * @param amount * @return {Promise} */ - create: (type) => { + create: (type, amount = 1) => { return new Promise((resolve, reject) => { - /** - * Create new UniFi controller object - * - * @type {Controller} - */ - const controller = new unifi.Controller({ - host: config.unifi.ip, - port: config.unifi.port, - site: config.unifi.siteID, - sslverify: false - }); - - /** - * Login and create a voucher - */ - controller.login(config.unifi.username, config.unifi.password).then(() => { - controller.createVouchers(type.expiration, 1, parseInt(type.usage) === 1 ? 1 : 0, null, typeof type.upload !== "undefined" ? type.upload : null, typeof type.download !== "undefined" ? type.download : null, typeof type.megabytes !== "undefined" ? type.megabytes : null).then((voucher_data) => { - controller.getVouchers(voucher_data[0].create_time).then((voucher_data_complete) => { - const voucher = `${[voucher_data_complete[0].code.slice(0, 5), '-', voucher_data_complete[0].code.slice(5)].join('')}`; - log.info(`[UniFi] Created voucher with code: ${voucher}`); - resolve(voucher); - }).catch((e) => { - log.error('[UniFi] Error while getting voucher!'); - log.error(e); - reject('[UniFi] Error while getting voucher!'); - }); + startSession().then(() => { + controller.createVouchers(type.expiration, amount, parseInt(type.usage) === 1 ? 1 : 0, null, typeof type.upload !== "undefined" ? type.upload : null, typeof type.download !== "undefined" ? type.download : null, typeof type.megabytes !== "undefined" ? type.megabytes : null).then((voucher_data) => { + if(amount > 1) { + log.info(`[UniFi] Created ${amount} vouchers`); + resolve(true); + } else { + controller.getVouchers(voucher_data[0].create_time).then((voucher_data_complete) => { + const voucher = `${[voucher_data_complete[0].code.slice(0, 5), '-', voucher_data_complete[0].code.slice(5)].join('')}`; + log.info(`[UniFi] Created voucher with code: ${voucher}`); + resolve(voucher); + }).catch((e) => { + log.error('[UniFi] Error while getting voucher!'); + log.error(e); + reject('[UniFi] Error while getting voucher!'); + }); + } }).catch((e) => { log.error('[UniFi] Error while creating voucher!'); log.error(e); reject('[UniFi] Error while creating voucher!'); }); }).catch((e) => { - log.error('[UniFi] Error while logging in!'); - log.error(e); - reject('[UniFi] Error while logging in!'); + reject(e); }); }); }, /** - * Returns a list with all UniFi Vouchers + * Removes a UniFi Voucher * + * @param id * @return {Promise} */ - list: () => { + remove: (id) => { return new Promise((resolve, reject) => { - /** - * Create new UniFi controller object - * - * @type {Controller} - */ - const controller = new unifi.Controller({ - host: config.unifi.ip, - port: config.unifi.port, - site: config.unifi.siteID, - sslverify: false + startSession().then(() => { + controller.revokeVoucher(id).then(() => { + resolve(true); + }).catch((e) => { + log.error('[UniFi] Error while removing voucher!'); + log.error(e); + reject('[UniFi] Error while removing voucher!'); + }); + }).catch((e) => { + reject(e); }); + }); + }, - /** - * Login and get vouchers - */ - controller.login(config.unifi.username, config.unifi.password).then(() => { + /** + * Returns a list with all UniFi Vouchers + * + * @return {Promise} + */ + list: () => { + return new Promise((resolve, reject) => { + startSession().then(() => { controller.getVouchers().then((vouchers) => { log.info(`[UniFi] Found ${vouchers.length} voucher(s)`); resolve(vouchers); @@ -107,9 +150,7 @@ module.exports = { reject('[UniFi] Error while getting vouchers!'); }); }).catch((e) => { - log.error('[UniFi] Error while logging in!'); - log.error(e); - reject('[UniFi] Error while logging in!'); + reject(e); }); }); } diff --git a/public/images/logo_grayscale.png b/public/images/logo_grayscale.png new file mode 100644 index 0000000..0820ebe Binary files /dev/null and b/public/images/logo_grayscale.png differ diff --git a/server.js b/server.js index e30ea43..e44a123 100644 --- a/server.js +++ b/server.js @@ -189,26 +189,50 @@ if(webService) { } // Create voucher code - const voucherCode = await unifi.create(types(req.body['voucher-type'], true)).catch((e) => { + const voucherCode = await unifi.create(types(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`); }); - log.info('[Cache] Requesting UniFi Vouchers...'); + if(voucherCode) { + log.info('[Cache] Requesting UniFi Vouchers...'); + + const vouchers = await unifi.list().catch((e) => { + log.error('[Cache] Error requesting vouchers!'); + log.error(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`); + }); - const vouchers = await unifi.list().catch((e) => { - log.error('[Cache] Error requesting vouchers!'); - log.error(e); + 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(vouchers) { - cache.vouchers = vouchers; - cache.updated = new Date().getTime(); - log.info(`[Cache] Saved ${vouchers.length} voucher(s)`); - } + if(response) { + log.info('[Cache] Requesting UniFi Vouchers...'); - if(vouchers && voucherCode) { - res.cookie('flashMessage', JSON.stringify({type: 'info', message: `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`); + const vouchers = await unifi.list().catch((e) => { + log.error('[Cache] Error requesting vouchers!'); + log.error(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(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('/vouchers', [authorization.web], async (req, res) => { diff --git a/template/voucher.ejs b/template/voucher.ejs index 10d2f21..67f4083 100644 --- a/template/voucher.ejs +++ b/template/voucher.ejs @@ -183,6 +183,13 @@ + + + Remove Voucher Code + + <% }); %> @@ -219,6 +226,12 @@ +
+ +
+ +
+
@@ -245,6 +258,17 @@

This may take a few seconds, please don't close this page.

+ +