@moartube/moartube-node
Version:
A free, open-source, self-hosted, anonymous, decentralized video/live stream platform. Scalable via Cloudflare, works in the cloud or from home WiFi.
589 lines (467 loc) • 19.9 kB
JavaScript
const express = require('express');
const fs = require('fs');
const multer = require('multer');
const { v4: uuidv4 } = require('uuid');
const {
root_GET, avatar_GET, avatar_POST, banner_GET, banner_POST, personalizeNodeName_POST, personalizeNodeAbout_POST, personalizeNodeId_POST, secure_POST, account_POST,
networkInternal_POST, networkExternal_POST, cloudflareConfigure_POST, cloudflareClear_POST, cloudflareTurnstileConfigure_POST, cloudflareTurnstileConfigureClear_POST,
commentsToggle_POST, likesToggle_POST, dislikesToggle_POST, reportsToggle_POST, liveChatToggle_POST, databaseConfigToggle_POST, storageConfigToggle_POST,
exportDatabase_GET, importDatabase_POST
} = require('../controllers/settings');
const {
getImagesDirectoryPath, getCertificatesDirectoryPath
} = require('../utils/paths');
const {
logDebugMessageToConsole
} = require('../utils/logger');
const {
performAuthenticationCheck
} = require('../middleware/authentication');
const router = express.Router();
router.get('/', performAuthenticationCheck(true), async (req, res) => {
try {
const data = root_GET();
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.get('/avatar', performAuthenticationCheck(false), (req, res) => {
try {
const fileStream = avatar_GET();
if (fileStream != null) {
res.setHeader('Content-Type', 'image/png');
fileStream.pipe(res);
}
else {
res.status(404).send('avatar not found');
}
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.status(500).send('node avatar retrieval error');
}
});
router.post('/avatar', performAuthenticationCheck(true), (req, res) => {
logDebugMessageToConsole('uploading node avatar', null, null);
multer(
{
fileFilter: function (req, file, cb) {
const mimeType = file.mimetype;
if (mimeType === 'image/png') {
cb(null, true);
}
else {
cb(new Error('Invalid file upload mime type detected!'));
}
},
storage: multer.diskStorage({
destination: function (req, file, cb) {
fs.access(getImagesDirectoryPath(), fs.constants.F_OK, function (error) {
if (error) {
cb(new Error('file upload error'), null);
}
else {
cb(null, getImagesDirectoryPath());
}
});
},
filename: function (req, file, cb) {
let extension;
if (file.mimetype === 'image/png') {
extension = '.png';
}
const fileName = uuidv4() + extension;
cb(null, fileName);
}
})
}).fields([{ name: 'iconFile', maxCount: 1 }, { name: 'avatarFile', maxCount: 1 }])
(req, res, async function (error) {
if (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: error.message });
}
else {
logDebugMessageToConsole('uploaded node avatar', null, null);
try {
const iconFile = req.files['iconFile'][0];
const avatarFile = req.files['avatarFile'][0];
const data = await avatar_POST(iconFile, avatarFile);
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
}
});
});
router.get('/banner', performAuthenticationCheck(false), (req, res) => {
try {
const fileStream = banner_GET();
if (fileStream != null) {
res.setHeader('Content-Type', 'image/png');
fileStream.pipe(res);
}
else {
res.status(404).send('banner not found');
}
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.status(500).send('node banner retrieval error');
}
});
router.post('/banner', performAuthenticationCheck(true), (req, res) => {
logDebugMessageToConsole('uploading node banner', null, null);
multer(
{
fileFilter: function (req, file, cb) {
const mimeType = file.mimetype;
if (mimeType === 'image/png') {
cb(null, true);
}
else {
cb(new Error('Invalid file upload mime type detected!'));
}
},
storage: multer.diskStorage({
destination: function (req, file, cb) {
fs.access(getImagesDirectoryPath(), fs.constants.F_OK, function (error) {
if (error) {
cb(new Error('file upload error'), null);
}
else {
cb(null, getImagesDirectoryPath());
}
});
},
filename: function (req, file, cb) {
let extension;
if (file.mimetype === 'image/png') {
extension = '.png';
}
const fileName = uuidv4() + extension;
cb(null, fileName);
}
})
}).fields([{ name: 'bannerFile', maxCount: 1 }])
(req, res, function (error) {
if (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: error.message });
}
else {
logDebugMessageToConsole('uploaded node banner', null, null);
try {
const bannerFile = req.files['bannerFile'][0];
const data = banner_POST(bannerFile);
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
}
});
});
router.post('/personalize/nodeName', performAuthenticationCheck(true), async (req, res) => {
try {
const nodeName = req.body.nodeName;
const data = await personalizeNodeName_POST(nodeName);
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.post('/personalize/nodeAbout', performAuthenticationCheck(true), async (req, res) => {
try {
const nodeAbout = req.body.nodeAbout;
const data = await personalizeNodeAbout_POST(nodeAbout);
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.post('/personalize/nodeId', performAuthenticationCheck(true), async (req, res) => {
try {
const nodeId = req.body.nodeId;
const data = await personalizeNodeId_POST(nodeId);
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.post('/secure', performAuthenticationCheck(true), (req, res) => {
let isSecure = (req.query.isSecure === 'true');
if (isSecure) {
multer({
fileFilter: function (req, file, cb) {
cb(null, true);
},
storage: multer.diskStorage({
destination: function (req, file, cb) {
fs.access(getCertificatesDirectoryPath(), fs.constants.F_OK, function (error) {
if (error) {
cb(new Error('file upload error'), null);
}
else {
cb(null, getCertificatesDirectoryPath());
}
});
},
filename: function (req, file, cb) {
if (file.fieldname === 'keyFile') {
cb(null, 'private_key.pem');
}
else if (file.fieldname === 'certFile') {
cb(null, 'certificate.pem');
}
else if (file.fieldname === 'caFiles') {
cb(null, file.originalname);
}
else {
cb(new Error('invalid field name in POST /settings/secure:' + file.fieldname), null);
}
}
})
}).fields([{ name: 'keyFile', maxCount: 1 }, { name: 'certFile', maxCount: 1 }, { name: 'caFiles' }])
(req, res, async function (error) {
if (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
else {
try {
const keyFile = req.files['keyFile'];
const certFile = req.files['certFile'];
const caFiles = req.files['caFiles'];
const data = secure_POST(isSecure, keyFile, certFile, caFiles);
res.send(data);
process.send({ cmd: 'restart_server' });
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
}
});
}
else {
try {
const data = secure_POST(isSecure);
res.send(data);
process.send({ cmd: 'restart_server' });
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
}
});
router.post('/cloudflare/configure', performAuthenticationCheck(true), async (req, res) => {
try {
const cloudflareEmailAddress = req.body.cloudflareEmailAddress;
const cloudflareZoneId = req.body.cloudflareZoneId;
const cloudflareGlobalApiKey = req.body.cloudflareGlobalApiKey;
const data = await cloudflareConfigure_POST(cloudflareEmailAddress, cloudflareZoneId, cloudflareGlobalApiKey);
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.post('/cloudflare/clear', performAuthenticationCheck(true), async (req, res) => {
try {
const data = await cloudflareClear_POST();
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.post('/cloudflare/turnstile/configure', performAuthenticationCheck(true), async (req, res) => {
try {
const cloudflareTurnstileSiteKey = req.body.cloudflareTurnstileSiteKey;
const cloudflareTurnstileSecretKey = req.body.cloudflareTurnstileSecretKey;
const data = await cloudflareTurnstileConfigure_POST(cloudflareTurnstileSiteKey, cloudflareTurnstileSecretKey);
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.post('/cloudflare/turnstile/clear', performAuthenticationCheck(true), async (req, res) => {
try {
const data = await cloudflareTurnstileConfigureClear_POST();
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.post('/databaseConfig/toggle', performAuthenticationCheck(true), async (req, res) => {
try {
const databaseConfig = req.body.databaseConfig;
const data = await databaseConfigToggle_POST(databaseConfig);
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.post('/storageConfig/toggle', performAuthenticationCheck(true), async (req, res) => {
try {
const storageConfig = req.body.storageConfig;
const data = await storageConfigToggle_POST(storageConfig);
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.post('/comments/toggle', performAuthenticationCheck(true), (req, res) => {
try {
const isCommentsEnabled = req.body.isCommentsEnabled;
const data = commentsToggle_POST(isCommentsEnabled);
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.post('/likes/toggle', performAuthenticationCheck(true), (req, res) => {
try {
const isLikesEnabled = req.body.isLikesEnabled;
const data = likesToggle_POST(isLikesEnabled);
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.post('/dislikes/toggle', performAuthenticationCheck(true), (req, res) => {
try {
const isDislikesEnabled = req.body.isDislikesEnabled;
const data = dislikesToggle_POST(isDislikesEnabled);
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.post('/reports/toggle', performAuthenticationCheck(true), (req, res) => {
try {
const isReportsEnabled = req.body.isReportsEnabled;
const data = reportsToggle_POST(isReportsEnabled);
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.post('/liveChat/toggle', performAuthenticationCheck(true), (req, res) => {
try {
const isLiveChatEnabled = req.body.isLiveChatEnabled;
const data = liveChatToggle_POST(isLiveChatEnabled);
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.post('/account', performAuthenticationCheck(true), (req, res) => {
try {
const username = req.body.username;
const password = req.body.password;
const data = account_POST(username, password);
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.post('/network/internal', performAuthenticationCheck(true), (req, res) => {
try {
const listeningNodePort = req.body.listeningNodePort;
const data = networkInternal_POST(listeningNodePort);
res.send(data);
process.send({ cmd: 'restart_server' });
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.post('/network/external', performAuthenticationCheck(true), async (req, res) => {
try {
const publicNodeProtocol = req.body.publicNodeProtocol;
const publicNodeAddress = req.body.publicNodeAddress;
const publicNodePort = req.body.publicNodePort;
const data = await networkExternal_POST(publicNodeProtocol, publicNodeAddress, publicNodePort);
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.post('/import/database', performAuthenticationCheck(false), async (req, res) => {
try {
multer({
storage: multer.memoryStorage(),
}).fields([{ name: 'database_file', maxCount: 1 }])
(req, res, async function (error) {
if (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
else {
try {
const databaseFile = req.files['database_file'];
const data = await importDatabase_POST(databaseFile);
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
}
});
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
router.get('/export/database', performAuthenticationCheck(false), async (req, res) => {
try {
const data = await exportDatabase_GET();
res.send(data);
}
catch (error) {
logDebugMessageToConsole(null, error, new Error().stack);
res.send({ isError: true, message: 'error communicating with the MoarTube node' });
}
});
module.exports = router;