diff --git a/util/src/entities/AuditLog.ts b/util/src/entities/AuditLog.ts
index 4b81ed6a..b003e7ba 100644
--- a/util/src/entities/AuditLog.ts
+++ b/util/src/entities/AuditLog.ts
@@ -4,41 +4,93 @@ import { ChannelPermissionOverwrite } from "./Channel";
import { User } from "./User";
export enum AuditLogEvents {
- GUILD_UPDATE = 1,
- CHANNEL_CREATE = 10,
+ // guild level
+ GUILD_UPDATE = 1,
+ GUILD_IMPORT = 2,
+ GUILD_EXPORTED = 3,
+ GUILD_ARCHIVE = 4,
+ GUILD_UNARCHIVE = 5,
+ // join-leave
+ USER_JOIN = 6,
+ USER_LEAVE = 7,
+ // channels
+ CHANNEL_CREATE = 10,
CHANNEL_UPDATE = 11,
CHANNEL_DELETE = 12,
- CHANNEL_OVERWRITE_CREATE = 13,
+ // permission overrides
+ CHANNEL_OVERWRITE_CREATE = 13,
CHANNEL_OVERWRITE_UPDATE = 14,
CHANNEL_OVERWRITE_DELETE = 15,
- MEMBER_KICK = 20,
+ // kick and ban
+ MEMBER_KICK = 20,
MEMBER_PRUNE = 21,
MEMBER_BAN_ADD = 22,
MEMBER_BAN_REMOVE = 23,
+ // member updates
MEMBER_UPDATE = 24,
MEMBER_ROLE_UPDATE = 25,
MEMBER_MOVE = 26,
MEMBER_DISCONNECT = 27,
BOT_ADD = 28,
+ // roles
ROLE_CREATE = 30,
ROLE_UPDATE = 31,
ROLE_DELETE = 32,
+ ROLE_SWAP = 33,
+ // invites
INVITE_CREATE = 40,
INVITE_UPDATE = 41,
INVITE_DELETE = 42,
+ // webhooks
WEBHOOK_CREATE = 50,
WEBHOOK_UPDATE = 51,
WEBHOOK_DELETE = 52,
+ WEBHOOK_SWAP = 53,
+ // custom emojis
EMOJI_CREATE = 60,
EMOJI_UPDATE = 61,
EMOJI_DELETE = 62,
+ EMOJI_SWAP = 63,
+ // deletion
+ MESSAGE_CREATE = 70, // messages sent using non-primary seat of the user only
+ MESSAGE_EDIT = 71, // non-self edits only
MESSAGE_DELETE = 72,
MESSAGE_BULK_DELETE = 73,
+ // pinning
MESSAGE_PIN = 74,
MESSAGE_UNPIN = 75,
+ // integrations
INTEGRATION_CREATE = 80,
INTEGRATION_UPDATE = 81,
INTEGRATION_DELETE = 82,
+ // stage actions
+ STAGE_INSTANCE_CREATE = 83,
+ STAGE_INSTANCE_UPDATE = 84,
+ STAGE_INSTANCE_DELETE = 85,
+ // stickers
+ STICKER_CREATE = 90,
+ STICKER_UPDATE = 91,
+ STICKER_DELETE = 92,
+ STICKER_SWAP = 93,
+ // threads
+ THREAD_CREATE = 110,
+ THREAD_UPDATE = 111,
+ THREAD_DELETE = 112,
+ // application commands
+ APPLICATION_COMMAND_PERMISSION_UPDATE = 121,
+ // automod
+ POLICY_CREATE = 140,
+ POLICY_UPDATE = 141,
+ POLICY_DELETE = 142,
+ MESSAGE_BLOCKED_BY_POLICIES = 143, // in fosscord, blocked messages are stealth-dropped
+ // instance policies affecting the guild
+ GUILD_AFFECTED_BY_POLICIES = 216,
+ // message moves
+ IN_GUILD_MESSAGE_MOVE = 223,
+ CROSS_GUILD_MESSAGE_MOVE = 224,
+ // message routing
+ ROUTE_CREATE = 225,
+ ROUTE_UPDATE = 226,
}
@Entity("audit_logs")
diff --git a/util/src/entities/Channel.ts b/util/src/entities/Channel.ts
index 4bf81901..f3c40c83 100644
--- a/util/src/entities/Channel.ts
+++ b/util/src/entities/Channel.ts
@@ -3,7 +3,7 @@ import { BaseClass } from "./BaseClass";
import { Guild } from "./Guild";
import { PublicUserProjection, User } from "./User";
import { HTTPError } from "lambert-server";
-import { containsAll, emitEvent, getPermission, Snowflake, trimSpecial, InvisibleCharacters } from "../util";
+import { containsAll, emitEvent, getPermission, Snowflake, trimSpecial, InvisibleCharacters, ChannelTypes } from "../util";
import { ChannelCreateEvent, ChannelRecipientRemoveEvent } from "../interfaces";
import { Recipient } from "./Recipient";
import { Message } from "./Message";
@@ -28,6 +28,8 @@ export enum ChannelType {
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_STAGE_VOICE = 13, // a voice channel for hosting events with an audience
+ DIRECTORY = 14, // guild directory listing channel
+ GUILD_FORUM = 15, // forum composed of IM threads
TICKET_TRACKER = 33, // ticket tracker, individual ticket items shall have type 12
KANBAN = 34, // confluence like kanban board
VOICELESS_WHITEBOARD = 35, // whiteboard but without voice (whiteboard + voice is the same as stage)
@@ -147,7 +149,7 @@ export class Channel extends BaseClass {
orphanedRowAction: "delete",
})
webhooks?: Webhook[];
-
+
// TODO: DM channel
static async createChannel(
channel: Partial<Channel>,
@@ -173,12 +175,20 @@ export class Channel extends BaseClass {
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)
+ // Categories skip these checks on discord.com
+ if (channel.type !== ChannelType.GUILD_CATEGORY) {
+ if (channel.name.includes(" "))
+ 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 (channel.name.charAt(0) === "-" ||
+ channel.name.charAt(channel.name.length - 1) === "-")
+ throw new HTTPError("Channel name cannot start/end with dash.", 403);
+ }
+ else
+ channel.name = channel.name.trim(); //category names are trimmed client side on discord.com
}
if (!guild.features.includes("ALLOW_UNNAMED_CHANNELS")) {
@@ -297,7 +307,7 @@ export class Channel extends BaseClass {
await emitEvent({ event: "CHANNEL_CREATE", data: channel_dto, user_id: creator_user_id });
}
- if (recipients.length === 1) return channel_dto;
+ if (recipients.length === 1) return channel_dto;
else return channel_dto.excludedRecipients([creator_user_id]);
}
@@ -352,6 +362,16 @@ export class Channel extends BaseClass {
isDm() {
return this.type === ChannelType.DM || this.type === ChannelType.GROUP_DM;
}
+
+ // Does the channel support sending messages ( eg categories do not )
+ isWritable() {
+ const disallowedChannelTypes = [
+ ChannelType.GUILD_CATEGORY,
+ ChannelType.GUILD_STAGE_VOICE,
+ ChannelType.VOICELESS_WHITEBOARD,
+ ];
+ return disallowedChannelTypes.indexOf(this.type) == -1;
+ }
}
export interface ChannelPermissionOverwrite {
diff --git a/util/src/entities/Config.ts b/util/src/entities/Config.ts
index 8d29b387..f77991a9 100644
--- a/util/src/entities/Config.ts
+++ b/util/src/entities/Config.ts
@@ -4,6 +4,7 @@ import crypto from "crypto";
import { Snowflake } from "../util/Snowflake";
import { SessionsReplace } from "..";
import { hostname } from "os";
+import { Rights } from "../util/Rights";
@Entity("config")
export class ConfigEntity extends BaseClassWithoutId {
@@ -120,6 +121,7 @@ export interface ConfigValue {
secret: string | null;
};
ipdataApiKey: string | null;
+ defaultRights: string;
};
login: {
requireCaptcha: boolean;
@@ -311,6 +313,33 @@ export const DefaultConfigOptions: ConfigValue = {
secret: null,
},
ipdataApiKey: "eca677b284b3bac29eb72f5e496aa9047f26543605efe99ff2ce35c9",
+ defaultRights: (
+ 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
+ ).toString()
},
login: {
requireCaptcha: false,
@@ -324,7 +353,7 @@ export const DefaultConfigOptions: ConfigValue = {
// domains: fs.readFileSync(__dirname + "/blockedEmailDomains.txt", { encoding: "utf8" }).split("\n"),
},
dateOfBirth: {
- required: false,
+ required: true,
minimum: 13,
},
disabled: false,
diff --git a/util/src/entities/Group.ts b/util/src/entities/Group.ts
new file mode 100644
index 00000000..b24d38cf
--- /dev/null
+++ b/util/src/entities/Group.ts
@@ -0,0 +1,33 @@
+import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+
+import { BaseClass } from "./BaseClass";
+
+@Entity("groups")
+export class UserGroup extends BaseClass {
+ @Column({ nullable: true })
+ parent?: BigInt;
+
+ @Column()
+ color: number;
+
+ @Column()
+ hoist: boolean;
+
+ @Column()
+ mentionable: boolean;
+
+ @Column()
+ name: string;
+
+ @Column()
+ rights: BigInt;
+
+ @Column()
+ position: number;
+
+ @Column({ nullable: true })
+ icon: BigInt;
+
+ @Column({ nullable: true })
+ unicode_emoji: BigInt;
+}
diff --git a/util/src/entities/Message.ts b/util/src/entities/Message.ts
index b32bbd94..e18cf691 100644
--- a/util/src/entities/Message.ts
+++ b/util/src/entities/Message.ts
@@ -39,13 +39,15 @@ export enum MessageType {
USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2 = 10,
USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3 = 11,
CHANNEL_FOLLOW_ADD = 12,
+ ACTION = 13, // /me messages
GUILD_DISCOVERY_DISQUALIFIED = 14,
GUILD_DISCOVERY_REQUALIFIED = 15,
ENCRYPTED = 16,
REPLY = 19,
- APPLICATION_COMMAND = 20,
+ APPLICATION_COMMAND = 20, // application command or self command invocation
ROUTE_ADDED = 41, // custom message routing: new route affecting that channel
ROUTE_DISABLED = 42, // custom message routing: given route no longer affecting that channel
+ SELF_COMMAND_SCRIPT = 43, // self command scripts
ENCRYPTION = 50,
CUSTOM_START = 63,
UNHANDLED = 255
diff --git a/util/src/entities/User.ts b/util/src/entities/User.ts
index a5c4c136..49a7fbc6 100644
--- a/util/src/entities/User.ts
+++ b/util/src/entities/User.ts
@@ -163,6 +163,10 @@ export class User extends BaseClass {
@Column({ type: "simple-json", select: false })
settings: UserSettings;
+
+ // workaround to prevent fossord-unaware clients from deleting settings not used by them
+ @Column({ type: "simple-json", select: false })
+ extended_settings: string;
@Column({ type: "simple-json" })
notes: { [key: string]: string }; //key is ID of user
@@ -264,7 +268,7 @@ export class User extends BaseClass {
disabled: false,
deleted: false,
email: email,
- rights: "0", // TODO: grant rights correctly, as 0 actually stands for no rights at all
+ rights: Config.get().security.defaultRights,
nsfw_allowed: true, // TODO: depending on age
public_flags: "0",
flags: "0", // TODO: generate
@@ -273,6 +277,7 @@ export class User extends BaseClass {
valid_tokens_since: new Date(),
},
settings: { ...defaultSettings, locale: language },
+ extended_settings: {},
fingerprints: [],
notes: {},
});
diff --git a/util/src/entities/UserGroup.ts b/util/src/entities/UserGroup.ts
new file mode 100644
index 00000000..709b9d0b
--- /dev/null
+++ b/util/src/entities/UserGroup.ts
@@ -0,0 +1,37 @@
+import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+
+import { BaseClass } from "./BaseClass";
+import { Guild } from "./Guild";
+import { User } from "./User";
+
+@Entity("groups")
+export class UserGroup extends BaseClass {
+ @Column()
+ color: number;
+
+ @Column()
+ hoist: boolean;
+
+ @JoinColumn({ name: "controller", referencedColumnName: "id" })
+ @ManyToOne(() => User)
+ controller?: User;
+
+ @Column()
+ mentionable_by?: string;
+
+ @Column()
+ name: string;
+
+ @Column()
+ rights: string;
+
+ @Column({ nullable: true })
+ icon: string;
+
+ @Column({ nullable: true })
+ parent?: string;
+
+ @Column({ type: "simple-array", nullable: true})
+ associciations: string[];
+
+}
|