diff --git a/api-ports.md b/api-ports.md index 35bb58bf..ec6a7441 100644 --- a/api-ports.md +++ b/api-ports.md @@ -7,7 +7,7 @@ 3004 -> chats 3005 -> marketplace 3006 -> sync -3007 -> mail +3007 -> ems (External Messaging Service) 3008 -> unallocated 3009 -> unallocated 3010 -> unallocated @@ -16,3 +16,8 @@ 3013 -> unallocated 3014 -> unallocated 3015 -> unallocated +3016 -> unallocated +3017 -> unallocated +3018 -> unallocated +3019 -> unallocated +3020 -> auth \ No newline at end of file diff --git a/packages/server/boot b/packages/server/boot index c5c817de..126e0eee 100755 --- a/packages/server/boot +++ b/packages/server/boot @@ -1,4 +1,5 @@ #!/usr/bin/env node +require("dotenv").config() require("sucrase/register") const path = require("path") @@ -28,6 +29,7 @@ global["aliases"] = { "@shared-utils": path.resolve(__dirname, "utils"), "@shared-classes": path.resolve(__dirname, "classes"), "@shared-lib": path.resolve(__dirname, "lib"), + "@shared-middlewares": path.resolve(__dirname, "middlewares"), // expose internal resources "@lib": path.resolve(global["__src"], "lib"), diff --git a/packages/server/classes/AuthToken/index.js b/packages/server/classes/AuthToken/index.js new file mode 100644 index 00000000..505e560d --- /dev/null +++ b/packages/server/classes/AuthToken/index.js @@ -0,0 +1,237 @@ +import jwt from "jsonwebtoken" +import { Session, RegenerationToken, User } from "../../classes/DbModels" + +export default class Token { + static get strategy() { + return { + secret: process.env.JWT_SECRET, + expiresIn: process.env.JWT_EXPIRES_IN ?? "1h", + algorithm: process.env.JWT_ALGORITHM ?? "HS256", + } + } + + static async createNewAuthToken(payload, options = {}) { + if (options.updateSession) { + const sessionData = await Session.findOne({ _id: options.updateSession }) + + payload.session_uuid = sessionData.session_uuid + } else { + payload.session_uuid = global.nanoid() + } + + const { secret, expiresIn, algorithm } = Token.strategy + + const token = jwt.sign( + { + session_uuid: payload.session_uuid, + username: payload.username, + user_id: payload.user_id, + signLocation: payload.signLocation, + }, + secret, + { + expiresIn: expiresIn, + algorithm: algorithm + } + ) + + return token + } + + static async validate(token) { + let result = { + expired: false, + valid: true, + error: null, + data: null, + } + + if (typeof token === "undefined") { + result.valid = false + result.error = "Missing token" + + return result + } + + const { secret } = Token.strategy + + await jwt.verify(token, secret, async (err, decoded) => { + if (err) { + result.valid = false + result.error = err.message + + if (err.message === "jwt expired") { + result.expired = true + } + + return + } + + result.data = decoded + + const sessions = await Session.find({ user_id: decoded.user_id }) + const currentSession = sessions.find((session) => session.token === token) + + if (!currentSession) { + result.valid = false + result.error = "Session token not found" + } else { + result.session = currentSession + result.valid = true + result.user = async () => await User.findOne({ _id: decoded.user_id }) + } + }) + + return result + } + + static async regenerate(expiredToken, refreshToken, aggregateData = {}) { + // search for a regeneration token with the expired token (Should exist only one) + const regenerationToken = await RegenerationToken.findOne({ refreshToken: refreshToken }) + + if (!regenerationToken) { + throw new Error("Cannot find regeneration token") + } + + // check if the regeneration token is valid and not expired + let decodedRefreshToken = null + let decodedExpiredToken = null + + try { + decodedRefreshToken = jwt.decode(refreshToken) + decodedExpiredToken = jwt.decode(expiredToken) + } catch (error) { + console.error(error) + // TODO: Storage this incident + } + + if (!decodedRefreshToken) { + throw new Error("Cannot decode refresh token") + } + + if (!decodedExpiredToken) { + throw new Error("Cannot decode expired token") + } + + // is not needed to verify the expired token, because it suppossed to be expired + + // verify refresh token + await jwt.verify(refreshToken, global.jwtStrategy.secretOrKey, async (err) => { + // check if is expired + if (err) { + if (err.message === "jwt expired") { + // check if server has enabled the enforcement of regeneration token expiration + if (global.jwtStrategy.enforceRegenerationTokenExpiration) { + // delete the regeneration token + await RegenerationToken.deleteOne({ refreshToken: refreshToken }) + + throw new Error("Regeneration token expired and cannot be regenerated due server has enabled enforcement security policy") + } + } + } + + // check if the regeneration token is associated with the expired token + if (decodedRefreshToken.expiredToken !== expiredToken) { + throw new Error("Regeneration token is not associated with the expired token") + } + }) + + // find the session associated with the expired token + const session = await Session.findOne({ token: expiredToken }) + + if (!session) { + throw new Error("Cannot find session associated with the expired token") + } + + // generate a new token + const newToken = await this.createNewAuthToken({ + username: decodedExpiredToken.username, + session_uuid: session.session_uuid, + user_id: decodedExpiredToken.user_id, + ip_address: aggregateData.ip_address, + }, { + updateSession: session._id, + }) + + // delete the regeneration token + await RegenerationToken.deleteOne({ refreshToken: refreshToken }) + + return newToken + } + + static async createAuth(payload, options = {}) { + const token = await this.createNewAuthToken(payload, options) + + const session = { + token: token, + session_uuid: payload.session_uuid, + username: payload.username, + user_id: payload.user_id, + location: payload.signLocation, + ip_address: payload.ip_address, + client: payload.client, + date: new Date().getTime(), + } + + if (options.updateSession) { + await Session.findByIdAndUpdate(options.updateSession, session) + } else { + let newSession = new Session(session) + + await newSession.save() + } + + return token + } + + static async createRegenerative(expiredToken) { + // check if token is only expired, if is corrupted, reject + let decoded = null + + try { + decoded = jwt.decode(expiredToken) + } catch (error) { + console.error(error) + } + + if (!decoded) { + return false + } + + // check if token exists on a session + const sessions = await Session.find({ user_id: decoded.user_id }) + const currentSession = sessions.find((session) => session.token === expiredToken) + + if (!currentSession) { + throw new Error("This token is not associated with any session") + } + + // create a new refresh token and sign it with maximum expiration time of 1 day + const refreshToken = jwt.sign( + { + expiredToken + }, + global.jwtStrategy.secretOrKey, + { + expiresIn: "1d" + } + ) + + // create a new regeneration token and save it + const regenerationToken = new RegenerationToken({ + expiredToken, + refreshToken, + }) + + await regenerationToken.save() + + // return the regeneration token + return regenerationToken + } + + static async getRegenerationToken(expiredToken) { + const regenerationToken = await RegenerationToken.findOne({ expiredToken }) + + return regenerationToken + } +} \ No newline at end of file diff --git a/packages/server/classes/DbManager/index.js b/packages/server/classes/DbManager/index.js index c8b9f2a1..285c67f2 100755 --- a/packages/server/classes/DbManager/index.js +++ b/packages/server/classes/DbManager/index.js @@ -18,6 +18,7 @@ function getConnectionConfig(obj) { dbName: DB_NAME, user: DB_USER, pass: DB_PWD, + maxPoolSize: 100, } if (DB_AUTH_SOURCE) { diff --git a/packages/server/classes/RedisClient/index.js b/packages/server/classes/RedisClient/index.js index d231bc68..0b353e6d 100755 --- a/packages/server/classes/RedisClient/index.js +++ b/packages/server/classes/RedisClient/index.js @@ -50,27 +50,30 @@ export default () => { clientOptions = composeURL(clientOptions) - let client = {} + let client = new Redis(clientOptions.host, clientOptions.port, clientOptions) - client.initialize = async () => { - console.log(`🔌 Connecting to Redis client [${REDIS_HOST}]`) + client.on("error", (error) => { + console.error("❌ Redis client error:", error) + }) - client = new Redis(clientOptions) + client.on("connect", () => { + console.log(`✅ Redis client connected [${process.env.REDIS_HOST}]`) + }) - client.on("error", (error) => { - console.error("❌ Redis client error:", error) + client.on("reconnecting", () => { + console.log("🔄 Redis client reconnecting...") + }) + + const initialize = async () => { + return await new Promise((resolve, reject) => { + console.log(`🔌 Connecting to Redis client [${REDIS_HOST}]`) + + client.connect(resolve) }) - - client.on("connect", () => { - console.log(`✅ Redis client connected [${process.env.REDIS_HOST}]`) - }) - - client.on("reconnecting", () => { - console.log("🔄 Redis client reconnecting...") - }) - - return client } - return client + return { + client, + initialize + } } \ No newline at end of file diff --git a/packages/server/classes/SecureEntry/index.js b/packages/server/classes/SecureEntry/index.js new file mode 100644 index 00000000..e7591da0 --- /dev/null +++ b/packages/server/classes/SecureEntry/index.js @@ -0,0 +1,133 @@ +import crypto from "crypto" + +export default class SecureEntry { + constructor(model, params = {}) { + this.params = params + + if (!model) { + throw new Error("Missing model") + } + + this.model = model + } + + static get encrytionAlgorithm() { + return "aes-256-cbc" + } + + async set(key, value, { + keyName = "key", + valueName = "value", + }) { + if (!keyName) { + throw new Error("Missing keyName") + } + + if (!valueName) { + throw new Error("Missing valueName") + } + + if (!key) { + throw new Error("Missing key") + } + + if (!value) { + throw new Error("Missing value") + } + + let entry = await this.model.findOne({ + [keyName]: key, + [valueName]: value, + }).catch(() => null) + + const encryptionKey = Buffer.from(process.env.SYNC_ENCRIPT_SECRET, "hex") + const iv = crypto.randomBytes(16) + + const cipher = crypto.createCipheriv(SecureEntry.encrytionAlgorithm, encryptionKey, iv) + + let encryptedData + + try { + encryptedData = cipher.update(value) + } + catch (error) { + console.error(error) + } + + encryptedData = Buffer.concat([encryptedData, cipher.final()]) + + value = iv.toString("hex") + ":" + encryptedData.toString("hex") + + if (entry) { + entry[valueName] = value + + await entry.save() + + return entry + } + + entry = new this.model({ + [keyName]: key, + [valueName]: value, + }) + + await entry.save() + + return entry + } + + async get(key, value, { + keyName = "key", + valueName = "value", + }) { + if (!keyName) { + throw new Error("Missing keyName") + } + if (!key) { + throw new Error("Missing key") + } + + const searchQuery = { + [keyName]: key, + } + + if (value) { + searchQuery[valueName] = value + } + + const entry = await this.model.findOne(searchQuery).catch(() => null) + + if (!entry || !entry[valueName]) { + return null + } + + const encryptionKey = Buffer.from(process.env.SYNC_ENCRIPT_SECRET, "hex") + + const iv = Buffer.from(entry[valueName].split(":")[0], "hex") + const encryptedText = Buffer.from(entry[valueName].split(":")[1], "hex") + + const decipher = crypto.createDecipheriv(SecureEntry.encrytionAlgorithm, encryptionKey, iv) + + let decrypted = decipher.update(encryptedText) + + decrypted = Buffer.concat([decrypted, decipher.final()]) + + return decrypted.toString() + } + + async deleteByID(_id) { + if (!_id) { + throw new Error("Missing _id") + } + + const entry = await this.model.findById(_id).catch(() => null) + + if (!entry) { + return null + } + + await entry.delete() + + return entry + } +} \ No newline at end of file diff --git a/packages/server/middlewares/index.js b/packages/server/middlewares/index.js new file mode 100644 index 00000000..b755615f --- /dev/null +++ b/packages/server/middlewares/index.js @@ -0,0 +1,6 @@ +export default { + withAuthentication: require("./withAuthentication").default, + withOptionalAuthentication: require("./withOptionalAuthentication").default, + onlyAdmin: require("./onlyAdmin").default, + roles: require("./roles").default, +} \ No newline at end of file diff --git a/packages/server/middlewares/onlyAdmin/index.js b/packages/server/middlewares/onlyAdmin/index.js new file mode 100755 index 00000000..eea3a6b2 --- /dev/null +++ b/packages/server/middlewares/onlyAdmin/index.js @@ -0,0 +1,11 @@ +export default (req, res, next) => { + if (!req.auth) { + return res.status(401).json({ error: "No authenticated" }) + } + + if (!req.auth.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/server/middlewares/roles/index.js b/packages/server/middlewares/roles/index.js new file mode 100755 index 00000000..16c9e3c3 --- /dev/null +++ b/packages/server/middlewares/roles/index.js @@ -0,0 +1,19 @@ +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/server/middlewares/withAuthentication/index.js b/packages/server/middlewares/withAuthentication/index.js new file mode 100755 index 00000000..b8997202 --- /dev/null +++ b/packages/server/middlewares/withAuthentication/index.js @@ -0,0 +1,78 @@ +import { authorizedServerTokens } from "../../classes/DbModels" +import SecureEntry from "../../classes/SecureEntry" +import AuthToken from "../../classes/AuthToken" + +export default async (req, res, next) => { + function reject(description) { + return res.status(401).json({ error: `${description ?? "Invalid session"}` }) + } + + try { + const tokenAuthHeader = req.headers?.authorization?.split(" ") + + if (!tokenAuthHeader) { + return reject("Missing token header") + } + + if (!tokenAuthHeader[1]) { + return reject("Recived header, missing token") + } + + switch (tokenAuthHeader[0]) { + case "Bearer": { + const token = tokenAuthHeader[1] + + const validation = await AuthToken.validate(token) + + if (!validation.valid) { + return reject(validation.error) + } + + req.auth = { + token: token, + decoded: validation.data, + session: validation.session, + user: validation.user + } + + return next() + } + case "Server": { + const [client_id, token] = tokenAuthHeader[1].split(":") + + if (client_id === "undefined" || token === "undefined") { + return reject("Invalid server token") + } + + const secureEntries = new SecureEntry(authorizedServerTokens) + + const serverTokenEntry = await secureEntries.get(client_id, undefined, { + keyName: "client_id", + valueName: "token", + }) + + if (!serverTokenEntry) { + return reject("Invalid server token") + } + + if (serverTokenEntry !== token) { + return reject("Missmatching server token") + } + + req.user = { + __server: true, + _id: client_id, + roles: ["server"], + } + + return next() + } + default: { + return reject("Invalid token type") + } + } + } catch (error) { + console.error(error) + return res.status(500).json({ error: "An error occurred meanwhile authenticating your token" }) + } +} diff --git a/packages/server/middlewares/withOptionalAuthentication/index.js b/packages/server/middlewares/withOptionalAuthentication/index.js new file mode 100755 index 00000000..4a03cd05 --- /dev/null +++ b/packages/server/middlewares/withOptionalAuthentication/index.js @@ -0,0 +1,9 @@ +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/server/package.json b/packages/server/package.json index 0f32b58c..d681e165 100755 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -23,6 +23,7 @@ "dotenv": "^16.4.4", "http-proxy-middleware": "^2.0.6", "hyper-express": "^6.14.12", + "jsonwebtoken": "^9.0.2", "linebridge": "^0.16.0", "module-alias": "^2.2.3", "p-map": "^4.0.0", diff --git a/packages/server/services/auth/auth.service.js b/packages/server/services/auth/auth.service.js new file mode 100644 index 00000000..7994910f --- /dev/null +++ b/packages/server/services/auth/auth.service.js @@ -0,0 +1,25 @@ +import { Server } from "linebridge/src/server" +import DbManager from "@shared-classes/DbManager" + +import SharedMiddlewares from "@shared-middlewares" + +export default class API extends Server { + static refName = "auth" + static useEngine = "hyper-express" + static routesPath = `${__dirname}/routes` + static listen_port = process.env.HTTP_LISTEN_PORT ?? 3020 + + middlewares = { + ...SharedMiddlewares + } + + contexts = { + db: new DbManager(), + } + + async onInitialize() { + await this.contexts.db.initialize() + } +} + +Boot(API) \ No newline at end of file diff --git a/packages/server/services/auth/package.json b/packages/server/services/auth/package.json new file mode 100644 index 00000000..34a2bca5 --- /dev/null +++ b/packages/server/services/auth/package.json @@ -0,0 +1,6 @@ +{ + "name": "auth", + "version": "1.0.0", + "main": "index.js", + "license": "MIT" +} diff --git a/packages/server/services/auth/routes/auth/delete.js b/packages/server/services/auth/routes/auth/delete.js new file mode 100644 index 00000000..a9da4127 --- /dev/null +++ b/packages/server/services/auth/routes/auth/delete.js @@ -0,0 +1,22 @@ +import { Session } from "@shared-classes/DbModels" + +export default { + middlewares: ["withAuthentication"], + fn: async (req) => { + const { token, session } = req.auth + + const deletedSession = await Session.findOneAndDelete({ + user_id: session.user_id, + token: token, + }) + + if (session) { + return { + message: "Session deleted", + session: deletedSession + } + } + + throw new OperationError(404, "Session not found") + } +} \ No newline at end of file diff --git a/packages/server/services/auth/routes/auth/post.js b/packages/server/services/auth/routes/auth/post.js new file mode 100644 index 00000000..0d5232c3 --- /dev/null +++ b/packages/server/services/auth/routes/auth/post.js @@ -0,0 +1,36 @@ +import AuthToken from "@shared-classes/AuthToken" +import { User } from "@shared-classes/DbModels" +import requiredFields from "@shared-utils/requiredFields" +import bcrypt from "bcrypt" + +export default async (req, res) => { + requiredFields(["username", "password"], req.body) + + const { username, password } = req.body + + let isEmail = username.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/) + + let query = isEmail ? { email: username } : { username: username } + + const user = await User.findOne(query).select("+password") + + if (!user) { + throw new OperationError(401, "User not found") + } + + if (!bcrypt.compareSync(password, user.password)) { + return res.status(401).json({ + message: "Invalid credentials", + }) + } + + const token = await AuthToken.createAuth({ + username: user.username, + user_id: user._id.toString(), + ip_address: req.headers["x-forwarded-for"]?.split(",")[0] ?? req.socket?.remoteAddress ?? req.ip, + client: req.headers["user-agent"], + //signLocation: global.signLocation, + }) + + return { token: token } +} \ No newline at end of file diff --git a/packages/server/services/auth/routes/availability/get.js b/packages/server/services/auth/routes/availability/get.js new file mode 100644 index 00000000..f9453a52 --- /dev/null +++ b/packages/server/services/auth/routes/availability/get.js @@ -0,0 +1,30 @@ +import { User } from "@shared-classes/DbModels" + +export default async (req) => { + const { username, email } = req.query + + if (!username && !email) { + throw new OperationError(400, "Missing username or email") + } + + const user = await User.findOne({ + $or: [ + { username: username }, + { email: email }, + ] + }).catch((error) => { + return false + }) + + if (user) { + return { + message: "User already exists", + exists: true, + } + } else { + return { + message: "User doesn't exists", + exists: false, + } + } +} \ No newline at end of file diff --git a/packages/server/services/auth/routes/register/post.js b/packages/server/services/auth/routes/register/post.js new file mode 100644 index 00000000..b136c859 --- /dev/null +++ b/packages/server/services/auth/routes/register/post.js @@ -0,0 +1,72 @@ +import { User } from "@shared-classes/DbModels" +import bcrypt from "bcrypt" + +import requiredFields from "@shared-utils/requiredFields" + +export default async (req) => { + requiredFields(["username", "password", "email"], req.body) + + let { username, password, email, fullName, roles, avatar, acceptTos } = req.body + + if (ToBoolean(acceptTos) !== true) { + throw new OperationError(400, "You must accept the terms of service in order to create an account.") + } + + if (username.length < 3) { + throw new OperationError(400, "Username must be at least 3 characters") + } + + if (username.length > 64) { + throw new OperationError(400, "Username cannot be longer than 64 characters") + } + + // if username has capital letters, throw error + if (username !== username.toLowerCase()) { + throw new OperationError(400, "Username must be lowercase") + } + + // make sure the username has no spaces + if (username.includes(" ")) { + throw new OperationError(400, "Username cannot contain spaces") + } + + // make sure the username has no valid characters. Only letters, numbers, and underscores + if (!/^[a-z0-9_]+$/.test(username)) { + throw new OperationError(400, "Username can only contain letters, numbers, and underscores") + } + + // check if username is already taken + const existentUser = await User.findOne({ username: username }) + + if (existentUser) { + throw new OperationError(400, "User already exists") + } + + // check if the email is already in use + const existentEmail = await User.findOne({ email: email }) + + if (existentEmail) { + throw new OperationError(400, "Email already in use") + } + + // hash the password + const hash = bcrypt.hashSync(password, parseInt(process.env.BCRYPT_ROUNDS ?? 3)) + + let user = new User({ + username: username, + password: hash, + email: email, + fullName: fullName, + avatar: avatar ?? `https://api.dicebear.com/7.x/thumbs/svg?seed=${username}`, + roles: roles, + createdAt: new Date().getTime(), + acceptTos: acceptTos, + }) + + await user.save() + + // TODO: dispatch event bus + //global.eventBus.emit("user.create", user) + + return user +} \ No newline at end of file diff --git a/packages/server/services/chats/chats.service.js b/packages/server/services/chats/chats.service.js index d6d58c4c..559448df 100755 --- a/packages/server/services/chats/chats.service.js +++ b/packages/server/services/chats/chats.service.js @@ -21,7 +21,7 @@ export default class API { this.options = { listenHost: process.env.HTTP_LISTEN_HOST || "0.0.0.0", - listenPort: process.env.HTTP_LISTEN_PORT || 3020, + listenPort: process.env.HTTP_LISTEN_PORT || 3004, ...options } } diff --git a/packages/server/services/files/file.service.js b/packages/server/services/files/file.service.js index da82cabd..8ee64d08 100755 --- a/packages/server/services/files/file.service.js +++ b/packages/server/services/files/file.service.js @@ -37,7 +37,7 @@ export default class FileServerAPI { server = global.server = express() listenIp = process.env.HTTP_LISTEN_IP ?? "0.0.0.0" - listenPort = process.env.HTTP_LISTEN_PORT ?? 3060 + listenPort = process.env.HTTP_LISTEN_PORT ?? 3002 redis = global.redis = RedisClient() diff --git a/packages/server/services/main/main.service.js b/packages/server/services/main/main.service.js index caa6d396..bbce8741 100755 --- a/packages/server/services/main/main.service.js +++ b/packages/server/services/main/main.service.js @@ -8,7 +8,7 @@ import Token from "@lib/token" export default class API extends Server { static refName = "MAIN-API" - static listen_port = process.env.HTTP_LISTEN_PORT || 3010 + static listen_port = process.env.HTTP_LISTEN_PORT || 3000 static requireWSAuth = true constructor(params) { diff --git a/packages/server/services/main/package.json b/packages/server/services/main/package.json index 67079f21..3175c278 100755 --- a/packages/server/services/main/package.json +++ b/packages/server/services/main/package.json @@ -28,7 +28,6 @@ "nsfwjs": "^3.0.0", "p-map": "^4.0.0", "p-queue": "^7.3.4", - "path-to-regexp": "^6.2.1", "sharp": "^0.33.2" } } diff --git a/packages/server/services/marketplace/marketplace.service.js b/packages/server/services/marketplace/marketplace.service.js index bd140258..8220bf35 100755 --- a/packages/server/services/marketplace/marketplace.service.js +++ b/packages/server/services/marketplace/marketplace.service.js @@ -16,7 +16,7 @@ export default class API { server = global.server = new hyperexpress.Server() listenIp = process.env.HTTP_LISTEN_IP ?? "0.0.0.0" - listenPort = process.env.HTTP_LISTEN_PORT ?? 3040 + listenPort = process.env.HTTP_LISTEN_PORT ?? 3005 internalRouter = new hyperexpress.Router() diff --git a/packages/server/services/music/music.service.js b/packages/server/services/music/music.service.js index d515c5de..11436219 100755 --- a/packages/server/services/music/music.service.js +++ b/packages/server/services/music/music.service.js @@ -28,7 +28,7 @@ export default class API { this.options = { listenHost: process.env.HTTP_LISTEN_IP ?? "0.0.0.0", - listenPort: process.env.HTTP_LISTEN_PORT ?? 3050, + listenPort: process.env.HTTP_LISTEN_PORT ?? 3003, ...options } } diff --git a/packages/server/services/posts/classes/posts/methods/fullfill.js b/packages/server/services/posts/classes/posts/methods/fullfill.js index 2e89f1f9..ffa6589c 100644 --- a/packages/server/services/posts/classes/posts/methods/fullfill.js +++ b/packages/server/services/posts/classes/posts/methods/fullfill.js @@ -10,8 +10,6 @@ export default async (payload) => { posts = [posts] } - console.log(posts, posts.every((post) => !post)) - if (posts.every((post) => !post)) { return [] } diff --git a/packages/server/services/posts/posts.service.js b/packages/server/services/posts/posts.service.js index 5bf865b1..6f3bde3b 100644 --- a/packages/server/services/posts/posts.service.js +++ b/packages/server/services/posts/posts.service.js @@ -1,6 +1,9 @@ import { Server } from "linebridge/src/server" import DbManager from "@shared-classes/DbManager" +import RedisClient from "@shared-classes/RedisClient" + +import SharedMiddlewares from "@shared-middlewares" export default class API extends Server { static refName = "posts" @@ -8,8 +11,13 @@ export default class API extends Server { static routesPath = `${__dirname}/routes` static listen_port = process.env.HTTP_LISTEN_PORT ?? 3001 + middlewares = { + ...SharedMiddlewares + } + contexts = { db: new DbManager(), + redis: RedisClient() } events = { @@ -18,6 +26,7 @@ export default class API extends Server { async onInitialize() { await this.contexts.db.initialize() + await this.contexts.redis.initialize() } } diff --git a/packages/server/services/posts/routes/posts/[post_id]/get.js b/packages/server/services/posts/routes/posts/[post_id]/get.js index 6c3f2799..760b6b82 100644 --- a/packages/server/services/posts/routes/posts/[post_id]/get.js +++ b/packages/server/services/posts/routes/posts/[post_id]/get.js @@ -3,9 +3,9 @@ import Posts from "@classes/posts" export default { middlewares: ["withOptionalAuthentication"], fn: async (req, res) => { - const result = await Posts.data({ + const result = await Posts.data({ post_id: req.params.post_id, - for_user_id: req.user?._id.toString(), + for_user_id: req.auth?.session?.user_id, }) return result diff --git a/packages/server/services/sync/sync.service.js b/packages/server/services/sync/sync.service.js index ddfa5c69..c1facbdc 100755 --- a/packages/server/services/sync/sync.service.js +++ b/packages/server/services/sync/sync.service.js @@ -15,7 +15,7 @@ export default class API { server = global.server = new hyperexpress.Server() listenIp = process.env.HTTP_LISTEN_IP ?? "0.0.0.0" - listenPort = process.env.HTTP_LISTEN_PORT ?? 3070 + listenPort = process.env.HTTP_LISTEN_PORT ?? 3006 internalRouter = new hyperexpress.Router() diff --git a/packages/server/utils/requiredFields.js b/packages/server/utils/requiredFields.js index 6cf79c54..f33cb3c0 100644 --- a/packages/server/utils/requiredFields.js +++ b/packages/server/utils/requiredFields.js @@ -17,6 +17,6 @@ export default (fields, obj) => { } if (missing.length > 0) { - throw new Error(`Missing required fields: ${missing.join(", ")}`) + throw new OperationError(400, `Missing required fields: ${missing.join(", ")}`) } } \ No newline at end of file