Initial commit.
This commit is contained in:
commit
f0c91b4e55
78 changed files with 5054 additions and 0 deletions
22
src/app/channel/activeChannel.js
Normal file
22
src/app/channel/activeChannel.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
module.exports = class{
|
||||
constructor(name){
|
||||
this.name = name;
|
||||
this.userList = new Map();
|
||||
}
|
||||
}
|
||||
112
src/app/channel/channelManager.js
Normal file
112
src/app/channel/channelManager.js
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//Local Imports
|
||||
const channelModel = require('../../schemas/channelSchema');
|
||||
const activeChannel = require('./activeChannel');
|
||||
const chatHandler = require('./chatHandler');
|
||||
|
||||
//local variables
|
||||
var activeChannels = new Map;
|
||||
|
||||
module.exports.handleConnection = async function(io, socket){
|
||||
//Prevent logged out connections and authenticate socket
|
||||
if(socket.request.session.user != null){
|
||||
try{
|
||||
//Set socket user and channel values
|
||||
socket.user = socket.request.session.user;
|
||||
socket.chanName = socket.handshake.headers.referer.split('/c/')[1];
|
||||
|
||||
//Check if channel exists
|
||||
if(await channelModel.findOne({name: socket.chanName}) == null){
|
||||
socket.disconnect("Channel does not exist!");
|
||||
return;
|
||||
}
|
||||
|
||||
//Check if current channel is active
|
||||
var activeChan = activeChannels.get(socket.chan);
|
||||
if(!activeChan){
|
||||
//If not, make it so
|
||||
activeChan = new activeChannel(socket.chan);
|
||||
activeChannels.set(socket.chan, activeChan);
|
||||
}
|
||||
|
||||
//Check if this user is already connected
|
||||
if(activeChan.userList.get(socket.user.user)){
|
||||
//get current list of socket connnections of selected user
|
||||
var socketList = activeChan.userList.get(socket.user.user);
|
||||
//Add this one on
|
||||
socketList.push(socket.id);
|
||||
//Set the user back socket list back
|
||||
activeChan.userList.set(socket.user.user, socketList);
|
||||
}else{
|
||||
//if this is the first connection, initialize the socket array for this user
|
||||
activeChan.userList.set(socket.user.user, [socket.id]);
|
||||
}
|
||||
|
||||
//if everything looks good, admit the connection to the channel
|
||||
socket.join(socket.chan);
|
||||
|
||||
//Send out the userlist
|
||||
module.exports.broadcastUserList(io, socket.chan);
|
||||
|
||||
}catch(err){
|
||||
socket.disconnect("Server Error During Channel Connection Initialization");
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
|
||||
}else{
|
||||
socket.disconnect("Unauthenticated");
|
||||
return;
|
||||
}
|
||||
|
||||
//Socket Listeners
|
||||
socket.conn.on("close", (reason) => {
|
||||
//Get active channel
|
||||
var activeChan = activeChannels.get(socket.chan);
|
||||
|
||||
//If we have more than one active connection
|
||||
if(activeChan.userList.get(socket.user.user).length > 1){
|
||||
//temporarily store list of active user sockets
|
||||
var socketList = activeChan.userList.get(socket.user.user);
|
||||
//Filter out disconnecting socket from socket list, and set as current socket list for user
|
||||
activeChan.userList.set(socket.user.user,socketList.filter((id) => {
|
||||
return id != socket.id;
|
||||
}))
|
||||
}else{
|
||||
activeChan.userList.delete(socket.user.user);
|
||||
}
|
||||
|
||||
//and send out the filtered list
|
||||
module.exports.broadcastUserList(io, socket.chan);
|
||||
});
|
||||
|
||||
//define chat listeners
|
||||
chatHandler.defineListeners(io, socket);
|
||||
|
||||
}
|
||||
|
||||
module.exports.broadcastUserList = function(io, chan){
|
||||
var activeChan = activeChannels.get(chan);
|
||||
var userList = [];
|
||||
|
||||
activeChan.userList.forEach((socketlist, user) => {
|
||||
userList.push(user);
|
||||
});
|
||||
|
||||
io.in(chan).emit("user-list", userList);
|
||||
}
|
||||
39
src/app/channel/chatHandler.js
Normal file
39
src/app/channel/chatHandler.js
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//NPM Imports
|
||||
const validator = require('validator');//No express here, so regular validator it is!
|
||||
|
||||
module.exports.defineListeners = function(io, socket){
|
||||
socket.on("chat-message", (data) => {
|
||||
//Trim and Sanatize for XSS
|
||||
const msg = validator.trim(validator.escape(data.msg));
|
||||
//make sure high is an int
|
||||
const high = validator.toInt(data.high);
|
||||
|
||||
//nuke the message if its empty or huge
|
||||
if(!validator.isLength(msg, {min: 1, max: 255})){
|
||||
return;
|
||||
}
|
||||
|
||||
//nuke the message if the high number is wrong
|
||||
if(high < 0 || high > 10){
|
||||
return;
|
||||
}
|
||||
|
||||
io.in(socket.chan).emit("chat-message", {user: socket.user.user, msg, high});
|
||||
});
|
||||
}
|
||||
30
src/controllers/adminPanelController.js
Normal file
30
src/controllers/adminPanelController.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//Config
|
||||
const config = require('../../config.json');
|
||||
const channelModel = require('../schemas/channelSchema');
|
||||
|
||||
//register page functions
|
||||
module.exports.get = async function(req, res){
|
||||
try{
|
||||
const chanGuide = await channelModel.getChannelList(true);
|
||||
return res.render('adminPanel', {instance: config.instanceName, user: req.session.user, chanGuide: chanGuide});
|
||||
}catch(err){
|
||||
res.status(500);
|
||||
return res.send("Error indexing channels!");
|
||||
}
|
||||
}
|
||||
60
src/controllers/api/account/deleteController.js
Normal file
60
src/controllers/api/account/deleteController.js
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//npm imports
|
||||
const {validationResult, matchedData} = require('express-validator');
|
||||
|
||||
//local imports
|
||||
const userModel = require('../../../schemas/userSchema');
|
||||
const accountUtils = require('../../../utils/sessionUtils.js');
|
||||
const {exceptionHandler} = require('../../../utils/loggerUtils.js');
|
||||
|
||||
//api account functions
|
||||
module.exports.post = async function(req, res){
|
||||
try{
|
||||
const validResult = validationResult(req);
|
||||
|
||||
if(validResult.isEmpty()){
|
||||
//syntactic sugar :P
|
||||
const user = req.session.user;
|
||||
const data = matchedData(req);
|
||||
|
||||
//make sure we're not bullshitting ourselves here.
|
||||
if(user == null){
|
||||
res.status(400);
|
||||
return res.send('Invalid Session! Cannot delete account while logged out!');
|
||||
}
|
||||
|
||||
const userDB = await userModel.findOne(user);
|
||||
|
||||
|
||||
if(!userDB){
|
||||
res.status(400);
|
||||
return res.send('Invalid User! Account must exist in order to delete!');
|
||||
}
|
||||
|
||||
await userDB.nuke(data.pass);
|
||||
accountUtils.killSession(req.session);
|
||||
return res.sendStatus(200);
|
||||
}else{
|
||||
res.status(400);
|
||||
res.send({errors: validResult.array()})
|
||||
}
|
||||
}catch(err){
|
||||
exceptionHandler(res, err);
|
||||
}
|
||||
|
||||
}
|
||||
45
src/controllers/api/account/loginController.js
Normal file
45
src/controllers/api/account/loginController.js
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//npm imports
|
||||
const {validationResult, matchedData} = require('express-validator');
|
||||
|
||||
//local imports
|
||||
const accountUtils = require('../../../utils/sessionUtils.js');
|
||||
const {exceptionHandler} = require('../../../utils/loggerUtils.js');
|
||||
|
||||
|
||||
//api account functions
|
||||
module.exports.post = async function(req, res){
|
||||
try{
|
||||
const validResult = validationResult(req);
|
||||
|
||||
if(validResult.isEmpty()){
|
||||
const data = matchedData(req);
|
||||
const {user, pass} = data;
|
||||
|
||||
//try to authenticate the session, and return a successful code if it works
|
||||
await accountUtils.authenticateSession(user, pass, req);
|
||||
return res.sendStatus(200);
|
||||
}else{
|
||||
res.status(400);
|
||||
res.send({errors: validResult.array()})
|
||||
}
|
||||
}catch(err){
|
||||
exceptionHandler(res, err);
|
||||
}
|
||||
|
||||
}
|
||||
33
src/controllers/api/account/logoutController.js
Normal file
33
src/controllers/api/account/logoutController.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//local imports
|
||||
const accountUtils = require('../../../utils/sessionUtils.js');
|
||||
|
||||
module.exports.get = async function(req, res){
|
||||
if(req.session.user){
|
||||
try{
|
||||
accountUtils.killSession(req.session);
|
||||
return res.sendStatus(200);
|
||||
}catch(err){
|
||||
res.status(400);
|
||||
return res.send(err.message)
|
||||
}
|
||||
}else{
|
||||
res.status(400);
|
||||
return res.send()
|
||||
}
|
||||
}
|
||||
39
src/controllers/api/account/registerController.js
Normal file
39
src/controllers/api/account/registerController.js
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//NPM Imports
|
||||
const {validationResult, matchedData} = require('express-validator');
|
||||
|
||||
//local imports
|
||||
const userModel = require('../../../schemas/userSchema');
|
||||
const {exceptionHandler} = require('../../../utils/loggerUtils.js');
|
||||
|
||||
module.exports.post = async function(req, res){
|
||||
try{
|
||||
const validResult = validationResult(req);
|
||||
|
||||
if(validResult.isEmpty()){
|
||||
const user = matchedData(req);
|
||||
await userModel.register(user)
|
||||
return res.sendStatus(200);
|
||||
}else{
|
||||
res.status(400);
|
||||
res.send({errors: validResult.array()})
|
||||
}
|
||||
}catch(err){
|
||||
exceptionHandler(res, err);
|
||||
}
|
||||
}
|
||||
89
src/controllers/api/account/updateController.js
Normal file
89
src/controllers/api/account/updateController.js
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//NPM Imports
|
||||
const {validationResult, matchedData} = require('express-validator');
|
||||
|
||||
//local imports
|
||||
const userModel = require('../../../schemas/userSchema');
|
||||
const accountUtils = require('../../../utils/sessionUtils.js');
|
||||
const {exceptionHandler} = require('../../../utils/loggerUtils.js');
|
||||
|
||||
module.exports.post = async function(req, res){
|
||||
const validResult = validationResult(req);
|
||||
const data = matchedData(req);
|
||||
var tempResult = [];
|
||||
|
||||
//if we're not chaning the password
|
||||
if(data.passChange == null){
|
||||
//go through validation errors
|
||||
validResult.errors.forEach(function(error, i){
|
||||
//remove irrelevant password validation errors (i know its gross but they need to be optional as a set, not individually)
|
||||
if(!error.path.startsWith("passChange.")){
|
||||
tempResult.push(error);
|
||||
}
|
||||
});
|
||||
|
||||
validResult.errors = tempResult;
|
||||
}
|
||||
|
||||
try{
|
||||
if(validResult.isEmpty()){
|
||||
const {field, change} = data;
|
||||
const {user} = req.session;
|
||||
|
||||
const userDB = await userModel.findOne(user);
|
||||
const update = {};
|
||||
|
||||
if(userDB){
|
||||
if(data.img){
|
||||
userDB.img = data.img;
|
||||
update.img = data.img;
|
||||
}
|
||||
|
||||
if(data.bio){
|
||||
userDB.bio = data.bio;
|
||||
update.bio = data.bio;
|
||||
}
|
||||
|
||||
if(data.signature){
|
||||
userDB.signature = data.signature;
|
||||
update.signature = data.signature;
|
||||
}
|
||||
|
||||
if(data.passChange){
|
||||
//kill active session to prevent connect-mongo from freaking out
|
||||
accountUtils.killSession(req.session);
|
||||
await userDB.passwordReset(data.passChange);
|
||||
}
|
||||
|
||||
await userDB.save();
|
||||
|
||||
res.status(200);
|
||||
return res.send(update);
|
||||
}else{
|
||||
res.status(400);
|
||||
return res.send({errors: [{msg:"User not found!"}]});
|
||||
}
|
||||
}else{
|
||||
res.status(400);
|
||||
res.send({errors: validResult.array()})
|
||||
}
|
||||
}catch(err){
|
||||
exceptionHandler(res, err);
|
||||
}
|
||||
|
||||
}
|
||||
48
src/controllers/api/channel/deleteController.js
Normal file
48
src/controllers/api/channel/deleteController.js
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//NPM imports
|
||||
const {validationResult, matchedData} = require('express-validator');
|
||||
|
||||
//local imports
|
||||
const {exceptionHandler} = require('../../../utils/loggerUtils.js');
|
||||
const channelModel = require('../../../schemas/channelSchema');
|
||||
|
||||
//api account functions
|
||||
module.exports.post = async function(req, res){
|
||||
try{
|
||||
const validResult = validationResult(req);
|
||||
|
||||
if(validResult.isEmpty()){
|
||||
const data = matchedData(req);
|
||||
const channel = await channelModel.findOne({name: data.chanName});
|
||||
|
||||
if(channel == null){
|
||||
throw new Error("Chanenl does not exist!");
|
||||
}
|
||||
|
||||
await channel.nuke(data.confirm);
|
||||
return res.sendStatus(200);
|
||||
}else{
|
||||
res.status(400);
|
||||
res.send({errors: validResult.array()})
|
||||
}
|
||||
}catch(err){
|
||||
exceptionHandler(res, err);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
32
src/controllers/api/channel/listController.js
Normal file
32
src/controllers/api/channel/listController.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//local imports
|
||||
const channelModel = require('../../../schemas/channelSchema');
|
||||
|
||||
//api account functions
|
||||
module.exports.get = async function(req, res){
|
||||
try{
|
||||
//I'm not sanatizing this, it never gets processed...
|
||||
const chanGuide = await channelModel.getChannelList(req.query.showHidden || req.query.showHidden === '');
|
||||
|
||||
res.status(200);
|
||||
return res.send(chanGuide);
|
||||
}catch(err){
|
||||
res.status(400);
|
||||
return res.send(err.message);
|
||||
}
|
||||
}
|
||||
42
src/controllers/api/channel/registerController.js
Normal file
42
src/controllers/api/channel/registerController.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//NPM Imports
|
||||
const {validationResult, matchedData} = require('express-validator');
|
||||
|
||||
//local imports
|
||||
const {exceptionHandler} = require('../../../utils/loggerUtils.js');
|
||||
const channelModel = require('../../../schemas/channelSchema');
|
||||
|
||||
//api account functions
|
||||
module.exports.post = async function(req, res){
|
||||
try{
|
||||
const validResult = validationResult(req);
|
||||
const channel = matchedData(req);
|
||||
|
||||
|
||||
if(validResult.isEmpty()){
|
||||
await channelModel.register(channel)
|
||||
return res.sendStatus(200);
|
||||
}else{
|
||||
res.status(400);
|
||||
res.send({errors: validResult.array()})
|
||||
}
|
||||
}catch(err){
|
||||
exceptionHandler(res, err);
|
||||
}
|
||||
|
||||
}
|
||||
72
src/controllers/api/channel/settingsController.js
Normal file
72
src/controllers/api/channel/settingsController.js
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//NPM imports
|
||||
const {validationResult, matchedData} = require('express-validator');
|
||||
|
||||
//local imports
|
||||
const {exceptionHandler} = require('../../../utils/loggerUtils.js');
|
||||
const channelModel = require('../../../schemas/channelSchema');
|
||||
|
||||
//api account functions
|
||||
module.exports.get = async function(req, res){
|
||||
try{
|
||||
const validResult = validationResult(req);
|
||||
|
||||
if(validResult.isEmpty()){
|
||||
const data = matchedData(req);
|
||||
const channel = await channelModel.findOne({name: data.chanName});
|
||||
|
||||
if(channel == null){
|
||||
throw new Error("Channel not found.");
|
||||
}
|
||||
|
||||
res.status(200);
|
||||
return res.send(channel.settings);
|
||||
}else{
|
||||
res.status(400);
|
||||
res.send({errors: validResult.array()})
|
||||
}
|
||||
}catch(err){
|
||||
exceptionHandler(res, err);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports.post = async function(req, res){
|
||||
try{
|
||||
const validResult = validationResult(req);
|
||||
|
||||
if(validResult.isEmpty()){
|
||||
const data = matchedData(req);
|
||||
const channel = await channelModel.findOne({name: data.chanName});
|
||||
const settingsMap = new Map(Object.entries(data.settingsMap));
|
||||
|
||||
if(channel == null){
|
||||
throw new Error("Channel not found.");
|
||||
}
|
||||
|
||||
res.status(200);
|
||||
return res.send(await channel.updateSettings(settingsMap));
|
||||
}else{
|
||||
res.status(400);
|
||||
res.send({errors: validResult.array()})
|
||||
}
|
||||
}catch(err){
|
||||
exceptionHandler(res, err);
|
||||
}
|
||||
|
||||
}
|
||||
23
src/controllers/channelController.js
Normal file
23
src/controllers/channelController.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//Config
|
||||
const config = require('../../config.json');
|
||||
|
||||
//channel functions
|
||||
module.exports.get = function(req, res){
|
||||
res.render('channel', {instance: config.instanceName, user: req.session.user});
|
||||
}
|
||||
36
src/controllers/channelSettingsController.js
Normal file
36
src/controllers/channelSettingsController.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//Config
|
||||
const config = require('../../config.json');
|
||||
const channelModel = require('../schemas/channelSchema');
|
||||
|
||||
//root index functions
|
||||
module.exports.get = async function(req, res){
|
||||
try{
|
||||
const chanName = (req.url.slice(1).replace('/settings',''));
|
||||
const channel = await channelModel.findOne({name: chanName});
|
||||
|
||||
if(channel == null){
|
||||
throw new Error("Channel not found.");
|
||||
}
|
||||
|
||||
return res.render('channelSettings', {instance: config.instanceName, user: req.session.user, channel});
|
||||
}catch(err){
|
||||
res.status(500);
|
||||
res.send(err.message);
|
||||
}
|
||||
}
|
||||
30
src/controllers/indexController.js
Normal file
30
src/controllers/indexController.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//Config
|
||||
const config = require('../../config.json');
|
||||
const channelModel = require('../schemas/channelSchema');
|
||||
|
||||
//root index functions
|
||||
module.exports.get = async function(req, res){
|
||||
try{
|
||||
const chanGuide = await channelModel.getChannelList();
|
||||
return res.render('index', {instance: config.instanceName, user: req.session.user, chanGuide: chanGuide});
|
||||
}catch(err){
|
||||
res.status(500);
|
||||
return res.send("Error indexing channels!");
|
||||
}
|
||||
}
|
||||
23
src/controllers/newChannelController.js
Normal file
23
src/controllers/newChannelController.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//Config
|
||||
const config = require('../../config.json');
|
||||
|
||||
//root index functions
|
||||
module.exports.get = async function(req, res){
|
||||
res.render('newChannel', {instance: config.instanceName, user: req.session.user});
|
||||
}
|
||||
50
src/controllers/profileController.js
Normal file
50
src/controllers/profileController.js
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//Local Imports
|
||||
const userModel = require('../schemas/userSchema');
|
||||
|
||||
//Config
|
||||
const config = require('../../config.json');
|
||||
|
||||
|
||||
//profile functions
|
||||
module.exports.get = async function(req, res){
|
||||
|
||||
var profileName = req.url.slice(1) == '' ? (req.session.user ? req.session.user.user : null) : req.url.slice(1);
|
||||
|
||||
const userDB = await userModel.findOne({ user: profileName });
|
||||
|
||||
if(userDB){
|
||||
res.render('profile', {instance: config.instanceName,
|
||||
user: req.session.user,
|
||||
profile: {
|
||||
id: userDB.id,
|
||||
user: userDB.user,
|
||||
date: userDB.date,
|
||||
tokes: userDB.tokes,
|
||||
img: userDB.img,
|
||||
signature: userDB.signature,
|
||||
bio: userDB.bio
|
||||
}
|
||||
});
|
||||
}else{
|
||||
res.render('profile', {instance: config.instanceName,
|
||||
user: req.session.user,
|
||||
profile: null
|
||||
});
|
||||
}
|
||||
}
|
||||
23
src/controllers/registerController.js
Normal file
23
src/controllers/registerController.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//Config
|
||||
const config = require('../../config.json');
|
||||
|
||||
//register page functions
|
||||
module.exports.get = function(req, res){
|
||||
res.render('register', {instance: config.instanceName, user: req.session.user});
|
||||
}
|
||||
30
src/routers/adminPanelRouter.js
Normal file
30
src/routers/adminPanelRouter.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//npm imports
|
||||
const { Router } = require('express');
|
||||
|
||||
|
||||
//local imports
|
||||
const adminPanelController = require("../controllers/adminPanelController");
|
||||
|
||||
//globals
|
||||
const router = Router();
|
||||
|
||||
//routing functions
|
||||
router.get('/', adminPanelController.get);
|
||||
|
||||
module.exports = router;
|
||||
50
src/routers/api/accountRouter.js
Normal file
50
src/routers/api/accountRouter.js
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//npm imports
|
||||
const { Router } = require('express');
|
||||
|
||||
//local imports
|
||||
const {accountValidator} = require("../../utils/validators");
|
||||
const loginController = require("../../controllers/api/account/loginController");
|
||||
const logoutController = require("../../controllers/api/account/logoutController");
|
||||
const registerController = require("../../controllers/api/account/registerController");
|
||||
const updateController = require("../../controllers/api/account/updateController");
|
||||
const deleteController = require("../../controllers/api/account/deleteController");
|
||||
|
||||
//globals
|
||||
const router = Router();
|
||||
|
||||
//routing functions
|
||||
router.post('/login', accountValidator.user(), accountValidator.pass(), loginController.post);
|
||||
|
||||
router.get('/logout', logoutController.get);
|
||||
|
||||
router.post('/register', accountValidator.user(),
|
||||
accountValidator.pass(),
|
||||
accountValidator.pass('passConfirm'),
|
||||
accountValidator.email(), registerController.post);
|
||||
|
||||
router.post('/update', accountValidator.img(),
|
||||
accountValidator.bio(),
|
||||
accountValidator.signature(),
|
||||
accountValidator.pass('passChange.oldPass'),
|
||||
accountValidator.securePass('passChange.newPass'),
|
||||
accountValidator.pass('passChange.confirmPass'), updateController.post);
|
||||
|
||||
router.post('/delete', accountValidator.pass(), deleteController.post);
|
||||
|
||||
module.exports = router;
|
||||
37
src/routers/api/channelRouter.js
Normal file
37
src/routers/api/channelRouter.js
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//npm imports
|
||||
const { Router } = require('express');
|
||||
|
||||
//local imports
|
||||
const {channelValidator} = require("../../utils/validators");
|
||||
const registerController = require("../../controllers/api/channel/registerController");
|
||||
const listController = require("../../controllers/api/channel/listController");
|
||||
const settingsController = require("../../controllers/api/channel/settingsController");
|
||||
const deleteController = require("../../controllers/api/channel/deleteController");
|
||||
|
||||
//globals
|
||||
const router = Router();
|
||||
|
||||
//routing functions
|
||||
router.post('/register', channelValidator.name(), channelValidator.description(), channelValidator.thumbnail(), registerController.post);
|
||||
router.get('/list', listController.get);
|
||||
router.get('/settings', channelValidator.name('chanName'), settingsController.get);
|
||||
router.post('/settings', channelValidator.name('chanName'), channelValidator.settingsMap(), settingsController.post);
|
||||
router.post('/delete', channelValidator.name('chanName'), channelValidator.name('confirm'),deleteController.post);
|
||||
|
||||
module.exports = router;
|
||||
31
src/routers/apiRouter.js
Normal file
31
src/routers/apiRouter.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//npm imports
|
||||
const { Router } = require('express');
|
||||
|
||||
//local imports
|
||||
const accountRouter = require("./api/accountRouter");
|
||||
const channelRouter = require("./api/channelRouter");
|
||||
|
||||
//globals
|
||||
const router = Router();
|
||||
|
||||
//routing functions
|
||||
router.use('/account', accountRouter);
|
||||
router.use('/channel', channelRouter);
|
||||
|
||||
module.exports = router;
|
||||
32
src/routers/channelRouter.js
Normal file
32
src/routers/channelRouter.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//npm imports
|
||||
const { Router } = require('express');
|
||||
|
||||
|
||||
//local imports
|
||||
const channelController = require("../controllers/channelController");
|
||||
const channelSettingsController = require("../controllers/channelSettingsController");
|
||||
|
||||
//globals
|
||||
const router = Router();
|
||||
|
||||
//routing functions
|
||||
router.get('/*/settings', channelSettingsController.get);
|
||||
router.get('/*/', channelController.get);
|
||||
|
||||
module.exports = router;
|
||||
30
src/routers/indexRouter.js
Normal file
30
src/routers/indexRouter.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//npm imports
|
||||
const { Router } = require('express');
|
||||
|
||||
|
||||
//local imports
|
||||
const indexController = require("../controllers/indexController");
|
||||
|
||||
//globals
|
||||
const router = Router();
|
||||
|
||||
//routing functions
|
||||
router.get('/', indexController.get);
|
||||
|
||||
module.exports = router;
|
||||
30
src/routers/newChannelRouter.js
Normal file
30
src/routers/newChannelRouter.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//npm imports
|
||||
const { Router } = require('express');
|
||||
|
||||
|
||||
//local imports
|
||||
const newChannelController = require("../controllers/newChannelController");
|
||||
|
||||
//globals
|
||||
const router = Router();
|
||||
|
||||
//routing functions
|
||||
router.get('/', newChannelController.get);
|
||||
|
||||
module.exports = router;
|
||||
30
src/routers/profileRouter.js
Normal file
30
src/routers/profileRouter.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//npm imports
|
||||
const { Router } = require('express');
|
||||
|
||||
|
||||
//local imports
|
||||
const profileController = require("../controllers/profileController");
|
||||
|
||||
//globals
|
||||
const router = Router();
|
||||
|
||||
//routing functions
|
||||
router.get('/*', profileController.get);
|
||||
|
||||
module.exports = router;
|
||||
30
src/routers/registerRouter.js
Normal file
30
src/routers/registerRouter.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//npm imports
|
||||
const { Router } = require('express');
|
||||
|
||||
|
||||
//local imports
|
||||
const registerController = require("../controllers/registerController");
|
||||
|
||||
//globals
|
||||
const router = Router();
|
||||
|
||||
//routing functions
|
||||
router.get('/', registerController.get);
|
||||
|
||||
module.exports = router;
|
||||
127
src/schemas/channelSchema.js
Normal file
127
src/schemas/channelSchema.js
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//NPM Imports
|
||||
const {mongoose} = require('mongoose');
|
||||
|
||||
//Local Imports
|
||||
const statSchema = require('./statSchema.js');
|
||||
|
||||
const channelSchema = new mongoose.Schema({
|
||||
id: {
|
||||
type: mongoose.SchemaTypes.Number,
|
||||
required: true
|
||||
},
|
||||
name: {
|
||||
type: mongoose.SchemaTypes.String,
|
||||
required: true,
|
||||
default: 0
|
||||
},
|
||||
description: {
|
||||
type: mongoose.SchemaTypes.String,
|
||||
required: true,
|
||||
default: 0
|
||||
},
|
||||
thumbnail: {
|
||||
type: mongoose.SchemaTypes.String,
|
||||
required: true,
|
||||
default: "img/johnny.png"
|
||||
},
|
||||
settings: {
|
||||
hidden: {
|
||||
type: mongoose.SchemaTypes.Boolean,
|
||||
required: true,
|
||||
default: true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
channelSchema.pre('save', async function (next){
|
||||
if(this.isModified("name")){
|
||||
if(this.name.match(/^[a-z0-9_\-.]+$/i) == null){
|
||||
throw new Error("Username must only contain alpha-numerics and the following symbols: '-_.'");
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
//statics
|
||||
channelSchema.statics.register = async function(channelObj){
|
||||
const {name, description, thumbnail} = channelObj;
|
||||
|
||||
const chanDB = await this.findOne({ name });
|
||||
|
||||
if(chanDB){
|
||||
throw new Error("Channel name already taken!");
|
||||
}else{
|
||||
const id = await statSchema.incrementChannelCount();
|
||||
const newChannel = await this.create((thumbnail ? {id, name, description, thumbnail} : {id, name, description}));
|
||||
}
|
||||
}
|
||||
|
||||
channelSchema.statics.getChannelList = async function(includeHidden = false){
|
||||
const chanDB = await this.find({});
|
||||
var chanGuide = [];
|
||||
|
||||
//crawl through channels
|
||||
chanDB.forEach((channel) => {
|
||||
//For each channel, push an object with only the information we need to the channel guide
|
||||
if(!channel.settings.hidden || includeHidden){
|
||||
chanGuide.push({
|
||||
id: channel.id,
|
||||
name: channel.name,
|
||||
description: channel.description,
|
||||
thumbnail: channel.thumbnail
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//return the channel guide
|
||||
return chanGuide;
|
||||
}
|
||||
|
||||
//methods
|
||||
channelSchema.methods.updateSettings = async function(settingsMap){
|
||||
settingsMap.forEach((value, key) => {
|
||||
if(this.settings[key] == null){
|
||||
throw new Error("Invalid channel setting.");
|
||||
}
|
||||
|
||||
this.settings[key] = value;
|
||||
})
|
||||
|
||||
await this.save();
|
||||
|
||||
return this.settings;
|
||||
}
|
||||
|
||||
channelSchema.methods.nuke = async function(confirm){
|
||||
if(confirm == "" || confirm == null){
|
||||
throw new Error("Empty Confirmation String!");
|
||||
}else if(confirm != this.name){
|
||||
throw new Error("Bad Confirmation String!");
|
||||
}
|
||||
|
||||
//Annoyingly there isnt a good way to do this from 'this'
|
||||
var oldUser = await module.exports.deleteOne(this);
|
||||
|
||||
if(oldUser == null){
|
||||
throw new Error("Server Error: Unable to delete channel! Please report this error to your server administrator, and with timestamp.");
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = mongoose.model("channel", channelSchema);
|
||||
104
src/schemas/statSchema.js
Normal file
104
src/schemas/statSchema.js
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//NPM Imports
|
||||
const {mongoose} = require('mongoose');
|
||||
|
||||
//Local Imports
|
||||
const config = require('./../../config.json');
|
||||
|
||||
const statSchema = new mongoose.Schema({
|
||||
//This does NOT handle deleted accounts/channels. Use userModel.estimatedDocumentCount() for number of active users.
|
||||
userCount: {
|
||||
type: mongoose.SchemaTypes.Number,
|
||||
required: true,
|
||||
default: 0
|
||||
},
|
||||
channelCount: {
|
||||
type: mongoose.SchemaTypes.Number,
|
||||
required: true,
|
||||
default: 0
|
||||
},
|
||||
launchCount: {
|
||||
type: mongoose.SchemaTypes.Number,
|
||||
required: true,
|
||||
default: 0
|
||||
}
|
||||
});
|
||||
|
||||
//statics
|
||||
statSchema.statics.getStats = async function(){
|
||||
//Get the first document we find
|
||||
var stats = await this.findOne({});
|
||||
|
||||
if(stats){
|
||||
//If we found something then the statistics document exist and this is it,
|
||||
//So long as no one else has fucked with the database it should be the only one. (is this forshadowing for a future bug?)
|
||||
return stats;
|
||||
}else{
|
||||
//Otherwise this is the first launch of the install, say hello
|
||||
console.log("First launch detected! Initializing statistics document in Database!");
|
||||
|
||||
//create and save the statistics document
|
||||
stats = await this.create({});
|
||||
await stats.save();
|
||||
|
||||
//live up to the name of the function
|
||||
return stats;
|
||||
}
|
||||
}
|
||||
|
||||
statSchema.statics.incrementLaunchCount = async function(){
|
||||
//get our statistics document
|
||||
const stats = await this.getStats();
|
||||
|
||||
//increment counter and save
|
||||
stats.launchCount++;
|
||||
stats.save();
|
||||
|
||||
//print bootup message to console.
|
||||
console.log(`${config.instanceName}(Powered by Canopy) initialized. This server has booted ${stats.launchCount} time${stats.launchCount == 1 ? '' : 's'}.`)
|
||||
}
|
||||
|
||||
statSchema.statics.incrementUserCount = async function(){
|
||||
//get our statistics document
|
||||
const stats = await this.getStats();
|
||||
//temporarily keep old count so we can return it for the users ID
|
||||
const oldCount = stats.userCount;
|
||||
|
||||
//increment counter and save
|
||||
stats.userCount++;
|
||||
stats.save();
|
||||
|
||||
//return the count from beggining of function for user ID
|
||||
return oldCount;
|
||||
}
|
||||
|
||||
statSchema.statics.incrementChannelCount = async function(){
|
||||
//get our statistics document
|
||||
const stats = await this.getStats();
|
||||
//temporarily keep old count so we can return it for the channel ID
|
||||
const oldCount = stats.channelCount;
|
||||
|
||||
//increment counter and save
|
||||
stats.channelCount++;
|
||||
stats.save();
|
||||
|
||||
//return the count from beggining of function for channel ID
|
||||
return oldCount;
|
||||
}
|
||||
|
||||
module.exports = mongoose.model("statistics", statSchema);
|
||||
210
src/schemas/userSchema.js
Normal file
210
src/schemas/userSchema.js
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//NPM Imports
|
||||
const {mongoose} = require('mongoose');
|
||||
|
||||
//local imports
|
||||
const server = require('../server.js');
|
||||
const statSchema = require('./statSchema.js');
|
||||
const hashUtil = require('../utils/hashUtils');
|
||||
|
||||
|
||||
const userSchema = new mongoose.Schema({
|
||||
id: {
|
||||
type: mongoose.SchemaTypes.Number,
|
||||
required: true
|
||||
},
|
||||
user: {
|
||||
type: mongoose.SchemaTypes.String,
|
||||
required: true,
|
||||
},
|
||||
pass: {
|
||||
type: mongoose.SchemaTypes.String,
|
||||
required: true
|
||||
},
|
||||
email: {
|
||||
type: mongoose.SchemaTypes.String
|
||||
},
|
||||
date: {
|
||||
type: mongoose.SchemaTypes.Date,
|
||||
required: true,
|
||||
default: new Date()
|
||||
},
|
||||
tokes: {
|
||||
type: mongoose.SchemaTypes.Map,
|
||||
required: true,
|
||||
default: new Map()
|
||||
},
|
||||
img: {
|
||||
type: mongoose.SchemaTypes.String,
|
||||
required: true,
|
||||
default: "img/johnny.png"
|
||||
},
|
||||
bio: {
|
||||
type: mongoose.SchemaTypes.String,
|
||||
required: true,
|
||||
default: "Bio not set!"
|
||||
},
|
||||
signature: {
|
||||
type: mongoose.SchemaTypes.String,
|
||||
required: true,
|
||||
default: "Signature not set!"
|
||||
}
|
||||
});
|
||||
|
||||
//This is one of those places where you really DON'T want to use an arrow function over an anonymous one!
|
||||
userSchema.pre('save', async function (next){
|
||||
if(this.isModified("pass")){
|
||||
this.pass = hashUtil.hashPassword(this.pass);
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
//statics
|
||||
userSchema.statics.register = async function(userObj){
|
||||
const {user, pass, passConfirm, email} = userObj;
|
||||
|
||||
if(pass == passConfirm){
|
||||
const userDB = await this.findOne({$or: email ? [{user}, {email}] : [{user}]});
|
||||
|
||||
if(userDB){
|
||||
throw new Error("User name/email already taken!");
|
||||
}else{
|
||||
const id = await statSchema.incrementUserCount();
|
||||
const newUser = await this.create({id, user, pass, email});
|
||||
}
|
||||
}else{
|
||||
throw new Error("Confirmation password doesn't match!");
|
||||
}
|
||||
}
|
||||
|
||||
userSchema.statics.authenticate = async function(user, pass){
|
||||
//check for missing pass
|
||||
if(!user || !pass){
|
||||
throw new Error("Missing user/pass.");
|
||||
}
|
||||
|
||||
//get the user if it exists
|
||||
const userDB = await this.findOne({ user });
|
||||
|
||||
//if not scream and shout
|
||||
if(!userDB){
|
||||
badLogin();
|
||||
}
|
||||
|
||||
//Check our password is correct
|
||||
if(userDB.checkPass(pass)){
|
||||
return userDB;
|
||||
}else{
|
||||
//if not scream and shout
|
||||
badLogin();
|
||||
}
|
||||
|
||||
//standardize bad login response so it's unknowin which is bad for security reasons.
|
||||
function badLogin(){
|
||||
throw new Error("Bad Username or Password.");
|
||||
}
|
||||
}
|
||||
|
||||
//methods
|
||||
userSchema.methods.checkPass = function(pass){
|
||||
return hashUtil.comparePassword(pass, this.pass);
|
||||
}
|
||||
|
||||
userSchema.methods.getAuthenticatedSessions = async function(){
|
||||
var returnArr = [];
|
||||
|
||||
//retrieve active sessions (they really need to implement this shit async already)
|
||||
return new Promise((resolve) => {
|
||||
server.store.all((err, sessions) => {
|
||||
//You guys ever hear of a 'not my' problem? Fucking y33tskies lmao, better use a try/catch
|
||||
if(err){
|
||||
throw err;
|
||||
|
||||
}
|
||||
|
||||
//crawl through active sessions
|
||||
sessions.forEach((session) => {
|
||||
//if a session matches the current user
|
||||
if(session.user.id == this.id){
|
||||
//we return it
|
||||
returnArr.push(session);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
resolve(returnArr);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
//note: if you gotta call this from a request authenticated by it's user, make sure to kill that session first!
|
||||
userSchema.methods.killAllSessions = async function(){
|
||||
//get authenticated sessions
|
||||
var sessions = await this.getAuthenticatedSessions();
|
||||
|
||||
//crawl through and kill all sessions
|
||||
sessions.forEach((session) => {
|
||||
server.store.destroy(session.seshid);
|
||||
});
|
||||
}
|
||||
|
||||
userSchema.methods.passwordReset = async function(passChange){
|
||||
if(this.checkPass(passChange.oldPass)){
|
||||
if(passChange.newPass == passChange.confirmPass){
|
||||
//Note: We don't have to worry about hashing here because the schema is written to do it auto-magically
|
||||
this.pass = passChange.newPass;
|
||||
|
||||
//Save our password
|
||||
await this.save();
|
||||
|
||||
//Kill all authed sessions for security purposes
|
||||
await this.killAllSessions();
|
||||
}else{
|
||||
//confirmation pass doesn't match
|
||||
throw new Error("Mismatched confirmation password!");
|
||||
}
|
||||
}else{
|
||||
//Old password wrong
|
||||
throw new Error("Incorrect Password!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
userSchema.methods.nuke = async function(pass){
|
||||
if(pass == "" || pass == null){
|
||||
throw new Error("No confirmation password!");
|
||||
}
|
||||
|
||||
if(this.checkPass(pass)){
|
||||
//Annoyingly there isnt a good way to do this from 'this'
|
||||
var oldUser = await module.exports.deleteOne(this);
|
||||
|
||||
if(oldUser){
|
||||
await this.killAllSessions();
|
||||
}else{
|
||||
throw new Error("Server Error: Unable to delete account! Please report this error to your server administrator, and with timestamp.");
|
||||
}
|
||||
}else{
|
||||
throw new Error("Bad pass.");
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = mongoose.model("user", userSchema);
|
||||
111
src/server.js
Normal file
111
src/server.js
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//Define NPM imports
|
||||
const express = require('express');
|
||||
const session = require('express-session');
|
||||
const {createServer } = require('http');
|
||||
const { Server } = require('socket.io');
|
||||
const path = require('path');
|
||||
const mongoStore = require('connect-mongo');
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
//Define Local Imports
|
||||
const statModel = require('./schemas/statSchema');
|
||||
const channelManager = require('./app/channel/channelManager');
|
||||
const indexRouter = require('./routers/indexRouter');
|
||||
const registerRouter = require('./routers/registerRouter');
|
||||
const profileRouter = require('./routers/profileRouter');
|
||||
const adminPanelRouter = require('./routers/adminPanelRouter');
|
||||
const channelRouter = require('./routers/channelRouter');
|
||||
const newChannelRouter = require('./routers/newChannelRouter');
|
||||
const apiRouter = require('./routers/apiRouter');
|
||||
|
||||
//Define Config
|
||||
const config = require('../config.json');
|
||||
const port = config.port;
|
||||
const dbUrl = `mongodb://${config.db.user}:${config.db.pass}@${config.db.address}:${config.db.port}/${config.db.database}`;
|
||||
|
||||
//Define Node JS
|
||||
const app = express();
|
||||
|
||||
//Define session-store (exported so we can kill sessions from user schema)
|
||||
module.exports.store = mongoStore.create({mongoUrl: dbUrl});
|
||||
|
||||
//define sessionMiddleware
|
||||
const sessionMiddleware = session({
|
||||
secret: config.sessionSecret,
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
store: module.exports.store
|
||||
});
|
||||
|
||||
//Define http and socket.io servers
|
||||
const httpServer = createServer(app);
|
||||
const io = new Server(httpServer, {});
|
||||
|
||||
//Connect mongoose to the database
|
||||
mongoose.set("sanitizeFilter", true).connect(dbUrl).then(() => {
|
||||
console.log("Connected to DB");
|
||||
}).catch((err) => {
|
||||
console.error("Unable to connecto to DB: ");
|
||||
console.error(err);
|
||||
process.exit();
|
||||
});
|
||||
|
||||
//Set View Engine
|
||||
app.set('view engine', 'ejs');
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
//Middlware
|
||||
//Enable Express
|
||||
app.use(express.json());
|
||||
|
||||
//Enable Express-Sessions
|
||||
app.use(sessionMiddleware);
|
||||
|
||||
//Enable Express-Session w/ Socket.IO
|
||||
io.engine.use(sessionMiddleware);
|
||||
|
||||
//Routes
|
||||
//Humie-Friendly
|
||||
app.use('/', indexRouter);
|
||||
app.use('/register', registerRouter);
|
||||
app.use('/profile', profileRouter);
|
||||
app.use('/adminPanel', adminPanelRouter);
|
||||
app.use('/c', channelRouter);
|
||||
app.use('/newChannel', newChannelRouter);
|
||||
//Bot-Ready
|
||||
app.use('/api', apiRouter);
|
||||
|
||||
//3rd-Party Browser-Side Libraries
|
||||
app.use('/lib/bootstrap-icons',express.static(path.join(__dirname, '../node_modules/bootstrap-icons')));
|
||||
app.use('/lib/socket.io',express.static(path.join(__dirname, '../node_modules/socket.io/client-dist')));
|
||||
app.use('/lib/validator',express.static(path.join(__dirname, '../node_modules/validator')));
|
||||
|
||||
//Static File Server
|
||||
app.use(express.static(path.join(__dirname, '../www')));
|
||||
|
||||
//Increment launch counter
|
||||
statModel.incrementLaunchCount();
|
||||
|
||||
//Hand over general-namespace socket.io connections to the channel manager
|
||||
io.on("connection", (socket) => {channelManager.handleConnection(io, socket)} );
|
||||
|
||||
//Listen Function
|
||||
httpServer.listen(port, () => {
|
||||
console.log(`Opening port ${port}`);
|
||||
});
|
||||
26
src/utils/hashUtils.js
Normal file
26
src/utils/hashUtils.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
const bcrypt = require('bcrypt');
|
||||
|
||||
module.exports.hashPassword = function(pass){
|
||||
const salt = bcrypt.genSaltSync();
|
||||
return bcrypt.hashSync(pass, salt);
|
||||
}
|
||||
|
||||
module.exports.comparePassword = function(pass, hash){
|
||||
return bcrypt.compareSync(pass, hash);
|
||||
}
|
||||
22
src/utils/loggerUtils.js
Normal file
22
src/utils/loggerUtils.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//At some point this will be a bit more advanced, right now it's just a placeholder :P
|
||||
module.exports.exceptionHandler = function(res, err){
|
||||
//if not yell at the browser for fucking up, and tell it what it did wrong.
|
||||
res.status(400);
|
||||
return res.send({errors: [{type: "Caught Exception", msg: err.message, date: new Date()}]});
|
||||
}
|
||||
48
src/utils/sessionUtils.js
Normal file
48
src/utils/sessionUtils.js
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//local imports
|
||||
const userModel = require('../schemas/userSchema.js');
|
||||
|
||||
//this module is good for keeping wrappers for userModel and other shit in that does more session handling than database access/modification.
|
||||
|
||||
module.exports.authenticateSession = async function(user, pass, req){
|
||||
|
||||
//Authenticate the session
|
||||
userDB = await userModel.authenticate(user, pass);
|
||||
|
||||
//Tattoo the session with user and metadata
|
||||
//unfortunately store.all() does not return sessions w/ their ID so we had to improvise...
|
||||
//Not sure if this is just how connect-mongo is implemented or if it's an express issue, but connect-mongodb-session seems to not implement the all() function what so ever...
|
||||
req.session.seshid = req.session.id;
|
||||
req.session.authdate = new Date();
|
||||
req.session.authip = req.ip;
|
||||
req.session.user = {
|
||||
user: userDB.user,
|
||||
id: userDB.id
|
||||
}
|
||||
|
||||
|
||||
//userDB.activeSessions.push(sessionData);
|
||||
await userDB.save();
|
||||
|
||||
//return user
|
||||
return userDB.user;
|
||||
}
|
||||
|
||||
module.exports.killSession = async function(session){
|
||||
session.destroy();
|
||||
}
|
||||
50
src/utils/validators.js
Normal file
50
src/utils/validators.js
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//NPM Imports
|
||||
const { check, body, checkSchema, checkExact} = require('express-validator');
|
||||
|
||||
module.exports.accountValidator = {
|
||||
user: (field = 'user') => body(field).escape().trim().isLength({min: 1, max: 22}),
|
||||
|
||||
//Password security requirements may change over time, therefore we should only validate against strongPassword() when creating new accounts
|
||||
//that way we don't break old ones upon change
|
||||
pass: (field = 'pass') => body(field).notEmpty().escape().trim(),
|
||||
securePass: (field) => this.accountValidator.pass(field).isStrongPassword({minLength: 8, minLowercase: 1, minUppercase: 1, minNumbers: 1, minSymbols: 1}),
|
||||
|
||||
email: (field = 'email') => body(field).optional().isEmail().normalizeEmail(),
|
||||
|
||||
img: (field = 'img') => body(field).optional().isURL({require_tld: false}).trim(),
|
||||
|
||||
signature: (field = 'signature') => body(field).optional().escape().trim().isLength({min: 1, max: 150}),
|
||||
|
||||
bio: (field = 'bio') => body(field).optional().escape().trim().isLength({min: 1, max: 1000}),
|
||||
}
|
||||
|
||||
module.exports.channelValidator = {
|
||||
name: (field = 'name') => check(field).escape().trim().isLength({min: 1, max: 50}),
|
||||
|
||||
description: (field = 'description') => body(field).escape().trim().isLength({min: 1, max: 1000}),
|
||||
|
||||
thumbnail: (field = 'thumbnail') => this.accountValidator.img(field),
|
||||
|
||||
settingsMap: () => checkExact(checkSchema({
|
||||
'settingsMap.hidden': {
|
||||
optional: true,
|
||||
isBoolean: true,
|
||||
}
|
||||
}))
|
||||
}
|
||||
63
src/views/adminPanel.ejs
Normal file
63
src/views/adminPanel.ejs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<!--Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<%- include('partial/styles', {instance, user}); %>
|
||||
<link rel="stylesheet" type="text/css" href="/css/adminPanel.css">
|
||||
<title><%= instance %> - Admin Panel</title>
|
||||
</head>
|
||||
<body>
|
||||
<%- include('partial/navbar', {user}); %>
|
||||
<div id="admin-channel-list-div" class="admin-channel-list">
|
||||
<h3>Channel List:</h3>
|
||||
<table id="admin-channel-list-table" class="admin-channel-list">
|
||||
<tr id="admin-channel-list-entry-title" class="admin-channel-list-entry">
|
||||
<td id="admin-channel-list-entry-img-title" class="admin-channel-list-entry admin-channel-list-entry-title admin-channel-list-entry-item admin-channel-list-entry-img-row">
|
||||
<h3>Img</h3>
|
||||
</td>
|
||||
<td id="admin-channel-list-entry-name-title" class="admin-channel-list-entry admin-channel-list-entry-title admin-channel-list-entry-item admin-channel-list-entry-name-row">
|
||||
<h3>Name</h3>
|
||||
</td>
|
||||
<td id="admin-channel-list-entry-description-title" class="admin-channel-list-entry admin-channel-list-entry-title admin-channel-list-entry-item">
|
||||
<h3>Description</h3>
|
||||
</td>
|
||||
</tr>
|
||||
<% chanGuide.forEach((channel) => { %>
|
||||
<tr id="admin-channel-list-entry-<%- channel.name %>" class="admin-channel-list-entry">
|
||||
<td id="admin-channel-list-entry-img-<%- channel.name %>" class="admin-channel-list-entry admin-channel-list-entry-item admin-channel-list-entry-img-row">
|
||||
<a href="/c/<%- channel.name %>" class="admin-channel-list-entry admin-channel-list-entry-item">
|
||||
<img id="admin-channel-list-entry-img-<%- channel.name %>" class="admin-channel-list-entry admin-channel-list-entry-item" src="<%- channel.thumbnail %>">
|
||||
</a>
|
||||
</td>
|
||||
<td id="admin-channel-list-entry-name-<%- channel.name %>" class="admin-channel-list-entry admin-channel-list-entry-item admin-channel-list-entry-name-row">
|
||||
<a href="/c/<%- channel.name %>" class="admin-channel-list-entry admin-channel-list-entry-item">
|
||||
<%- channel.name %>
|
||||
</a>
|
||||
</td>
|
||||
<td id="admin-channel-list-entry-description-<%- channel.name %>" class="admin-channel-list-entry admin-channel-list-entry-item">
|
||||
<p><%- channel.description %></p>
|
||||
</td>
|
||||
</tr>
|
||||
<% }); %>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
<footer>
|
||||
<%- include('partial/scripts', {user}); %>
|
||||
<script src="js/adminPanel.js"></script>
|
||||
</footer>
|
||||
</html>
|
||||
101
src/views/channel.ejs
Normal file
101
src/views/channel.ejs
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
<!--Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<%- include('partial/styles', {instance, user}); %>
|
||||
<link rel="stylesheet" type="text/css" href="/css/channel.css">
|
||||
<title><%= instance %> - *DISCONNECTED*</title>
|
||||
</head>
|
||||
<body>
|
||||
<%- include('partial/navbar', {user}); %>
|
||||
<div class="channel" id="channel-flexbox">
|
||||
<div class="media-panel" id="media-panel-div">
|
||||
<div class="media-panel panel-head-div" id="media-panel-head-div">
|
||||
<i class="media-panel panel-head-element bi-caret-down-fill" id="media-panel-div-toggle-icon"></i>
|
||||
<p class="media-panel panel-head-element" id="media-panel-title-paragraph">Currently Playing: NULL</p>
|
||||
<span class="media-panel panel-head-spacer-span" id="media-panel-head-spacer-span"></span>
|
||||
<i class="media-panel panel-head-element bi-arrow-repeat" id="media-panel-sync-icon"></i>
|
||||
<i class="media-panel panel-head-element bi-aspect-ratio-fill" id="media-panel-aspect-lock-icon"></i>
|
||||
<i class="media-panel panel-head-element bi-film" id="media-panel-cinema-mode-icon"></i>
|
||||
<i class="media-panel panel-head-element bi-arrows-vertical" id="media-panel-flip-vertical-icon"></i>
|
||||
<i class="media-panel panel-head-element bi-arrows" id="media-panel-flip-horizontal-icon"></i>
|
||||
<i class="media-panel panel-head-element bi-arrow-clockwise" id="media-panel-reload-icon"></i>
|
||||
<i class="media-panel panel-head-element bi-chat-right-dots-fill" id="media-panel-show-chat-icon"></i>
|
||||
</div>
|
||||
<video src="/video/static.webm" class="media-panel" id="media-panel-video" muted loop autoplay></video>
|
||||
</div>
|
||||
<div class="chat-panel" id="chat-panel-div">
|
||||
<div class="drag-handle" id="chat-panel-drag-handle">
|
||||
</div>
|
||||
<div class="chat-panel panel-head-div" id="chat-panel-head-div">
|
||||
<i class="chat-panel panel-head-element bi-film" id="chat-panel-show-video-icon"></i>
|
||||
<i class="chat-panel panel-head-element bi-caret-down-fill" id="chat-panel-div-hide"></i>
|
||||
<select class="chat-panel panel-head-element" id="chat-panel-high-level-select">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
<option value="6">6</option>
|
||||
<option value="7">7</option>
|
||||
<option value="8">8</option>
|
||||
<option value="9">9</option>
|
||||
<option value="10">10</option>
|
||||
</select>
|
||||
<p class="chat-panel panel-head-element" id="chat-panel-high-level-paragraph">/10</p>
|
||||
<select class="chat-panel panel-head-element" id="chat-panel-flair-select">
|
||||
<option>Flair</option>
|
||||
</select>
|
||||
<span class="chat-panel panel-head-spacer-span" id="chat-panel-head-spacer-span"></span>
|
||||
<p class="chat-panel panel-head-element" id="chat-panel-user-count">NULL Users</p>
|
||||
<i class="chat-panel panel-head-element bi-caret-down-fill" id="chat-panel-users-toggle"></i>
|
||||
</div>
|
||||
<div class="chat-panel" id="chat-panel-main-div">
|
||||
<div class="chat-panel" id="chat-panel-multipanel-div">
|
||||
</div>
|
||||
<div class="chat-panel" id="chat-area">
|
||||
<div class="chat-panel" id="chat-panel-buffer-div">
|
||||
</div>
|
||||
<div class="chat-panel" id="chat-panel-control-div">
|
||||
<i class="chat-panel chat-panel-control bi-gear-fill" id="chat-panel-settings-icon"></i>
|
||||
<i class="chat-panel chat-panel-control bi-magic" id="chat-panel-admin-icon"></i>
|
||||
<i class="chat-panel chat-panel-control bi-images" id="chat-panel-emote-icon"></i>
|
||||
<input class="chat-panel chat-panel-control" id="chat-panel-prompt" placeholder="Chat...">
|
||||
<button class="chat-panel chat-panel-control" id="chat-panel-send-button">Send</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-panel" id="chat-panel-users-div">
|
||||
<div class="drag-handle" id="chat-panel-users-drag-handle">
|
||||
</div>
|
||||
<div class="chat-panel" id="chat-panel-users-list-div">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<footer>
|
||||
<%- include('partial/scripts', {user}); %>
|
||||
<script src="/lib/socket.io/socket.io.min.js"></script>
|
||||
<script src="/js/channel/chat.js"></script>
|
||||
<script src="/js/channel/userlist.js"></script>
|
||||
<script src="/js/channel/player.js"></script>
|
||||
<script src="/js/channel/channel.js"></script>
|
||||
</footer>
|
||||
</html>
|
||||
37
src/views/channelSettings.ejs
Normal file
37
src/views/channelSettings.ejs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<!--Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<%- include('partial/styles', {instance, user}); %>
|
||||
<link rel="stylesheet" type="text/css" href="/css/newChannel.css">
|
||||
<title><%= instance %> - Channel Settings: <%= channel.name %></title>
|
||||
</head>
|
||||
<body>
|
||||
<%- include('partial/navbar', {user}); %>
|
||||
<form action="javascript:">
|
||||
<span>
|
||||
<label>Hidden:</label>
|
||||
<input id="channel-hidden" type="checkbox" <% if(channel.settings.hidden){ %> checked <% } %>>
|
||||
</span>
|
||||
</form>
|
||||
<a href="javascript:" id="channel-delete">Delete Channel</a>
|
||||
<footer>
|
||||
<%- include('partial/scripts', {user}); %>
|
||||
<script src="/js/channelSettings.js"></script>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
41
src/views/index.ejs
Normal file
41
src/views/index.ejs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<!--Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<%- include('partial/styles', {instance, user}); %>
|
||||
<link rel="stylesheet" type="text/css" href="css/index.css">
|
||||
<title><%= instance %></title>
|
||||
</head>
|
||||
<body>
|
||||
<%- include('partial/navbar', {user}); %>
|
||||
<h3><a href="/newchannel">Start a new channel...</a></h3>
|
||||
<div id="channel-guide-div" class="channel-guide">
|
||||
<% chanGuide.forEach((channel) => { %>
|
||||
<div id="channel-guide-entry-<%- channel.name %>" class="channel-guide-entry">
|
||||
<a href="/c/<%- channel.name %>" class="channel-guide-entry channel-guide-entry-item"><img id="channel-guide-entry-img-<%- channel.name %>" class="channel-guide-entry channel-guide-entry-item" src="<%- channel.thumbnail %>"></a>
|
||||
<h3 id="channel-guide-entry-name-<%- channel.name %>" class="channel-guide-entry channel-guide-entry-item"><a href="/c/<%- channel.name %>" class="channel-guide-entry channel-guide-entry-item"><%- channel.name %></a></h3>
|
||||
<span id="channel-guide-entry-description-span-<%- channel.name %>" class="channel-guide-entry channel-guide-entry-item">
|
||||
<p id="channel-guide-entry-description-<%- channel.name %>" class="channel-guide-entry channel-guide-entry-item"><%- channel.description %></h3>
|
||||
</span>
|
||||
</div>
|
||||
<% }); %>
|
||||
</div>
|
||||
</body>
|
||||
<footer>
|
||||
<%- include('partial/scripts', {user}); %>
|
||||
</footer>
|
||||
</html>
|
||||
38
src/views/newChannel.ejs
Normal file
38
src/views/newChannel.ejs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<!--Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<%- include('partial/styles', {instance, user}); %>
|
||||
<link rel="stylesheet" type="text/css" href="/css/newChannel.css">
|
||||
<title><%= instance %> - New Channel</title>
|
||||
</head>
|
||||
<body>
|
||||
<%- include('partial/navbar', {user}); %>
|
||||
<form action="javascript:">
|
||||
<label>Channel Name:</label>
|
||||
<input id="register-channel-name" placeholder="Required">
|
||||
<label>Description:</label>
|
||||
<input id="register-description" placeholder="Required">
|
||||
<label>Thumbnail:</label>
|
||||
<input id="register-thumbnail" placeholder="Required">
|
||||
</form>
|
||||
</body>
|
||||
<footer>
|
||||
<%- include('partial/scripts', {user}); %>
|
||||
<script src="js/newChannel.js"></script>
|
||||
</footer>
|
||||
</html>
|
||||
27
src/views/partial/navbar.ejs
Normal file
27
src/views/partial/navbar.ejs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<!--Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
||||
<div id="navbar">
|
||||
<p class="navbar-item" id="instance-title"><a href="/" class="navbar-item"><%= instance %></a></p>
|
||||
<span class="navbar-item" id="right-controls">
|
||||
<% if(user){ %>
|
||||
<p class="navbar-item">Welcome, <a class="navbar-item" href="/profile"><%= user.user %></a> - <a href="/adminPanel" title="Admin Panel" class="bi bi-server navbar-item"></a> <a class="navbar-item" href="javascript:" id="logout-button">logout</a></p>
|
||||
<% }else{ %>
|
||||
<input class="navbar-item login-prompt" id="username-prompt" placeholder="username">
|
||||
<input class="navbar-item login-prompt" id="password-prompt" placeholder="password" type="password">
|
||||
<p class="navbar-item"><a class="navbar-item" href="javascript:" id="login-button">Login</a> - <a class="navbar-item" href="/register">Register</a></p>
|
||||
<% } %>
|
||||
</span>
|
||||
</div>
|
||||
17
src/views/partial/scripts.ejs
Normal file
17
src/views/partial/scripts.ejs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<!--Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
||||
<script src="/js/utils.js"></script>
|
||||
<script src="/js/navbar.js"></script>
|
||||
18
src/views/partial/styles.ejs
Normal file
18
src/views/partial/styles.ejs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<!--Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
||||
<link rel="stylesheet" href="/lib/bootstrap-icons/font/bootstrap-icons.css">
|
||||
<link rel="stylesheet" type="text/css" href="/css/global.css">
|
||||
<link rel="stylesheet" type="text/css" href="/css/theme/movie-night.css">
|
||||
83
src/views/profile.ejs
Normal file
83
src/views/profile.ejs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
<!--Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<%- include('partial/styles', {instance, user}); %>
|
||||
<% var selfProfile = user ? profile ? profile.user == user.user : false : false %>
|
||||
<link rel="stylesheet" type="text/css" href="/css/profile.css">
|
||||
<% if(profile){ %>
|
||||
<title><%= instance %> - Profile: <%= profile.user %></title>
|
||||
<% } else { %>
|
||||
<title><%= instance %> - Profile: Logged Out</title>
|
||||
<% } %>
|
||||
</head>
|
||||
<body>
|
||||
<%- include('partial/navbar', {user}); %>
|
||||
<% if(profile){ %>
|
||||
<div class="profile" id="profile-div">
|
||||
<h1 class="profile-item" id="profile-username"><%= profile.user %></h1>
|
||||
<img class="profile-item" id="profile-img" src="<%= profile.img %>">
|
||||
<% if(selfProfile){ %>
|
||||
<p class="profile-item-edit">(<a class="profile-item-edit" id="profile-img-edit" href="javascript:">edit</a>)</p>
|
||||
<% } %>
|
||||
<p class="profile-item" id="profile-tokes">tokes: <%= profile.tokes %> (Not yet implemented)</p>
|
||||
|
||||
<span class="profile-item" id="profile-signature">
|
||||
<p class="profile-item profile-item-label" id="profile-signature-label">Signature: <span class="profile-content" id="profile-signature-content"><%= profile.signature %></span></p>
|
||||
<% if(selfProfile){ %>
|
||||
<p class="profile-item-edit">(<a class="profile-item-edit" id="profile-signature-edit" href="javascript:">edit</a>)</p>
|
||||
<% } %>
|
||||
</span>
|
||||
|
||||
<span class="profile-item" id="profile-bio">
|
||||
<p class="profile-item profile-item-label" id="profile-bio-label">Bio: <span class="profile-content" id="profile-bio-content"><%= profile.bio %></span></p>
|
||||
<% if(selfProfile){ %>
|
||||
<p class="profile-item-edit">(<a class="profile-item-edit" id="profile-bio-edit" href="javascript:">edit</a>)</p>
|
||||
<% } %>
|
||||
</span>
|
||||
|
||||
<p class="profile-item" id="profile-creation-date">Joined: <%= profile.date %></p>
|
||||
<div class="profile-item" id="profile-badge-shelf">
|
||||
<h3 class="profile-item" id="no-badge-label">Badgeless?</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% if(selfProfile){ %>
|
||||
<div class="account-settings" id="account-settings-div">
|
||||
<h3 class="account-settings" id="account-settings-label">Account Settings</h3>
|
||||
<span class="account-settings-password-reset" id="account-settings-password-reset-div">
|
||||
<h4 class="account-settings-password-reset" id="account-settings-password-reset-label">Password Reset:</h4>
|
||||
<input class="account-settings-password-reset" id="account-settings-password-reset-old" placeholder="Current Password" type="password">
|
||||
<input class="account-settings-password-reset" id="account-settings-password-reset-new" placeholder="New Password" type="password">
|
||||
<input class="account-settings-password-reset" id="account-settings-password-reset-confirm" placeholder="Confirm New Password" type="password">
|
||||
</span>
|
||||
<span class="account-settings" id="account-settings-delete">
|
||||
<a href="javascript:" class="account-settings" id="account-settings-delete-link">Delete Account</a>
|
||||
</span>
|
||||
</div>
|
||||
<% } %>
|
||||
<% }else if(user){ %>
|
||||
<h1 class="profile-item" id="profile-error-label">Profile not found!</h1>
|
||||
<% } else {%>
|
||||
<h1 class="profile-item" id="profile-error-label">Please login to view your profile!</h1>
|
||||
<% } %>
|
||||
</body>
|
||||
<footer>
|
||||
<%- include('partial/scripts', {user}); %>
|
||||
<script src="/js/profile.js"></script>
|
||||
</footer>
|
||||
</html>
|
||||
41
src/views/register.ejs
Normal file
41
src/views/register.ejs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<!--Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<%- include('partial/styles', {instance, user}); %>
|
||||
<link rel="stylesheet" type="text/css" href="/css/register.css">
|
||||
<title><%= instance %> - Account Registration</title>
|
||||
</head>
|
||||
<body>
|
||||
<%- include('partial/navbar', {user}); %>
|
||||
<form action="javascript:">
|
||||
<label>Username:</label>
|
||||
<input id="register-username" placeholder="Required">
|
||||
<label>Password:</label>
|
||||
<input id="register-password" placeholder="Required" type="password">
|
||||
<label>Confirm Password:</label>
|
||||
<input id="register-password-confirm" placeholder="Required" type="password">
|
||||
<label>Account Recovery Email:</label>
|
||||
<input id="register-email" placeholder="Optional">
|
||||
</form>
|
||||
</body>
|
||||
<footer>
|
||||
<%- include('partial/scripts', {user}); %>
|
||||
<script src="js/register.js"></script>
|
||||
</footer>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue