summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.DS_Storebin6148 -> 8196 bytes
-rw-r--r--package-lock.json26
-rw-r--r--package.json2
-rw-r--r--src/Server.ts15
-rw-r--r--src/middlewares/GlobalRateLimit.ts2
-rw-r--r--src/middlewares/RateLimit.ts3
-rw-r--r--src/routes/api/v8/auth/login.ts12
-rw-r--r--src/routes/api/v8/auth/register.ts14
-rw-r--r--src/routes/api/v8/guilds/index.ts88
-rw-r--r--src/test/mongo_test.ts34
-rw-r--r--src/util/Event.ts24
11 files changed, 121 insertions, 99 deletions
diff --git a/.DS_Store b/.DS_Store

index 7daf908b..07eb6a58 100644 --- a/.DS_Store +++ b/.DS_Store
Binary files differdiff --git a/package-lock.json b/package-lock.json
index 147b1d76..b35ee829 100644 --- a/package-lock.json +++ b/package-lock.json
@@ -21,6 +21,8 @@ "lambert-db": "^1.1.8", "lambert-server": "^1.0.10", "missing-native-js-functions": "^1.2.2", + "mongodb": "^3.6.4", + "mongoose-long": "^0.3.2", "node-fetch": "^2.6.1" }, "devDependencies": { @@ -778,12 +780,13 @@ }, "node_modules/fosscord-server-util": { "version": "1.0.0", - "resolved": "git+ssh://git@github.com/fosscord/fosscord-server-util.git#3d54ed476240702812caf0b6e1ce94bfb0329cb5", + "resolved": "git+ssh://git@github.com/fosscord/fosscord-server-util.git#4125b7810d6da218fef6e26ec7cfbd1032c4cbb3", "license": "ISC", "dependencies": { "jsonwebtoken": "^8.5.1", "lambert-db": "^1.1.7", - "missing-native-js-functions": "^1.2.2" + "missing-native-js-functions": "^1.2.2", + "mongodb": "^3.6.4" } }, "node_modules/fresh": { @@ -1461,6 +1464,14 @@ "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==" }, + "node_modules/mongoose-long": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/mongoose-long/-/mongoose-long-0.3.2.tgz", + "integrity": "sha512-5gTjPH6HUmtNhamv8MPwExWo01Z4d9CT5njZlupqqbmxzMXTbDOgCuP/jnK+9SV0Fs7nuyYlXv7pJ/nA2pAAuA==", + "peerDependencies": { + "mongoose": "4.x || 5.x" + } + }, "node_modules/mongoose/node_modules/mongodb": { "version": "3.6.3", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.3.tgz", @@ -2987,12 +2998,13 @@ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" }, "fosscord-server-util": { - "version": "git+ssh://git@github.com/fosscord/fosscord-server-util.git#3d54ed476240702812caf0b6e1ce94bfb0329cb5", + "version": "git+ssh://git@github.com/fosscord/fosscord-server-util.git#4125b7810d6da218fef6e26ec7cfbd1032c4cbb3", "from": "fosscord-server-util@github:fosscord/fosscord-server-util", "requires": { "jsonwebtoken": "^8.5.1", "lambert-db": "^1.1.7", - "missing-native-js-functions": "^1.2.2" + "missing-native-js-functions": "^1.2.2", + "mongodb": "^3.6.4" } }, "fresh": { @@ -3586,6 +3598,12 @@ "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==" }, + "mongoose-long": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/mongoose-long/-/mongoose-long-0.3.2.tgz", + "integrity": "sha512-5gTjPH6HUmtNhamv8MPwExWo01Z4d9CT5njZlupqqbmxzMXTbDOgCuP/jnK+9SV0Fs7nuyYlXv7pJ/nA2pAAuA==", + "requires": {} + }, "mpath": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.3.tgz", diff --git a/package.json b/package.json
index d88232ba..6520901a 100644 --- a/package.json +++ b/package.json
@@ -32,6 +32,8 @@ "lambert-db": "^1.1.8", "lambert-server": "^1.0.10", "missing-native-js-functions": "^1.2.2", + "mongodb": "^3.6.4", + "mongoose-long": "^0.3.2", "node-fetch": "^2.6.1" }, "devDependencies": { diff --git a/src/Server.ts b/src/Server.ts
index b561f94e..fa4111db 100644 --- a/src/Server.ts +++ b/src/Server.ts
@@ -1,5 +1,6 @@ import "missing-native-js-functions"; import fs from "fs/promises"; +import { Connection } from "mongoose"; import { Server, ServerOptions } from "lambert-server"; import { Authentication, GlobalRateLimit } from "./middlewares/"; import Config from "./util/Config"; @@ -29,8 +30,20 @@ export class DiscordServer extends Server { super({ ...opts, errorHandler: false, jsonBody: false }); } + async setupSchema() { + await db.collection("users").createIndex({ id: 1 }, { unique: true }); + await db.collection("messages").createIndex({ id: 1 }, { unique: true }); + await db.collection("channels").createIndex({ id: 1 }, { unique: true }); + await db.collection("guilds").createIndex({ id: 1 }, { unique: true }); + await db.collection("members").createIndex({ id: 1 }, { unique: true }); + await db.collection("roles").createIndex({ id: 1 }, { unique: true }); + await db.collection("emojis").createIndex({ id: 1 }, { unique: true }); + } + async start() { - await db.init(); + // @ts-ignore + await (db as Promise<Connection>); + await this.setupSchema(); console.log("[DB] connected"); await Promise.all([Config.init()]); diff --git a/src/middlewares/GlobalRateLimit.ts b/src/middlewares/GlobalRateLimit.ts
index c729987a..33dc5e0f 100644 --- a/src/middlewares/GlobalRateLimit.ts +++ b/src/middlewares/GlobalRateLimit.ts
@@ -6,6 +6,8 @@ import { db } from "fosscord-server-util"; // TODO: increment count on serverside export async function GlobalRateLimit(req: Request, res: Response, next: NextFunction) { + return next(); + // TODO: use new db mongoose models if (!Config.get().limits.rate.ip.enabled) return next(); const ip = getIpAdress(req); diff --git a/src/middlewares/RateLimit.ts b/src/middlewares/RateLimit.ts
index c42d773c..b015c7e0 100644 --- a/src/middlewares/RateLimit.ts +++ b/src/middlewares/RateLimit.ts
@@ -5,6 +5,9 @@ import { getIpAdress } from "./GlobalRateLimit"; export function RateLimit({ count = 10, timespan = 1000 * 5, name = "/" }) { return async (req: Request, res: Response, next: NextFunction) => { + return next(); + // TODO: use new db mongoose models + let id = req.userid || getIpAdress(req); const limit: { count: number; start: number } = (await db.data.ratelimit.routes[name][id].get()) || { diff --git a/src/routes/api/v8/auth/login.ts b/src/routes/api/v8/auth/login.ts
index ac9775df..acdac1ce 100644 --- a/src/routes/api/v8/auth/login.ts +++ b/src/routes/api/v8/auth/login.ts
@@ -2,7 +2,7 @@ import { Request, Response, Router } from "express"; import { check, FieldErrors, Length } from "../../../../util/instanceOf"; import bcrypt from "bcrypt"; import jwt from "jsonwebtoken"; -import { db, User } from "fosscord-server-util"; +import { User, UserModel } from "fosscord-server-util"; import Config from "../../../../util/Config"; import { adjustEmail } from "./register"; @@ -23,10 +23,12 @@ router.post( const { login, password } = req.body; // * MongoDB Specific query for user with same email or phone number - const userquery = { $or: [{ email: adjustEmail(login) }, { phone: login }] }; - const user: User = await db.data - .users(userquery) - .get({ hash: true, id: true, user_settings: { locale: true, theme: true } }); + const user = await UserModel.findOne( + { + $or: [{ email: adjustEmail(login) }, { phone: login }], + }, + `hash id user_settings.locale user_settings.theme` + ).exec(); if (!user) { throw FieldErrors({ diff --git a/src/routes/api/v8/auth/register.ts b/src/routes/api/v8/auth/register.ts
index 1250b689..1205c462 100644 --- a/src/routes/api/v8/auth/register.ts +++ b/src/routes/api/v8/auth/register.ts
@@ -1,6 +1,6 @@ import { Request, Response, Router } from "express"; import Config from "../../../../util/Config"; -import { db, trimSpecial, User, Snowflake } from "fosscord-server-util"; +import { trimSpecial, User, Snowflake, UserModel } from "fosscord-server-util"; import bcrypt from "bcrypt"; import { check, Email, EMAIL_REGEX, FieldErrors, Length } from "../../../../util/instanceOf"; import "missing-native-js-functions"; @@ -80,7 +80,8 @@ router.post( adjusted_email = adjustEmail(email); // check if there is already an account with this email - const exists = await db.data.users({ email: adjusted_email }).get(); + const exists = await UserModel.findOne({ email: adjusted_email }).exec(); + if (exists) { throw FieldErrors({ email: { @@ -116,7 +117,8 @@ router.post( if (!register.allowMultipleAccounts) { // TODO: check if fingerprint was eligible generated - const exists = await db.data.users({ fingerprint }).get(); + const exists = await UserModel.findOne({ fingerprints: fingerprint }).exec(); + if (exists) { throw FieldErrors({ email: { @@ -150,7 +152,7 @@ router.post( // TODO: is there any better way to generate a random discriminator only once, without checking if it already exists in the mongodb database? for (let tries = 0; tries < 5; tries++) { discriminator = Math.randomIntBetween(1, 9999).toString().padStart(4, "0"); - exists = await db.data.users({ discriminator, username: adjusted_username }).get({ id: true }); + exists = await UserModel.findOne({ discriminator, username: adjusted_username }, "id").exec(); if (!exists) break; } @@ -164,6 +166,8 @@ router.post( } // constructing final user object + // TODO fix: + // @ts-ignore const user: User = { id: Snowflake.generate(), created_at: Date.now(), @@ -220,7 +224,7 @@ router.post( }; // insert user into database - await db.data.users.push(user); + await new UserModel(user).save({}); return res.json({ token: await generateToken(user.id) }); } diff --git a/src/routes/api/v8/guilds/index.ts b/src/routes/api/v8/guilds/index.ts
index 2d7e081a..46372a68 100644 --- a/src/routes/api/v8/guilds/index.ts +++ b/src/routes/api/v8/guilds/index.ts
@@ -1,19 +1,20 @@ import { Router, Request, Response } from "express"; -import { db, Guild, Snowflake } from "fosscord-server-util"; +import { GuildDeleteEvent, GuildModel, MemberModel, Snowflake } from "fosscord-server-util"; import { HTTPError } from "lambert-server"; import { check } from "./../../../../util/instanceOf"; -import { GuildCreateSchema, GuildGetSchema, GuildUpdateSchema } from "../../../../schema/Guild"; +import { GuildCreateSchema, GuildUpdateSchema } from "../../../../schema/Guild"; +import { emitEvent } from "../../../../util/Event"; const router: Router = Router(); router.get("/:id", async (req: Request, res: Response) => { - const member = await db.data.guilds({ id: req.params.id }).members({ id: req.userid }).get({ id: true }); + const guild = await GuildModel.findOne({ id: BigInt(req.params.id) }).exec(); + if (!guild) throw new HTTPError("Guild doesn't exist"); - if (!member) { - throw new HTTPError("you arent a member of the guild you are trying to access", 401); - } + const member = await MemberModel.findOne({ guild_id: req.params.id, id: req.userid }, "id").exec(); + + if (!member) throw new HTTPError("you arent a member of the guild you are trying to access", 401); - const guild = await db.data.guilds({ id: req.params.id }).get(GuildGetSchema); return res.json(guild); }); @@ -21,7 +22,7 @@ router.patch("/:id", check(GuildUpdateSchema), async (req: Request, res: Respons // TODO: check permission of member const body = req.body as GuildUpdateSchema; - const guild = await db.data.guilds({ id: req.params.id }).get({ id: true }); + const guild = await GuildModel.findOne({ id: BigInt(req.params.id) }).exec(); if (!guild) throw new HTTPError("This guild doesnt exist", 404); throw "not finished"; @@ -30,70 +31,40 @@ router.patch("/:id", check(GuildUpdateSchema), async (req: Request, res: Respons // // TODO: finish POST route router.post("/", check(GuildCreateSchema), async (req: Request, res: Response) => { const body = req.body as GuildCreateSchema; + // TODO: check if user is in more than 100 (config max guilds) const guildID = Snowflake.generate(); - const guild: Guild = { - // name: undefined, - // owner: undefined, - ...body, // ! contains name & icon values + const guild = { + name: body.name, + region: body.region || "en-US", owner_id: req.userid, + icon: undefined, afk_channel_id: undefined, afk_timeout: 300, application_id: undefined, banner: undefined, - channels: [], default_message_notifications: undefined, description: undefined, splash: undefined, discovery_splash: undefined, - emojis: [], explicit_content_filter: undefined, features: [], - // icon: undefined, id: guildID, - // joined_at: undefined, large: undefined, max_members: 250000, - max_presences: undefined, + max_presences: 250000, max_video_channel_users: 25, - member_count: 0, presence_count: 0, - members: [ - { - id: req.userid, - roles: [], // @everyone role is not explicitly set, the client and server automatically assumes it - joined_at: Date.now(), - nick: undefined, - premium_since: undefined, - deaf: false, - mute: false, - pending: false, - permissions: 8n, // value will be computed if a role is changed - }, - ], + member_count: 0, mfa_level: 0, preferred_locale: "en-US", premium_subscription_count: 0, premium_tier: 0, - presences: [], public_updates_channel_id: undefined, - region: undefined, - roles: [ - { - color: 0, - hoist: false, - name: "@everyone", - permissions: 0n, - id: guildID, - managed: true, // ? discord set this to true, - mentionable: false, - position: 0, - }, - ], rules_channel_id: undefined, system_channel_flags: undefined, system_channel_id: undefined, - unavailable: undefined, + unavailable: false, vanity_url_code: undefined, verification_level: undefined, voice_states: [], @@ -103,7 +74,9 @@ router.post("/", check(GuildCreateSchema), async (req: Request, res: Response) = }; try { - await db.data.guilds.push(guild); + await new GuildModel(guild).save(); + // TODO: insert default everyone role + // TODO: automatically add user to guild } catch (error) { throw new HTTPError("Couldnt create Guild", 500); } @@ -111,16 +84,29 @@ router.post("/", check(GuildCreateSchema), async (req: Request, res: Response) = }); router.delete("/:id", async (req: Request, res: Response) => { - const { id: guildID } = req.params; - - const guild = await db.data.guilds({ id: guildID }).get({ owner_id: true }); + try { + var guildID = BigInt(req.params.id); + } catch (error) { + throw new HTTPError("Invalid id format", 400); + } + const guild = await GuildModel.findOne({ id: BigInt(req.params.id) }, "owner_id").exec(); if (!guild) throw new HTTPError("This guild doesnt exist", 404); if (guild.owner_id !== req.userid) throw new HTTPError("You arent the owner of this guild", 401); - await db.data.guilds({ id: guildID }).delete(); + await emitEvent({ + event: "GUILD_DELETE", + data: { + id: guildID, + }, + guild_id: guildID, + } as GuildDeleteEvent); + + await GuildModel.deleteOne({ id: guildID }).exec(); return res.status(204); }); export default router; + +export async function addMember(guild: bigint, user: bigint) {} diff --git a/src/test/mongo_test.ts b/src/test/mongo_test.ts
index b2cc2bce..5c973429 100644 --- a/src/test/mongo_test.ts +++ b/src/test/mongo_test.ts
@@ -1,20 +1,28 @@ -import mongoose from "mongoose"; -import { Long } from "mongodb"; -import { Snowflake } from "fosscord-server-util"; +import mongoose, { Schema, Types } from "mongoose"; +import { Long as MongoTypeLong } from "mongodb"; +require("mongoose-long")(mongoose); + +const partSchema = new Schema({ + long: { + type: mongoose.Types.Long, + }, +}); + +const Part = mongoose.model("Part", partSchema, "test"); async function main() { - const conn = await mongoose.createConnection( - "mongodb://localhost:27017/lambert?readPreference=secondaryPreferred", - { - useNewUrlParser: true, - useUnifiedTopology: false, - } - ); + const conn = await mongoose.connect("mongodb://localhost:27017/lambert?readPreference=secondaryPreferred", { + useNewUrlParser: true, + useUnifiedTopology: false, + }); console.log("connected"); - const result = await conn.collection("users").insertOne({ test: Long.fromString(Snowflake.generate().toString()) }); - // .project(undefined) - console.log(result); + const part = new Part({ long: 390810485244821505n }); + + // await part.save(); + console.log("saved"); + const test = await Part.find({}); + console.log(test); } main(); diff --git a/src/util/Event.ts b/src/util/Event.ts
index 53c08e2b..c75c909f 100644 --- a/src/util/Event.ts +++ b/src/util/Event.ts
@@ -1,26 +1,10 @@ -import { db } from "fosscord-server-util"; +import { Event, EventModel } from "fosscord-server-util"; -export async function emitEvent({ - guild, - user, - channel, - event, - data, -}: { - guild?: bigint; - channel?: bigint; - user?: bigint; - event: string; - data: any; -}) { +export async function emitEvent(payload: Omit<Event, "created_at">) { const emitEvent = { created_at: Math.floor(Date.now() / 1000), // in seconds - guild_id: guild, - user_id: user, - channel_id: channel, - data, - event, + ...payload, }; - return await db.data.events.push(emitEvent); + return await new EventModel(emitEvent).save(); }