diff --git a/packages/music_spaces_server/.env-example b/packages/music_spaces_server/.env-example deleted file mode 100755 index d5dd5e8e..00000000 --- a/packages/music_spaces_server/.env-example +++ /dev/null @@ -1,2 +0,0 @@ -MAIN_API_URL="https://api.example.com" -SERVER_TOKEN="ABCDEFGH12345678" \ No newline at end of file diff --git a/packages/music_spaces_server/Dockerfile b/packages/music_spaces_server/Dockerfile deleted file mode 100755 index 169729a6..00000000 --- a/packages/music_spaces_server/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM node:16-bullseye - -RUN apt update -RUN apt install python -y -RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app - -WORKDIR /home/node/app -USER node - -EXPOSE 3020 - -COPY package.json ./ -COPY --chown=node:node . . - -RUN chmod -R 777 /home/node/app -RUN npm install -RUN npm run build - -CMD ["node", "/home/node/app/dist/index.js"] \ No newline at end of file diff --git a/packages/music_spaces_server/package.json b/packages/music_spaces_server/package.json deleted file mode 100755 index 8319d636..00000000 --- a/packages/music_spaces_server/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "@comty/music_spaces_server", - "version": "0.39.3", - "main": "dist/index.js", - "scripts": { - "build": "corenode-cli build", - "dev": "nodemon --ignore dist/ --exec corenode-node ./src/index.js" - }, - "license": "MIT", - "dependencies": { - "@foxify/events": "^2.1.0", - "axios": "^1.2.1", - "bcrypt": "5.0.1", - "corenode": "0.28.26", - "cors": "^2.8.5", - "dotenv": "^16.0.3", - "express": "^4.18.2", - "jsonwebtoken": "8.5.1", - "luxon": "^3.0.4", - "moment": "2.29.4", - "moment-timezone": "0.5.37", - "morgan": "^1.10.0", - "nanoid": "3.2.0", - "socket.io": "^4.5.4" - }, - "devDependencies": { - "cross-env": "^7.0.3", - "nodemon": "^2.0.15" - } -} diff --git a/packages/music_spaces_server/src/api.js b/packages/music_spaces_server/src/api.js deleted file mode 100755 index 2440f4f9..00000000 --- a/packages/music_spaces_server/src/api.js +++ /dev/null @@ -1,229 +0,0 @@ -import express from "express" -import http from "http" -import cors from "cors" -import morgan from "morgan" -import socketio from "socket.io" -import EventEmitter from "@foxify/events" -import jwt from "jsonwebtoken" -import axios from "axios" - -import routes from "./routes" - -const mainAPI = axios.create({ - baseURL: process.env.MAIN_API_URL ?? "http://localhost:3000", - headers: { - "server-token": process.env.SERVER_TOKEN, - } -}) - -class TextRoomServer { - constructor(server, options = {}) { - this.io = socketio(server, { - cors: { - origin: "*", - methods: ["GET", "POST"], - credentials: true, - } - }) - - this.limitations = { - maxMessageLength: 540, - ...options.limitations, - } - } - - connectionPool = [] - - roomEventsHandlers = { - "send:message": (socket, payload) => { - const { connectedRoom } = socket - let { message } = payload - - if (message.length > this.limitations.maxMessageLength) { - message = message.substring(0, this.limitations.maxMessageLength) - } - - this.io.to(connectedRoom).emit("message", { - timestamp: payload.timestamp ?? Date.now(), - content: String(message), - user: { - username: socket.userData.username, - fullName: socket.userData.fullName, - avatar: socket.userData.avatar, - }, - }) - } - } - - initializeSocketIO = () => { - this.io.use(async (socket, next) => { - const token = socket.handshake.auth.token - - if (!token) { - return next(new Error(`auth:token_missing`)) - } - - const session = await mainAPI.post("/validate_session", { - session: token - }) - .then((res) => { - return res.data - }) - .catch((err) => { - return false - }) - - if (!session || !session?.valid) { - return next(new Error(`auth:token_invalid`)) - } - - const { data: userData } = await mainAPI.get("/user/public_data", { - params: { - username: session.username - } - }).catch((err) => { - return null - }) - - if (!userData) { - return next(new Error(`auth:user_failed`)) - } - - try { - // try to decode the token and get the user's username - const decodedToken = jwt.decode(token) - - socket.userData = userData - socket.token = token - socket.decodedToken = decodedToken - } - catch (err) { - return next(new Error(`auth:decode_failed`)) - } - - console.log(`[${socket.id}] connected`) - - next() - }) - - this.io.on("connection", (socket) => { - socket.on("join", (...args) => this.handleClientJoin(socket, ...args)) - - socket.on("disconnect", () => { - this.handleClientDisconnect(socket) - }) - }) - } - - async handleClientJoin(socket, payload, cb) { - const { room } = payload - - socket.connectedRoom = room - - const pool = await this.attachClientToPool(socket, room).catch((err) => { - cb(err) - return null - }) - - if (!pool) return - - console.log(`[${socket.id}] joined room [${room}]`) - - socket.join(room) - - Object.keys(this.roomEventsHandlers).forEach((event) => { - socket.on(event, (...args) => this.roomEventsHandlers[event](socket, ...args)) - }) - - const roomConnections = this.connectionPool.filter((client) => client.room === room).length - - cb(null, { - roomConnections, - limitations: this.limitations, - }) - } - - handleClientDisconnect(socket) { - const index = this.connectionPool.findIndex((client) => client.id === socket.id) - - if (index === -1) return - - return this.connectionPool.splice(index, 1) - } - - async attachClientToPool(socket, room) { - // TODO: check if user can join room or is privated - - if (!room) { - throw new Error(`room:invalid`) - } - - return this.connectionPool.push({ - id: socket.id, - room, - socket - }) - } -} - -export default class Server { - constructor(options = {}) { - this.app = express() - this.httpServer = http.createServer(this.app) - - this.textRoomServer = new TextRoomServer(this.httpServer) - - this.options = { - listenPort: process.env.PORT || 3020, - ...options - } - } - - eventBus = global.eventBus = new EventEmitter() - - initialize = async () => { - this.app.use(cors()) - this.app.use(express.json({ extended: false })) - this.app.use(express.urlencoded({ extended: true })) - - // Use logger if not in production - if (!process.env.NODE_ENV === "production") { - this.app.use(morgan("dev")) - } - - await this.textRoomServer.initializeSocketIO() - - await this.registerBaseRoute() - await this.registerRoutes() - - await this.httpServer.listen(this.options.listenPort) - - return { - listenPort: this.options.listenPort, - } - } - - async registerBaseRoute() { - await this.app.get("/", async (req, res) => { - return res.json({ - uptimeMinutes: Math.floor(process.uptime() / 60), - }) - }) - } - - registerRoutes() { - routes.forEach((route) => { - const order = [] - - if (route.middlewares) { - route.middlewares.forEach((middleware) => { - order.push(middleware) - }) - } - - order.push(route.routes) - - this.app.use(route.use, ...order) - }) - } -} \ No newline at end of file diff --git a/packages/music_spaces_server/src/index.js b/packages/music_spaces_server/src/index.js deleted file mode 100755 index 8363cf98..00000000 --- a/packages/music_spaces_server/src/index.js +++ /dev/null @@ -1,49 +0,0 @@ -require("dotenv").config() - -// patches -const { Buffer } = require("buffer") - -global.b64Decode = (data) => { - return Buffer.from(data, "base64").toString("utf-8") -} -global.b64Encode = (data) => { - return Buffer.from(data, "utf-8").toString("base64") -} - -Array.prototype.updateFromObjectKeys = function (obj) { - this.forEach((value, index) => { - if (obj[value] !== undefined) { - this[index] = obj[value] - } - }) - - return this -} - -global.toBoolean = (value) => { - if (typeof value === "boolean") { - return value - } - - if (typeof value === "string") { - return value.toLowerCase() === "true" - } - - return false -} - -import pkg from "../package.json" -import API from "./api" - -async function main() { - const api = new API() - - console.log(`\nā–¶ļø Initializing ${pkg.name} ...\n`) - const init = await api.initialize() - - console.log(`\nšŸš€ ${pkg.name} v${pkg.version} is running on port ${init.listenPort}.\n`) -} - -main().catch((error) => { - console.error(`šŸ†˜ [FATAL ERROR] >`, error) -}) \ No newline at end of file diff --git a/packages/music_spaces_server/src/middlewares/errorHandler/index.js b/packages/music_spaces_server/src/middlewares/errorHandler/index.js deleted file mode 100755 index d8e53df2..00000000 --- a/packages/music_spaces_server/src/middlewares/errorHandler/index.js +++ /dev/null @@ -1,5 +0,0 @@ -export const errorHandler = (error, req, res, next) => { - res.json({ error: error.message }) -} - -export default errorHandler \ No newline at end of file diff --git a/packages/music_spaces_server/src/middlewares/hasPermissions/index.js b/packages/music_spaces_server/src/middlewares/hasPermissions/index.js deleted file mode 100755 index 2cc254a8..00000000 --- a/packages/music_spaces_server/src/middlewares/hasPermissions/index.js +++ /dev/null @@ -1,30 +0,0 @@ -export const hasPermissions = (req, res, next) => { - if (typeof (req.userData) == "undefined") { - return res.status(403).json(`User data is not available, please ensure if you are authenticated`) - } - - const { _id, username, roles } = req.userData - const { permissions } = req.body - - req.userPermissions = roles - - let check = [] - - if (Array.isArray(permissions)) { - check = permissions - } else { - check.push(permissions) - } - - if (check.length > 0) { - check.forEach((role) => { - if (!roles.includes(role)) { - return res.status(403).json(`${username} not have permissions ${permissions}`) - } - }) - } - - next() -} - -export default hasPermissions diff --git a/packages/music_spaces_server/src/middlewares/index.js b/packages/music_spaces_server/src/middlewares/index.js deleted file mode 100755 index d22af7db..00000000 --- a/packages/music_spaces_server/src/middlewares/index.js +++ /dev/null @@ -1,12 +0,0 @@ -// const fileUpload = require("@nanoexpress/middleware-file-upload/cjs")() - -export { default as withAuthentication } from "./withAuthentication" -export { default as withOptionalAuthentication } from "./withOptionalAuthentication" - -export { default as errorHandler } from "./errorHandler" -export { default as hasPermissions } from "./hasPermissions" -export { default as roles } from "./roles" -export { default as onlyAdmin } from "./onlyAdmin" -export { default as permissions } from "./permissions" - -// export { fileUpload as fileUpload } \ No newline at end of file diff --git a/packages/music_spaces_server/src/middlewares/onlyAdmin/index.js b/packages/music_spaces_server/src/middlewares/onlyAdmin/index.js deleted file mode 100755 index 730faba8..00000000 --- a/packages/music_spaces_server/src/middlewares/onlyAdmin/index.js +++ /dev/null @@ -1,7 +0,0 @@ -export default (req, res, next) => { - if (!req.user.roles.includes("admin")) { - return res.status(403).json({ error: "To make this request it is necessary to have administrator permissions" }) - } - - next() -} \ No newline at end of file diff --git a/packages/music_spaces_server/src/middlewares/permissions/index.js b/packages/music_spaces_server/src/middlewares/permissions/index.js deleted file mode 100755 index bff9e765..00000000 --- a/packages/music_spaces_server/src/middlewares/permissions/index.js +++ /dev/null @@ -1,39 +0,0 @@ -import { Config } from "../../models" - -export default (req, res, next) => { - const requestedPath = `${req.method.toLowerCase()}${req.path.toLowerCase()}` - - Config.findOne({ key: "permissions" }, undefined, { - lean: true, - }).then(({ value }) => { - req.assertedPermissions = [] - - const pathRoles = value.pathRoles ?? {} - - if (typeof pathRoles[requestedPath] === "undefined") { - console.warn(`[Permissions] No permissions defined for path ${requestedPath}`) - return next() - } - - const requiredRoles = Array.isArray(pathRoles[requestedPath]) ? pathRoles[requestedPath] : [pathRoles[requestedPath]] - - requiredRoles.forEach((role) => { - if (req.user.roles.includes(role)) { - req.assertedPermissions.push(role) - } - }) - - if (req.user.roles.includes("admin")) { - req.assertedPermissions.push("admin") - } - - if (req.assertedPermissions.length === 0 && !req.user.roles.includes("admin")) { - return res.status(403).json({ - error: "forbidden", - message: "You don't have permission to access this resource", - }) - } - - next() - }) -} \ No newline at end of file diff --git a/packages/music_spaces_server/src/middlewares/roles/index.js b/packages/music_spaces_server/src/middlewares/roles/index.js deleted file mode 100755 index 16c9e3c3..00000000 --- a/packages/music_spaces_server/src/middlewares/roles/index.js +++ /dev/null @@ -1,19 +0,0 @@ -export default (req, res, next) => { - req.isAdmin = () => { - if (req.user.roles.includes("admin")) { - return true - } - - return false - } - - req.hasRole = (role) => { - if (req.user.roles.includes(role)) { - return true - } - - return false - } - - next() -} \ No newline at end of file diff --git a/packages/music_spaces_server/src/middlewares/withAuthentication/index.js b/packages/music_spaces_server/src/middlewares/withAuthentication/index.js deleted file mode 100755 index b3dcf481..00000000 --- a/packages/music_spaces_server/src/middlewares/withAuthentication/index.js +++ /dev/null @@ -1,83 +0,0 @@ -import { Session, User } from "../../models" -import { Token } from "../../lib" -import jwt from "jsonwebtoken" - -export default (req, res, next) => { - function reject(description) { - return res.status(403).json({ error: `${description ?? "Invalid session"}` }) - } - - const authHeader = req.headers?.authorization?.split(" ") - - if (authHeader && authHeader[0] === "Bearer") { - const token = authHeader[1] - let decoded = null - - try { - decoded = jwt.decode(token) - } catch (error) { - console.error(error) - } - - if (!decoded) { - return reject("Cannot decode token") - } - - jwt.verify(token, global.jwtStrategy.secretOrKey, async (err) => { - const sessions = await Session.find({ user_id: decoded.user_id }) - const currentSession = sessions.find((session) => session.token === token) - - if (!currentSession) { - return reject("Cannot find session") - } - - const userData = await User.findOne({ _id: currentSession.user_id }).select("+refreshToken") - - if (!userData) { - return res.status(404).json({ error: "No user data found" }) - } - - // if cannot verify token, start regeneration process - if (err) { - // first check if token is only expired, if is corrupted, reject - if (err.name !== "TokenExpiredError") { - return reject("Invalid token, cannot regenerate") - } - - let regenerationToken = null - - // check if this expired token has a regeneration token associated - const associatedRegenerationToken = await Token.getRegenerationToken(token) - - if (associatedRegenerationToken) { - regenerationToken = associatedRegenerationToken.refreshToken - } else { - // create a new regeneration token with the expired token - regenerationToken = await Token.createNewRegenerationToken(token).catch((error) => { - // in case of error, reject - reject(error.message) - - return null - }) - } - - if (!regenerationToken) return - - // now send the regeneration token to the client (start Expired Exception Event [EEE]) - return res.status(401).json({ - error: "Token expired", - refreshToken: regenerationToken.refreshToken, - }) - } - - req.user = userData - req.jwtToken = token - req.decodedToken = decoded - req.currentSession = currentSession - - return next() - }) - } else { - return reject("Missing token header") - } -} diff --git a/packages/music_spaces_server/src/middlewares/withOptionalAuthentication/index.js b/packages/music_spaces_server/src/middlewares/withOptionalAuthentication/index.js deleted file mode 100755 index 4a03cd05..00000000 --- a/packages/music_spaces_server/src/middlewares/withOptionalAuthentication/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import withAuthentication from "../withAuthentication" - -export default (req, res, next) => { - if (req.headers?.authorization) { - withAuthentication(req, res, next) - } else { - next() - } -} \ No newline at end of file diff --git a/packages/music_spaces_server/src/routes/index.js b/packages/music_spaces_server/src/routes/index.js deleted file mode 100755 index 96c728da..00000000 --- a/packages/music_spaces_server/src/routes/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export default [ - -] \ No newline at end of file