Merge branch 'fosscord:master' into master

This commit is contained in:
Featyre 2022-01-24 05:25:22 +00:00 committed by GitHub
commit edd5cf651c
4 changed files with 420 additions and 334 deletions

View File

@ -37,7 +37,11 @@ export function isTextChannel(type: ChannelType): boolean {
case ChannelType.GUILD_PUBLIC_THREAD: case ChannelType.GUILD_PUBLIC_THREAD:
case ChannelType.GUILD_PRIVATE_THREAD: case ChannelType.GUILD_PRIVATE_THREAD:
case ChannelType.GUILD_TEXT: case ChannelType.GUILD_TEXT:
case ChannelType.ENCRYPTED:
case ChannelType.ENCRYPTED_THREAD:
return true; return true;
default:
throw new HTTPError("unimplemented", 400);
} }
} }
@ -87,7 +91,7 @@ router.get("/", async (req: Request, res: Response) => {
permissions.hasThrow("VIEW_CHANNEL"); permissions.hasThrow("VIEW_CHANNEL");
if (!permissions.has("READ_MESSAGE_HISTORY")) return res.json([]); if (!permissions.has("READ_MESSAGE_HISTORY")) return res.json([]);
var query: FindManyOptions<Message> & { where: { id?: any } } = { var query: FindManyOptions<Message> & { where: { id?: any; }; } = {
order: { id: "DESC" }, order: { id: "DESC" },
take: limit, take: limit,
where: { channel_id }, where: { channel_id },
@ -216,7 +220,7 @@ router.post(
channel.save() channel.save()
]); ]);
postHandleMessage(message).catch((e) => {}); // no await as it shouldnt block the message send function and silently catch error postHandleMessage(message).catch((e) => { }); // no await as it shouldnt block the message send function and silently catch error
return res.json(message); return res.json(message);
} }

View File

