Merge branch 'master' of https://github.com/fosscord/fosscord-server
This commit is contained in:
commit
dc01de5f6d
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,33 @@
|
||||
{
|
||||
"LoginSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"login": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"undelete": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"captcha_key": {
|
||||
"type": "string"
|
||||
},
|
||||
"login_source": {
|
||||
"type": "string"
|
||||
},
|
||||
"gift_code_sku_id": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"login",
|
||||
"password"
|
||||
],
|
||||
"$schema": "http://json-schema.org/draft-07/schema#"
|
||||
},
|
||||
"RegisterSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -42,35 +71,6 @@
|
||||
],
|
||||
"$schema": "http://json-schema.org/draft-07/schema#"
|
||||
},
|
||||
"LoginSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"login": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"undelete": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"captcha_key": {
|
||||
"type": "string"
|
||||
},
|
||||
"login_source": {
|
||||
"type": "string"
|
||||
},
|
||||
"gift_code_sku_id": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"login",
|
||||
"password"
|
||||
],
|
||||
"$schema": "http://json-schema.org/draft-07/schema#"
|
||||
},
|
||||
"ChannelModifySchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -127,10 +127,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -353,10 +353,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -727,10 +727,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -1050,10 +1050,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -1352,10 +1352,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -1657,10 +1657,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -1758,10 +1758,10 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
@ -1971,10 +1971,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -2278,10 +2278,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -2580,10 +2580,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -2894,10 +2894,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -3221,10 +3221,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -3587,10 +3587,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -3889,10 +3889,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -4191,10 +4191,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -4505,10 +4505,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -4814,10 +4814,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -5119,10 +5119,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -5424,10 +5424,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -5725,10 +5725,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -6046,10 +6046,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -6374,10 +6374,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -6680,10 +6680,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -6988,10 +6988,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -7302,10 +7302,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -7610,10 +7610,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -7939,10 +7939,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -8244,10 +8244,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -8550,10 +8550,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -9039,10 +9039,10 @@
|
||||
"$ref": "#/definitions/ChannelPermissionOverwriteType"
|
||||
},
|
||||
"allow": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
},
|
||||
"deny": {
|
||||
"type": "bigint"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
|
@ -14,8 +14,8 @@
|
||||
"dev": "tsnd --respawn src/start.ts",
|
||||
"patch": "ts-patch install -s && npx patch-package",
|
||||
"postinstall": "npm run patch",
|
||||
"generate:docs": "node scripts/generate_openapi.ts",
|
||||
"generate:schema": "node scripts/generate_schema.ts"
|
||||
"generate:docs": "node scripts/generate_openapi",
|
||||
"generate:schema": "node scripts/generate_schema"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -1,9 +1,9 @@
|
||||
// https://mermade.github.io/openapi-gui/#
|
||||
// https://editor.swagger.io/
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import * as TJS from "typescript-json-schema";
|
||||
import "missing-native-js-functions";
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const TJS = require("typescript-json-schema");
|
||||
require("missing-native-js-functions");
|
||||
const schemaPath = path.join(__dirname, "..", "assets", "schemas.json");
|
||||
|
||||
const settings = {
|
||||
|
@ -62,8 +62,8 @@ export interface ChannelModifySchema {
|
||||
permission_overwrites?: {
|
||||
id: string;
|
||||
type: ChannelPermissionOverwriteType;
|
||||
allow: bigint;
|
||||
deny: bigint;
|
||||
allow: string;
|
||||
deny: string;
|
||||
}[];
|
||||
parent_id?: string;
|
||||
id?: string; // is not used (only for guild create)
|
||||
|
@ -3,6 +3,7 @@ import {
|
||||
Attachment,
|
||||
Channel,
|
||||
ChannelType,
|
||||
Config,
|
||||
DmChannelDTO,
|
||||
Embed,
|
||||
emitEvent,
|
||||
@ -15,6 +16,7 @@ import { HTTPError } from "lambert-server";
|
||||
import { handleMessage, postHandleMessage, route } from "@fosscord/api";
|
||||
import multer from "multer";
|
||||
import { FindManyOptions, LessThan, MoreThan } from "typeorm";
|
||||
import { URL } from "url";
|
||||
|
||||
const router: Router = Router();
|
||||
|
||||
@ -111,6 +113,9 @@ router.get("/", async (req: Request, res: Response) => {
|
||||
});
|
||||
// @ts-ignore
|
||||
if (!x.author) x.author = { discriminator: "0000", username: "Deleted User", public_flags: "0", avatar: null };
|
||||
x.attachments?.forEach((x) => {
|
||||
x.proxy_url = `${Config.get().cdn.endpointPublic || "http://localhost:3003"}${new URL(x.proxy_url).pathname}`;
|
||||
});
|
||||
|
||||
return x;
|
||||
})
|
||||
|
@ -1,4 +1,13 @@
|
||||
import { Channel, ChannelPermissionOverwrite, ChannelUpdateEvent, emitEvent, getPermission, Member, Role } from "@fosscord/util";
|
||||
import {
|
||||
Channel,
|
||||
ChannelPermissionOverwrite,
|
||||
ChannelPermissionOverwriteType,
|
||||
ChannelUpdateEvent,
|
||||
emitEvent,
|
||||
getPermission,
|
||||
Member,
|
||||
Role
|
||||
} from "@fosscord/util";
|
||||
import { Router, Response, Request } from "express";
|
||||
import { HTTPError } from "lambert-server";
|
||||
|
||||
@ -14,7 +23,7 @@ router.put(
|
||||
route({ body: "ChannelPermissionOverwriteSchema", permission: "MANAGE_ROLES" }),
|
||||
async (req: Request, res: Response) => {
|
||||
const { channel_id, overwrite_id } = req.params;
|
||||
const body = req.body as { allow: bigint; deny: bigint; type: number; id: string };
|
||||
const body = req.body as ChannelPermissionOverwriteSchema;
|
||||
|
||||
var channel = await Channel.findOneOrFail({ id: channel_id });
|
||||
if (!channel.guild_id) throw new HTTPError("Channel not found", 404);
|
||||
@ -31,14 +40,12 @@ router.put(
|
||||
// @ts-ignore
|
||||
overwrite = {
|
||||
id: overwrite_id,
|
||||
type: body.type,
|
||||
allow: body.allow,
|
||||
deny: body.deny
|
||||
type: body.type
|
||||
};
|
||||
channel.permission_overwrites!.push(overwrite);
|
||||
}
|
||||
overwrite.allow = body.allow;
|
||||
overwrite.deny = body.deny;
|
||||
overwrite.allow = String(req.permission!.bitfield & (BigInt(body.allow) || 0n));
|
||||
overwrite.deny = String(req.permission!.bitfield & (BigInt(body.deny) || 0n));
|
||||
|
||||
await Promise.all([
|
||||
channel.save(),
|
||||
|
@ -5,14 +5,14 @@ import { route } from "@fosscord/api";
|
||||
const router = Router();
|
||||
|
||||
router.get("/", route({}), (req: Request, res: Response) => {
|
||||
const { endpoint } = Config.get().gateway;
|
||||
res.json({ url: endpoint || process.env.GATEWAY || "ws://localhost:3002" });
|
||||
const { endpointPublic } = Config.get().gateway;
|
||||
res.json({ url: endpointPublic || process.env.GATEWAY || "ws://localhost:3002" });
|
||||
});
|
||||
|
||||
router.get("/bot", route({}), (req: Request, res: Response) => {
|
||||
const { endpoint } = Config.get().gateway;
|
||||
const { endpointPublic } = Config.get().gateway;
|
||||
res.json({
|
||||
url: endpoint || process.env.GATEWAY || "ws://localhost:3002",
|
||||
url: endpointPublic || process.env.GATEWAY || "ws://localhost:3002",
|
||||
shards: 1,
|
||||
session_start_limit: {
|
||||
total: 1000,
|
||||
|
@ -87,7 +87,9 @@ router.post("/", route({ body: "GuildCreateSchema" }), async (req: Request, res:
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
body.channels?.map((x) => {
|
||||
body.channels
|
||||
?.sort((a, b) => (a.parent_id ? -1 : 1))
|
||||
.map((x) => {
|
||||
var id = ids.get(x.id) || Snowflake.generate();
|
||||
|
||||
// TODO: should we abort if parent_id is a category? (to disallow sub category channels)
|
||||
|
@ -1,53 +0,0 @@
|
||||
import { Config } from "@fosscord/util";
|
||||
import FormData from "form-data";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import fetch from "node-fetch";
|
||||
|
||||
export async function uploadFile(path: string, file: Express.Multer.File) {
|
||||
const form = new FormData();
|
||||
form.append("file", file.buffer, {
|
||||
contentType: file.mimetype,
|
||||
filename: file.originalname
|
||||
});
|
||||
|
||||
const response = await fetch(`${Config.get().cdn.endpoint || "http://localhost:3003"}${path}`, {
|
||||
headers: {
|
||||
signature: Config.get().security.requestSignature,
|
||||
...form.getHeaders()
|
||||
},
|
||||
method: "POST",
|
||||
body: form
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (response.status !== 200) throw result;
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function handleFile(path: string, body?: string): Promise<string | undefined> {
|
||||
if (!body || !body.startsWith("data:")) return body;
|
||||
try {
|
||||
const mimetype = body.split(":")[1].split(";")[0];
|
||||
const buffer = Buffer.from(body.split(",")[1], "base64");
|
||||
|
||||
// @ts-ignore
|
||||
const { id } = await uploadFile(path, { buffer, mimetype, originalname: "banner" });
|
||||
return id;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw new HTTPError("Invalid " + path);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteFile(path: string) {
|
||||
const response = await fetch(`${Config.get().cdn.endpoint || "http://localhost:3003"}${path}`, {
|
||||
headers: {
|
||||
signature: Config.get().security.requestSignature
|
||||
},
|
||||
method: "DELETE"
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (response.status !== 200) throw result;
|
||||
return result;
|
||||
}
|
@ -81,10 +81,10 @@ export function route(opts: RouteOptions) {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
if (opts.permission) {
|
||||
const required = new Permissions(opts.permission);
|
||||
const permission = await getPermission(req.user_id, req.params.guild_id, req.params.channel_id);
|
||||
req.permission = await getPermission(req.user_id, req.params.guild_id, req.params.channel_id);
|
||||
|
||||
// bitfield comparison: check if user lacks certain permission
|
||||
if (!permission.has(required)) {
|
||||
if (!req.permission.has(required)) {
|
||||
throw DiscordApiErrors.MISSING_PERMISSIONS.withParams(opts.permission as string);
|
||||
}
|
||||
}
|
||||
|
@ -24,16 +24,24 @@ const gateway = new GatewayServer({ server, port, production });
|
||||
async function main() {
|
||||
await initDatabase();
|
||||
await Config.init();
|
||||
// only set endpointPublic, if not already set
|
||||
await Config.set({
|
||||
cdn: {
|
||||
endpointClient: "${location.host}",
|
||||
endpoint: `http://localhost:${port}`,
|
||||
endpointPrivate: `http://localhost:${port}`,
|
||||
...(!Config.get().cdn.endpointPublic && {
|
||||
endpointPublic: `http://localhost:${port}`,
|
||||
}),
|
||||
},
|
||||
gateway: {
|
||||
endpointClient: '${location.protocol === "https:" ? "wss://" : "ws://"}${location.host}',
|
||||
endpoint: `ws://localhost:${port}`,
|
||||
endpointClient:
|
||||
'${location.protocol === "https:" ? "wss://" : "ws://"}${location.host}',
|
||||
endpointPrivate: `ws://localhost:${port}`,
|
||||
...(!Config.get().gateway.endpointPublic && {
|
||||
endpointPublic: `http://localhost:${port}`,
|
||||
}),
|
||||
},
|
||||
});
|
||||
} as any);
|
||||
|
||||
await Promise.all([api.start(), cdn.start(), gateway.start()]);
|
||||
console.log(`[Server] listening on port ${port}`);
|
||||
|
@ -9,16 +9,20 @@ export function initStats() {
|
||||
console.log(`[Process] running with pid: ${process.pid}`);
|
||||
|
||||
setInterval(async () => {
|
||||
const [cpuUsed, memory, network] = await Promise.all([osu.cpu.usage(), osu.mem.info(), osu.netstat.inOut()]);
|
||||
const [cpuUsed, memory, network] = await Promise.all([
|
||||
osu.cpu.usage(),
|
||||
osu.mem.info(),
|
||||
osu.netstat.inOut(),
|
||||
]);
|
||||
var networkUsage = "";
|
||||
if (typeof network === "object") {
|
||||
networkUsage = `| [Network]: in ${network.total.inputMb}mb | out ${network.total.outputMb}mb`;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`[CPU] ${cpuUsed.toFixed(2)}% | [Memory] ${Math.round(
|
||||
`[CPU] ${cpuUsed.toPrecision(3)}% | [Memory] ${Math.round(
|
||||
process.memoryUsage().rss / 1024 / 1024
|
||||
)}mb/${memory.totalMemMb.toFixed(0)}mb ${networkUsage}`
|
||||
);
|
||||
}, 1000 * 30);
|
||||
}, 1000 * 5);
|
||||
}
|
||||
|
@ -8,6 +8,13 @@ import imageSize from "image-size";
|
||||
|
||||
const router = Router();
|
||||
|
||||
const SANITIZED_CONTENT_TYPE = [
|
||||
"text/html",
|
||||
"text/mhtml",
|
||||
"multipart/related",
|
||||
"application/xhtml+xml",
|
||||
];
|
||||
|
||||
router.post(
|
||||
"/:channel_id",
|
||||
multer.single("file"),
|
||||
@ -24,7 +31,8 @@ router.post(
|
||||
const id = Snowflake.generate();
|
||||
const path = `attachments/${channel_id}/${id}/${filename}`;
|
||||
|
||||
const endpoint = Config.get()?.cdn.endpoint || "http://localhost:3003";
|
||||
const endpoint =
|
||||
Config.get()?.cdn.endpointPublic || "http://localhost:3003";
|
||||
|
||||
await storage.set(path, buffer);
|
||||
var width;
|
||||
@ -61,8 +69,13 @@ router.get(
|
||||
);
|
||||
if (!file) throw new HTTPError("File not found");
|
||||
const type = await FileType.fromBuffer(file);
|
||||
let content_type = type?.mime || "application/octet-stream";
|
||||
|
||||
res.set("Content-Type", type?.mime);
|
||||
if (SANITIZED_CONTENT_TYPE.includes(content_type)) {
|
||||
content_type = "application/octet-stream";
|
||||
}
|
||||
|
||||
res.set("Content-Type", content_type);
|
||||
res.set("Cache-Control", "public, max-age=31536000");
|
||||
|
||||
return res.send(file);
|
||||
|
@ -44,7 +44,8 @@ router.post(
|
||||
if (ANIMATED_MIME_TYPES.includes(type.mime)) hash = `a_${hash}`; // animated icons have a_ infront of the hash
|
||||
|
||||
const path = `avatars/${user_id}/${hash}`;
|
||||
const endpoint = Config.get().cdn.endpoint || "http://localhost:3003";
|
||||
const endpoint =
|
||||
Config.get().cdn.endpointPublic || "http://localhost:3003";
|
||||
|
||||
await storage.set(path, buffer);
|
||||
|
||||
|
@ -320,8 +320,8 @@ export class Channel extends BaseClass {
|
||||
}
|
||||
|
||||
export interface ChannelPermissionOverwrite {
|
||||
allow: bigint; // for bitfields we use bigints
|
||||
deny: bigint; // for bitfields we use bigints
|
||||
allow: string;
|
||||
deny: string;
|
||||
id: string;
|
||||
type: ChannelPermissionOverwriteType;
|
||||
}
|
||||
|
@ -1,12 +1,15 @@
|
||||
import { Column, Entity, JoinColumn, ManyToOne } from "typeorm";
|
||||
import { BaseClass } from "./BaseClass";
|
||||
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from "typeorm";
|
||||
import { BaseClass, BaseClassWithoutId } from "./BaseClass";
|
||||
import crypto from "crypto";
|
||||
import { Snowflake } from "../util/Snowflake";
|
||||
|
||||
@Entity("config")
|
||||
export class ConfigEntity extends BaseClass {
|
||||
@Column({ type: "simple-json" })
|
||||
value: ConfigValue;
|
||||
export class ConfigEntity extends BaseClassWithoutId {
|
||||
@PrimaryColumn()
|
||||
key: string;
|
||||
|
||||
@Column({ type: "simple-json", nullable: true })
|
||||
value: number | boolean | null | string | undefined;
|
||||
}
|
||||
|
||||
export interface RateLimitOptions {
|
||||
@ -37,14 +40,16 @@ export interface KafkaBroker {
|
||||
export interface ConfigValue {
|
||||
gateway: {
|
||||
endpointClient: string | null;
|
||||
endpoint: string | null;
|
||||
endpointPrivate: string | null;
|
||||
endpointPublic: string | null;
|
||||
};
|
||||
cdn: {
|
||||
endpointClient: string | null;
|
||||
endpoint: string | null;
|
||||
endpointPublic: string | null;
|
||||
endpointPrivate: string | null;
|
||||
};
|
||||
general: {
|
||||
instance_id: string;
|
||||
instanceId: string;
|
||||
};
|
||||
permissions: {
|
||||
user: {
|
||||
@ -149,14 +154,16 @@ export interface ConfigValue {
|
||||
export const DefaultConfigOptions: ConfigValue = {
|
||||
gateway: {
|
||||
endpointClient: null,
|
||||
endpoint: null,
|
||||
endpointPrivate: null,
|
||||
endpointPublic: null,
|
||||
},
|
||||
cdn: {
|
||||
endpointClient: null,
|
||||
endpoint: null,
|
||||
endpointPrivate: null,
|
||||
endpointPublic: null,
|
||||
},
|
||||
general: {
|
||||
instance_id: Snowflake.generate(),
|
||||
instanceId: Snowflake.generate(),
|
||||
},
|
||||
permissions: {
|
||||
user: {
|
||||
|
@ -1,22 +1,66 @@
|
||||
import "missing-native-js-functions";
|
||||
import { ConfigValue, ConfigEntity, DefaultConfigOptions } from "../entities/Config";
|
||||
|
||||
var config: ConfigEntity;
|
||||
var config: ConfigValue;
|
||||
var pairs: ConfigEntity[];
|
||||
|
||||
// TODO: use events to inform about config updates
|
||||
// Config keys are separated with _
|
||||
|
||||
export const Config = {
|
||||
init: async function init() {
|
||||
if (config) return config;
|
||||
config = (await ConfigEntity.findOne({ id: "0" })) || new ConfigEntity({ id: "0" });
|
||||
pairs = await ConfigEntity.find();
|
||||
config = pairsToConfig(pairs);
|
||||
|
||||
return this.set((config.value || {}).merge(DefaultConfigOptions));
|
||||
return this.set((config || {}).merge(DefaultConfigOptions));
|
||||
},
|
||||
get: function get() {
|
||||
return config.value as ConfigValue;
|
||||
return config;
|
||||
},
|
||||
set: function set(val: Partial<ConfigValue>) {
|
||||
if (!config) return;
|
||||
config.value = val.merge(config?.value || {});
|
||||
return config.save();
|
||||
if (!config || !val) return;
|
||||
config = val.merge(config);
|
||||
console.log(config);
|
||||
|
||||
return applyConfig(config);
|
||||
},
|
||||
};
|
||||
|
||||
function applyConfig(val: ConfigValue) {
|
||||
async function apply(obj: any, key = ""): Promise<any> {
|
||||
if (typeof obj === "object" && obj !== null)
|
||||
return Promise.all(Object.keys(obj).map((k) => apply(obj[k], key ? `${key}_${k}` : k)));
|
||||
|
||||
let pair = pairs.find((x) => x.key === key);
|
||||
if (!pair) pair = new ConfigEntity();
|
||||
|
||||
pair.key = key;
|
||||
pair.value = obj;
|
||||
return pair.save();
|
||||
}
|
||||
|
||||
return apply(val);
|
||||
}
|
||||
|
||||
function pairsToConfig(pairs: ConfigEntity[]) {
|
||||
var value: any = {};
|
||||
|
||||
pairs.forEach((p) => {
|
||||
const keys = p.key.split("_");
|
||||
let prev = "";
|
||||
let obj = value;
|
||||
let i = 0;
|
||||
|
||||
for (const key of keys) {
|
||||
if (Number(key) && !obj[prev]) obj = obj[prev] = [];
|
||||
if (i++ === keys.length - 1) obj[key] = p.value;
|
||||
else if (!obj[key]) obj[key] = {};
|
||||
|
||||
prev = key;
|
||||
obj = obj[key];
|
||||
}
|
||||
});
|
||||
|
||||
return value as ConfigValue;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ export function initDatabase() {
|
||||
//
|
||||
entities: Object.values(Models).filter((x) => x.constructor.name !== "Object"),
|
||||
synchronize: true,
|
||||
logging: true,
|
||||
logging: false,
|
||||
cache: {
|
||||
duration: 1000 * 3, // cache all find queries for 3 seconds
|
||||
},
|
||||
|
@ -3,6 +3,7 @@
|
||||
import { Channel, ChannelPermissionOverwrite, Guild, Member, Role } from "../entities";
|
||||
import { BitField } from "./BitField";
|
||||
import "missing-native-js-functions";
|
||||
import { BitFieldResolvable } from ".";
|
||||
// TODO: check role hierarchy permission
|
||||
|
||||
var HTTPError: any;
|
||||
@ -17,11 +18,19 @@ export type PermissionResolvable = bigint | number | Permissions | PermissionRes
|
||||
|
||||
type PermissionString = keyof typeof Permissions.FLAGS;
|
||||
|
||||
const CUSTOM_PERMISSION_OFFSET = BigInt(1) << BigInt(48); // 16 free custom permission bits, and 11 for discord to add new ones
|
||||
// BigInt doesn't have a bit limit (https://stackoverflow.com/questions/53335545/whats-the-biggest-bigint-value-in-js-as-per-spec)
|
||||
const CUSTOM_PERMISSION_OFFSET = BigInt(1) << BigInt(64); // 27 permission bits left for discord to add new ones
|
||||
|
||||
export class Permissions extends BitField {
|
||||
cache: PermissionCache = {};
|
||||
|
||||
constructor(bits: BitFieldResolvable = 0) {
|
||||
super(bits);
|
||||
if (this.bitfield & Permissions.FLAGS.ADMINISTRATOR) {
|
||||
this.bitfield = ALL_PERMISSIONS;
|
||||
}
|
||||
}
|
||||
|
||||
static FLAGS = {
|
||||
CREATE_INSTANT_INVITE: BigInt(1) << BigInt(0),
|
||||
KICK_MEMBERS: BigInt(1) << BigInt(1),
|
||||
@ -92,7 +101,7 @@ export class Permissions extends BitField {
|
||||
}
|
||||
|
||||
overwriteChannel(overwrites: ChannelPermissionOverwrite[]) {
|
||||
if (!overwrites) return this
|
||||
if (!overwrites) return this;
|
||||
if (!this.cache) throw new Error("permission chache not available");
|
||||
overwrites = overwrites.filter((x) => {
|
||||
if (x.type === 0 && this.cache.roles?.some((r) => r.id === x.id)) return true;
|
||||
@ -175,6 +184,8 @@ export class Permissions extends BitField {
|
||||
}
|
||||
}
|
||||
|
||||
const ALL_PERMISSIONS = Object.values(Permissions.FLAGS).reduce((total, val) => total | val, BigInt(0));
|
||||
|
||||
export type PermissionCache = {
|
||||
channel?: Channel | undefined;
|
||||
member?: Member | undefined;
|
||||
|
@ -11,7 +11,7 @@ export async function uploadFile(path: string, file: Express.Multer.File) {
|
||||
filename: file.originalname,
|
||||
});
|
||||
|
||||
const response = await fetch(`${Config.get().cdn.endpoint || "http://localhost:3003"}${path}`, {
|
||||
const response = await fetch(`${Config.get().cdn.endpointPrivate || "http://localhost:3003"}${path}`, {
|
||||
headers: {
|
||||
signature: Config.get().security.requestSignature,
|
||||
...form.getHeaders(),
|
||||
@ -41,7 +41,7 @@ export async function handleFile(path: string, body?: string): Promise<string |
|
||||
}
|
||||
|
||||
export async function deleteFile(path: string) {
|
||||
const response = await fetch(`${Config.get().cdn.endpoint || "http://localhost:3003"}${path}`, {
|
||||
const response = await fetch(`${Config.get().cdn.endpointPrivate || "http://localhost:3003"}${path}`, {
|
||||
headers: {
|
||||
signature: Config.get().security.requestSignature,
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user