fosscord-server/pulls/858

This commit is contained in:
Madeline 2022-08-21 17:35:04 +10:00
parent 3b16a496d4
commit 7ce8543510
25 changed files with 190 additions and 74 deletions

View File

@ -135,7 +135,7 @@ router.put(
embeds,
channel_id,
attachments,
edited_timestamp: undefined,
edited_timestamp: null,
timestamp: new Date(snowflake.timestamp),
});

View File

@ -13,7 +13,8 @@ import {
MessageCreateEvent,
Snowflake,
uploadFile,
Member
Member,
Role,
} from "@fosscord/util";
import { HTTPError } from "lambert-server";
import { handleMessage, postHandleMessage, route } from "@fosscord/api";
@ -146,11 +147,11 @@ router.get("/", async (req: Request, res: Response) => {
Some clients ( discord.js ) only check if a property exists within the response,
which causes erorrs when, say, the `application` property is `null`.
**/
for (var curr in x) {
if (x[curr] === null)
delete x[curr];
}
// for (var curr in x) {
// if (x[curr] === null)
// delete x[curr];
// }
return x;
})
@ -217,7 +218,7 @@ router.post(
embeds,
channel_id,
attachments,
edited_timestamp: undefined,
edited_timestamp: null,
timestamp: new Date()
});
@ -244,8 +245,12 @@ router.post(
);
}
//Fix for the client bug
delete message.member
const member = await Member.findOneOrFail({ where: { id: req.user_id }, relations: ["roles"] });
member.roles = member.roles.filter((role: Role) => {
return role.id !== role.guild_id;
}).map((role: Role) => {
return role.id;
}) as any;
await Promise.all([
message.save(),

View File

@ -6,6 +6,14 @@ const router = Router();
export interface UserSettingsSchema extends Partial<UserSettings> {}
router.get("/", route({}), async (req: Request, res: Response) => {
const user = await User.findOneOrFail(
{ id: req.user_id },
{ relations: ["settings"] }
)
return res.json(user.settings);
});
router.patch("/", route({ body: "UserSettingsSchema" }), async (req: Request, res: Response) => {
const body = req.body as UserSettings;
if (body.locale === "en") body.locale = "en-US"; // fix discord client crash on unkown locale

View File

@ -55,7 +55,8 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
attachments: opts.attachments || [],
embeds: opts.embeds || [],
reactions: /*opts.reactions ||*/[],
type: opts.type ?? 0
type: opts.type ?? 0,
edited_timestamp: null
});
if (message.content && message.content.length > Config.get().limits.message.maxCharacters) {
@ -278,6 +279,6 @@ interface MessageOptions extends MessageCreateSchema {
embeds?: Embed[];
channel_id?: string;
attachments?: Attachment[];
edited_timestamp?: Date;
edited_timestamp: Date | null;
timestamp?: Date;
}

View File

@ -23,6 +23,7 @@
},
{
"sourceMaps": true,
"resolveSourceMapLocations": null, /* allow breakpoints in modules other than bundle */
"type": "node",
"request": "launch",
"name": "Launch Server",

BIN
bundle/package-lock.json generated

Binary file not shown.

View File

@ -40,7 +40,7 @@
"@types/jsonwebtoken": "^8.5.0",
"@types/morgan": "^1.9.3",
"@types/multer": "^1.4.7",
"@types/node": "^14.17.9",
"@types/node": "^14.18.24",
"@types/node-fetch": "^2.5.12",
"@types/node-os-utils": "^1.2.0",
"@types/supertest": "^2.0.11",
@ -112,6 +112,7 @@
"typescript-cached-transpile": "^0.0.6",
"typescript-json-schema": "^0.50.1",
"ws": "^7.4.2",
"sharp": "^0.30.7"
"sharp": "^0.30.7",
"fast-zlib": "^2.0.1"
}
}

View File

@ -17,7 +17,7 @@
"devDependencies": {
"@types/amqplib": "^0.8.1",
"@types/jsonwebtoken": "^8.5.0",
"@types/node": "^14.17.9",
"@types/node": "^14.18.24",
"@types/node-fetch": "^2.5.12",
"@types/ws": "^7.4.0",
"@zerollup/ts-transform-paths": "^1.7.18",
@ -29,6 +29,7 @@
"@fosscord/util": "file:../util",
"amqplib": "^0.8.0",
"dotenv": "^8.2.0",
"fast-zlib": "^2.0.1",
"jsonwebtoken": "^8.5.1",
"lambert-server": "^1.2.11",
"missing-native-js-functions": "^1.2.18",

View File

@ -13,6 +13,7 @@ export async function Close(this: WebSocket, code: number, reason: string) {
if (this.heartbeatTimeout) clearTimeout(this.heartbeatTimeout);
if (this.readyTimeout) clearTimeout(this.readyTimeout);
this.deflate?.close();
this.inflate?.close();
this.removeAllListeners();
if (this.session_id) {

View File

@ -6,7 +6,7 @@ import { setHeartbeat } from "../util/Heartbeat";
import { IncomingMessage } from "http";
import { Close } from "./Close";
import { Message } from "./Message";
import { createDeflate } from "zlib";
import { Deflate, Inflate } from "fast-zlib";
import { URL } from "url";
import { Config } from "@fosscord/util";
var erlpack: any;
@ -45,7 +45,6 @@ export async function Connection(
return socket.close(CLOSECODES.Decode_error);
}
// @ts-ignore
socket.version = Number(searchParams.get("version")) || 8;
if (socket.version != 8)
return socket.close(CLOSECODES.Invalid_API_version);
@ -55,8 +54,8 @@ export async function Connection(
if (socket.compress) {
if (socket.compress !== "zlib-stream")
return socket.close(CLOSECODES.Decode_error);
socket.deflate = createDeflate({ chunkSize: 65535 });
socket.deflate.on("data", (chunk) => socket.send(chunk));
socket.deflate = new Deflate();
socket.inflate = new Inflate();
}
socket.events = {};

View File

@ -3,7 +3,7 @@ import { WebSocket, Payload } from "@fosscord/gateway";
var erlpack: any;
try {
erlpack = require("@yukikaze-bot/erlpack");
} catch (error) {}
} catch (error) { }
import OPCodeHandlers from "../opcodes";
import { Tuple } from "lambert-server";
import { check } from "../opcodes/instanceOf";
@ -22,8 +22,19 @@ export async function Message(this: WebSocket, buffer: WS.Data) {
if (this.encoding === "etf" && buffer instanceof Buffer)
data = erlpack.unpack(buffer);
else if (this.encoding === "json" && typeof buffer === "string")
data = JSON.parse(buffer);
else if (this.encoding === "json" && buffer instanceof Buffer) {
if (this.inflate) {
try {
buffer = this.inflate.process(buffer) as any;
} catch {
buffer = buffer.toString() as any;
}
}
data = JSON.parse(buffer as string);
}
else if (typeof buffer == "string") {
data = JSON.parse(buffer as string);
}
else return;
check.call(this, PayloadSchema, data);
@ -42,6 +53,6 @@ export async function Message(this: WebSocket, buffer: WS.Data) {
} catch (error) {
console.error(error);
// if (!this.CLOSED && this.CLOSING)
return this.close(CLOSECODES.Unknown_error);
return this.close(CLOSECODES.Unknown_error);
}
}

View File

@ -175,7 +175,8 @@ export async function onIdentify(this: WebSocket, data: Payload) {
avatar: related_user.avatar,
bot: related_user.bot,
bio: related_user.bio,
premium_since: user.premium_since
premium_since: user.premium_since,
accent_color: related_user.accent_color,
};
users.push(public_related_user);
}
@ -222,10 +223,12 @@ export async function onIdentify(this: WebSocket, data: Payload) {
premium: user.premium,
premium_type: user.premium_type,
public_flags: user.public_flags,
premium_usage_flags: user.premium_usage_flags,
purchased_flags: user.purchased_flags,
username: user.username,
verified: user.verified,
bot: user.bot,
accent_color: user.accent_color || 0,
accent_color: user.accent_color,
banner: user.banner,
bio: user.bio,
premium_since: user.premium_since
@ -274,6 +277,8 @@ export async function onIdentify(this: WebSocket, data: Payload) {
users: users.filter((x) => x).unique(),
merged_members: merged_members,
// shard // TODO: only for user sharding
sessions: [], // TODO:
presences: [], // TODO:
};
// TODO: send real proper data structure

View File

@ -42,7 +42,14 @@ export const IdentifySchema = {
$read_state_version: Number,
$user_guild_settings_version: Number,
$user_settings_version: undefined,
$useruser_guild_settings_version: Number,
$useruser_guild_settings_version: undefined,
},
$clientState: {
$guildHashes: Object,
$highestLastMessageId: String || Number,
$readStateVersion: Number,
$useruserGuildSettingsVersion: undefined,
$userGuildSettingsVersion: undefined,
},
$v: Number,
$version: Number,
@ -76,6 +83,7 @@ export interface IdentifySchema {
presence?: ActivitySchema;
compress?: boolean;
large_threshold?: number;
largeThreshold?: number;
shard?: [bigint, bigint];
guild_subscriptions?: boolean;
capabilities?: number;
@ -87,5 +95,12 @@ export interface IdentifySchema {
user_settings_version?: number;
useruser_guild_settings_version?: number;
};
clientState?: {
guildHashes?: any;
highestLastMessageId?: string | number;
readStateVersion?: number;
userGuildSettingsVersion?: number;
useruserGuildSettingsVersion?: number;
};
v?: number;
}

View File

@ -14,9 +14,7 @@ export function Send(socket: WebSocket, data: Payload) {
else return;
// TODO: compression
if (socket.deflate) {
socket.deflate.write(buffer);
socket.deflate.flush();
return;
buffer = socket.deflate.process(buffer) as Buffer;
}
return new Promise((res, rej) => {

View File

@ -1,6 +1,6 @@
import { Intents, Permissions } from "@fosscord/util";
import WS from "ws";
import { Deflate } from "zlib";
import { Deflate, Inflate } from "fast-zlib";
export interface WebSocket extends WS {
version: number;
@ -11,6 +11,7 @@ export interface WebSocket extends WS {
shard_count?: bigint;
shard_id?: bigint;
deflate?: Deflate;
inflate?: Inflate;
heartbeatTimeout: NodeJS.Timeout;
readyTimeout: NodeJS.Timeout;
intents: Intents;

BIN
package-lock.json generated

Binary file not shown.

View File

@ -108,8 +108,8 @@ export class Channel extends BaseClass {
@Column({ nullable: true })
user_limit?: number;
@Column({ nullable: true })
nsfw?: boolean;
@Column()
nsfw: boolean = false;
@Column({ nullable: true })
rate_limit_per_user?: number;
@ -291,6 +291,7 @@ export class Channel extends BaseClass {
(x) =>
new Recipient({ user_id: x, closed: !(type === ChannelType.GROUP_DM || x === creator_user_id) })
),
nsfw: false,
}).save();
}

View File

@ -444,38 +444,4 @@ export const DefaultConfigOptions: ConfigValue = {
traceSampleRate: 1.0,
environment: hostname()
}
};
console.log((
Rights.FLAGS.MANAGE_GUILDS +
Rights.FLAGS.MANAGE_MESSAGES +
Rights.FLAGS.MANAGE_TICKETS +
Rights.FLAGS.MANAGE_USERS +
Rights.FLAGS.CREATE_CHANNELS +
Rights.FLAGS.CREATE_DMS +
Rights.FLAGS.CREATE_DM_GROUPS +
Rights.FLAGS.CREATE_GUILDS +
Rights.FLAGS.CREATE_INVITES +
Rights.FLAGS.CREATE_ROLES +
Rights.FLAGS.CREATE_TEMPLATES +
Rights.FLAGS.CREATE_WEBHOOKS +
Rights.FLAGS.JOIN_GUILDS +
Rights.FLAGS.PIN_MESSAGES +
Rights.FLAGS.SELF_ADD_REACTIONS +
Rights.FLAGS.SELF_DELETE_MESSAGES +
Rights.FLAGS.SELF_EDIT_MESSAGES +
Rights.FLAGS.SELF_EDIT_NAME +
Rights.FLAGS.SEND_MESSAGES +
Rights.FLAGS.USE_ACTIVITIES +
Rights.FLAGS.USE_VIDEO +
Rights.FLAGS.USE_VOICE +
Rights.FLAGS.INVITE_USERS +
Rights.FLAGS.SELF_DELETE_DISABLE +
Rights.FLAGS.DEBTABLE +
Rights.FLAGS.KICK_BAN_MEMBERS +
Rights.FLAGS.SELF_LEAVE_GROUPS +
Rights.FLAGS.SELF_ADD_DISCOVERABLE +
Rights.FLAGS.USE_ACHIEVEMENTS +
Rights.FLAGS.USE_MASS_INVITES
).toString())
};

View File

@ -267,8 +267,8 @@ export class Guild extends BaseClass {
@Column({ nullable: true })
nsfw_level?: number;
@Column({ nullable: true })
nsfw?: boolean;
@Column()
nsfw: boolean;
// TODO: nested guilds
@Column({ nullable: true })
@ -335,7 +335,7 @@ export class Guild extends BaseClass {
unicode_emoji: null
}).save();
if (!body.channels || !body.channels.length) body.channels = [{ id: "01", type: 0, name: "general" }];
if (!body.channels || !body.channels.length) body.channels = [{ id: "01", type: 0, name: "general", nsfw: false }];
const ids = new Map();

View File

@ -122,7 +122,7 @@ export class Message extends BaseClass {
timestamp: Date;
@Column({ nullable: true })
edited_timestamp?: Date;
edited_timestamp: Date;
@Column({ nullable: true })
tts?: boolean;

View File

@ -30,6 +30,8 @@ export enum PrivateUserEnum {
nsfw_allowed,
premium,
premium_type,
purchased_flags,
premium_usage_flags,
disabled,
settings,
// locale
@ -53,8 +55,6 @@ export interface UserPrivate extends Pick<User, PrivateUserKeys> {
locale: string;
}
// TODO: add purchased_flags, premium_usage_flags
@Entity("users")
export class User extends BaseClass {
@Column()
@ -139,6 +139,12 @@ export class User extends BaseClass {
@Column()
public_flags: number;
@Column()
purchased_flags: number;
@Column()
premium_usage_flags: number;
@Column({ type: "bigint" })
rights: string; // Rights
@ -281,6 +287,8 @@ export class User extends BaseClass {
valid_tokens_since: new Date(),
},
settings: { ...defaultSettings, locale: language },
purchased_flags: 5, // TODO: idk what the values for this are
premium_usage_flags: 2, // TODO: idk what the values for this are
extended_settings: {},
fingerprints: [],
notes: {},
@ -332,6 +340,11 @@ export const defaultSettings: UserSettings = {
stream_notifications_enabled: false,
theme: "dark",
timezone_offset: 0, // TODO: timezone from request
banner_color: null,
friend_discovery_flags: 0,
view_nsfw_guilds: true,
passwordless: false,
};
export interface UserSettings {
@ -377,6 +390,10 @@ export interface UserSettings {
stream_notifications_enabled: boolean;
theme: "dark" | "white"; // dark
timezone_offset: number; // e.g -60
banner_color: string | null;
friend_discovery_flags: number;
view_nsfw_guilds: boolean;
passwordless: boolean;
}
export const CUSTOM_USER_FLAG_OFFSET = BigInt(1) << BigInt(32);

View File

@ -98,6 +98,7 @@ export interface ReadyEventData {
merged_members?: PublicMember[][];
// probably all users who the user is in contact with
users?: PublicUser[];
sessions: any[];
}
export interface ReadyEvent extends Event {

View File

@ -0,0 +1,53 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class opencordFixes1660678870706 implements MigrationInterface {
name = 'opencordFixes1660678870706'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE \`users\`
ADD \`purchased_flags\` int NOT NULL
`);
await queryRunner.query(`
ALTER TABLE \`users\`
ADD \`premium_usage_flags\` int NOT NULL
`);
await queryRunner.query(`
ALTER TABLE \`user_settings\`
ADD \`friend_discovery_flags\` int NOT NULL
`);
await queryRunner.query(`
ALTER TABLE \`user_settings\`
ADD \`view_nsfw_guilds\` tinyint NOT NULL
`);
await queryRunner.query(`
ALTER TABLE \`user_settings\`
ADD \`passwordless\` tinyint NOT NULL
`);
await queryRunner.query(`
ALTER TABLE \`users\` CHANGE \`mfa_enabled\` \`mfa_enabled\` tinyint NOT NULL
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE \`users\` CHANGE \`mfa_enabled\` \`mfa_enabled\` tinyint NULL
`);
await queryRunner.query(`
ALTER TABLE \`user_settings\` DROP COLUMN \`passwordless\`
`);
await queryRunner.query(`
ALTER TABLE \`user_settings\` DROP COLUMN \`view_nsfw_guilds\`
`);
await queryRunner.query(`
ALTER TABLE \`user_settings\` DROP COLUMN \`friend_discovery_flags\`
`);
await queryRunner.query(`
ALTER TABLE \`users\` DROP COLUMN \`premium_usage_flags\`
`);
await queryRunner.query(`
ALTER TABLE \`users\` DROP COLUMN \`purchased_flags\`
`);
}
}

View File

@ -0,0 +1,31 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class mobileFixes21660689892073 implements MigrationInterface {
name = 'mobileFixes21660689892073'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE \`user_settings\`
ADD \`banner_color\` varchar(255) NULL
`);
await queryRunner.query(`
ALTER TABLE \`channels\` CHANGE \`nsfw\` \`nsfw\` tinyint NOT NULL
`);
await queryRunner.query(`
ALTER TABLE \`guilds\` CHANGE \`nsfw\` \`nsfw\` tinyint NOT NULL
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE \`guilds\` CHANGE \`nsfw\` \`nsfw\` tinyint NULL
`);
await queryRunner.query(`
ALTER TABLE \`channels\` CHANGE \`nsfw\` \`nsfw\` tinyint NULL
`);
await queryRunner.query(`
ALTER TABLE \`user_settings\` DROP COLUMN \`banner_color\`
`);
}
}

View File

@ -29,7 +29,7 @@ export function initDatabase(): Promise<Connection> {
url: isSqlite ? undefined : dbConnectionString,
database: isSqlite ? dbConnectionString : undefined,
// @ts-ignore
entities: Object.values(Models).filter((x) => x.constructor.name !== "Object" && x.name),
entities: Object.values(Models).filter((x) => x?.constructor?.name !== "Object" && x?.name),
synchronize: type !== "mongodb",
logging: false,
cache: {