@ -3,7 +3,7 @@ import { BaseClass } from "./BaseClass";
import { Guild } from "./Guild"; import { Guild } from "./Guild";
import { PublicUserProjection, User } from "./User"; import { PublicUserProjection, User } from "./User";
import { HTTPError } from "lambert-server"; import { HTTPError } from "lambert-server";
import { containsAll, emitEvent, getPermission, Snowflake, trimSpecial } from "../util"; import { containsAll, emitEvent, getPermission, Snowflake, trimSpecial, InvisibleCharacters } from "../util";
import { ChannelCreateEvent, ChannelRecipientRemoveEvent } from "../interfaces"; import { ChannelCreateEvent, ChannelRecipientRemoveEvent } from "../interfaces";
import { Recipient } from "./Recipient"; import { Recipient } from "./Recipient";
import { Message } from "./Message"; import { Message } from "./Message";
@ -21,11 +21,14 @@ export enum ChannelType {
GUILD_CATEGORY = 4, // an organizational category that contains up to 50 channels GUILD_CATEGORY = 4, // an organizational category that contains up to 50 channels
GUILD_NEWS = 5, // a channel that users can follow and crosspost into their own server GUILD_NEWS = 5, // a channel that users can follow and crosspost into their own server
GUILD_STORE = 6, // a channel in which game developers can sell their game on Discord GUILD_STORE = 6, // a channel in which game developers can sell their game on Discord
// TODO: what are channel types between 7-9? ENCRYPTED = 7, // end-to-end encrypted channel
ENCRYPTED_THREAD = 8, // end-to-end encrypted thread channel
GUILD_NEWS_THREAD = 10, // a temporary sub-channel within a GUILD_NEWS channel GUILD_NEWS_THREAD = 10, // a temporary sub-channel within a GUILD_NEWS channel
GUILD_PUBLIC_THREAD = 11, // a temporary sub-channel within a GUILD_TEXT channel GUILD_PUBLIC_THREAD = 11, // a temporary sub-channel within a GUILD_TEXT channel
GUILD_PRIVATE_THREAD = 12, // a temporary sub-channel within a GUILD_TEXT channel that is only viewable by those invited and those with the MANAGE_THREADS permission GUILD_PRIVATE_THREAD = 12, // a temporary sub-channel within a GUILD_TEXT channel that is only viewable by those invited and those with the MANAGE_THREADS permission
GUILD_STAGE_VOICE = 13, // a voice channel for hosting events with an audience GUILD_STAGE_VOICE = 13, // a voice channel for hosting events with an audience
CUSTOM_START = 64, // start custom channel types from here
UNHANDLED = 255 // unhandled unowned pass-through channel type
} }
@Entity("channels") @Entity("channels")
@ -147,6 +150,7 @@ export class Channel extends BaseClass {
skipExistsCheck?: boolean; skipExistsCheck?: boolean;
skipPermissionCheck?: boolean; skipPermissionCheck?: boolean;
skipEventEmit?: boolean; skipEventEmit?: boolean;
skipNameChecks?: boolean;
} }
) { ) {
if (!opts?.skipPermissionCheck) { if (!opts?.skipPermissionCheck) {
@ -155,6 +159,27 @@ export class Channel extends BaseClass {
permissions.hasThrow("MANAGE_CHANNELS"); permissions.hasThrow("MANAGE_CHANNELS");
} }
if (!opts?.skipNameChecks) {
const guild = await Guild.findOneOrFail({ id: channel.guild_id });
if (!guild.features.includes("ALLOW_INVALID_CHANNEL_NAMES") && channel.name) {
for (var character of InvisibleCharacters)
if (channel.name.includes(character))
throw new HTTPError("Channel name cannot include invalid characters", 403);
if (channel.name.match(/\-\-+/g))
throw new HTTPError("Channel name cannot include multiple adjacent dashes.", 403)
if (channel.name.charAt(0) === "-" ||
channel.name.charAt(channel.name.length - 1) === "-")
throw new HTTPError("Channel name cannot start/end with dash.", 403)
}
if (!guild.features.includes("ALLOW_UNNAMED_CHANNELS")) {
if (!channel.name)
throw new HTTPError("Channel name cannot be empty.", 403);
}
}
switch (channel.type) { switch (channel.type) {
case ChannelType.GUILD_TEXT: case ChannelType.GUILD_TEXT:
case ChannelType.GUILD_VOICE: case ChannelType.GUILD_VOICE:
@ -239,7 +264,7 @@ export class Channel extends BaseClass {
channel = await new Channel({ channel = await new Channel({
name, name,
type, type,
owner_id: type === ChannelType.DM ? undefined : creator_user_id, owner_id: type === ChannelType.DM ? undefined : null, // 1:1 DMs are ownerless in fosscord-server
created_at: new Date(), created_at: new Date(),
last_message_id: null, last_message_id: null,
recipients: channelRecipients.map( recipients: channelRecipients.map(
@ -286,9 +311,9 @@ export class Channel extends BaseClass {
user_id: user_id, user_id: user_id,
}); });
//If the owner leave we make the first recipient in the list the new owner //If the owner leave the server user is the new owner
if (channel.owner_id === user_id) { if (channel.owner_id === user_id) {
channel.owner_id = channel.recipients!.find((r) => r.user_id !== user_id)!.user_id; //Is there a criteria to choose the new owner? channel.owner_id = "1"; // The channel is now owned by the server user
await emitEvent({ await emitEvent({
event: "CHANNEL_UPDATE", event: "CHANNEL_UPDATE",
data: await DmChannelDTO.from(channel, [user_id]), data: await DmChannelDTO.from(channel, [user_id]),

View File

@ -0,0 +1,56 @@
// List from https://invisible-characters.com/
export const InvisibleCharacters = [
'\u{9}', //Tab
'\u{20}', //Space
'\u{ad}', //Soft hyphen
'\u{34f}', //Combining grapheme joiner
'\u{61c}', //Arabic letter mark
'\u{115f}', //Hangul choseong filler
'\u{1160}', //Hangul jungseong filler
'\u{17b4}', //Khmer vowel inherent AQ
'\u{17b5}', //Khmer vowel inherent AA
'\u{180e}', //Mongolian vowel separator
'\u{2000}', //En quad
'\u{2001}', //Em quad
'\u{2002}', //En space
'\u{2003}', //Em space
'\u{2004}', //Three-per-em space
'\u{2005}', //Four-per-em space
'\u{2006}', //Six-per-em space
'\u{2007}', //Figure space
'\u{2008}', //Punctuation space
'\u{2009}', //Thin space
'\u{200a}', //Hair space
'\u{200b}', //Zero width space
'\u{200c}', //Zero width non-joiner
'\u{200d}', //Zero width joiner
'\u{200e}', //Left-to-right mark
'\u{200f}', //Right-to-left mark
'\u{202f}', //Narrow no-break space
'\u{205f}', //Medium mathematical space
'\u{2060}', //Word joiner
'\u{2061}', //Function application
'\u{2062}', //Invisible times
'\u{2063}', //Invisible separator
'\u{2064}', //Invisible plus
'\u{206a}', //Inhibit symmetric swapping
'\u{206b}', //Activate symmetric swapping
'\u{206c}', //Inhibit arabic form shaping
'\u{206d}', //Activate arabic form shaping
'\u{206e}', //National digit shapes
'\u{206f}', //Nominal digit shapes
'\u{3000}', //Ideographic space
'\u{2800}', //Braille pattern blank
'\u{3164}', //Hangul filler
'\u{feff}', //Zero width no-break space
'\u{ffa0}', //Haldwidth hangul filler
'\u{1d159}', //Musical symbol null notehead
'\u{1d173}', //Musical symbol begin beam
'\u{1d174}', //Musical symbol end beam
'\u{1d175}', //Musical symbol begin tie
'\u{1d176}', //Musical symbol end tie
'\u{1d177}', //Musical symbol begin slur
'\u{1d178}', //Musical symbol end slur
'\u{1d179}', //Musical symbol begin phrase
'\u{1d17a}' //Musical symbol end phrase
];

View File

@ -18,3 +18,4 @@ export * from "./Snowflake";
export * from "./String"; export * from "./String";
export * from "./Array"; export * from "./Array";
export * from "./TraverseDirectory"; export * from "./TraverseDirectory";
export * from "./InvisibleCharacters";