summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--assets/locales/en/auth.json3
-rw-r--r--assets/schemas.json3
-rw-r--r--src/api/routes/auth/register.ts16
-rw-r--r--src/api/routes/users/#id/profile.ts86
-rw-r--r--src/api/routes/users/@me/index.ts9
-rw-r--r--src/util/config/types/RegisterConfiguration.ts1
-rw-r--r--src/util/entities/Channel.ts12
-rw-r--r--src/util/schemas/UserModifySchema.ts1
-rw-r--r--src/util/util/InvisibleCharacters.ts9
9 files changed, 102 insertions, 38 deletions
diff --git a/assets/locales/en/auth.json b/assets/locales/en/auth.json

index a78d4d60..b6264a43 100644 --- a/assets/locales/en/auth.json +++ b/assets/locales/en/auth.json
@@ -13,6 +13,7 @@ "EMAIL_ALREADY_REGISTERED": "Email is already registered", "DATE_OF_BIRTH_UNDERAGE": "You need to be {{years}} years or older", "CONSENT_REQUIRED": "You must agree to the Terms of Service and Privacy Policy.", - "USERNAME_TOO_MANY_USERS": "Too many users have this username, please try another" + "USERNAME_TOO_MANY_USERS": "Too many users have this username, please try another", + "GUESTS_DISABLED": "Guest users are disabled" } } diff --git a/assets/schemas.json b/assets/schemas.json
index e3200800..05650a4e 100644 --- a/assets/schemas.json +++ b/assets/schemas.json
@@ -1105,6 +1105,9 @@ }, "code": { "type": "string" + }, + "email": { + "type": "string" } }, "additionalProperties": false, diff --git a/src/api/routes/auth/register.ts b/src/api/routes/auth/register.ts
index d3b5a59c..5cc28f7a 100644 --- a/src/api/routes/auth/register.ts +++ b/src/api/routes/auth/register.ts
@@ -1,6 +1,6 @@ +import { getIpAdress, IPAnalysis, isProxy, route, verifyCaptcha } from "@fosscord/api"; +import { adjustEmail, Config, FieldErrors, generateToken, HTTPError, Invite, RegisterSchema, User } from "@fosscord/util"; import { Request, Response, Router } from "express"; -import { Config, generateToken, Invite, FieldErrors, User, adjustEmail, RegisterSchema } from "@fosscord/util"; -import { route, getIpAdress, IPAnalysis, isProxy, verifyCaptcha } from "@fosscord/api"; let bcrypt: any; try { @@ -9,7 +9,6 @@ try { bcrypt = require("bcryptjs"); console.log("Warning: using bcryptjs because bcrypt is not installed! Performance will be affected."); } -import { HTTPError } from "@fosscord/util"; const router: Router = Router(); @@ -44,6 +43,12 @@ router.post("/", route({ body: "RegisterSchema" }), async (req: Request, res: Re }); } + if (!register.allowGuests) { + throw FieldErrors({ + email: { code: "GUESTS_DISABLED", message: req.t("auth:register.GUESTS_DISABLED") } + }); + } + if (register.requireCaptcha && security.captcha.enabled) { const { sitekey, service } = security.captcha; if (!body.captcha_key) { @@ -60,7 +65,7 @@ router.post("/", route({ body: "RegisterSchema" }), async (req: Request, res: Re captcha_key: verify["error-codes"], captcha_sitekey: sitekey, captcha_service: service - }) + }); } } @@ -111,7 +116,8 @@ router.post("/", route({ body: "RegisterSchema" }), async (req: Request, res: Re }); } - if (register.dateOfBirth.required && !body.date_of_birth) { + // If no password is provided, this is a guest account + if (register.dateOfBirth.required && !body.date_of_birth && body.password) { throw FieldErrors({ date_of_birth: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED") } }); diff --git a/src/api/routes/users/#id/profile.ts b/src/api/routes/users/#id/profile.ts
index 27717c79..fa1d52c3 100644 --- a/src/api/routes/users/#id/profile.ts +++ b/src/api/routes/users/#id/profile.ts
@@ -13,45 +13,81 @@ export interface UserProfileResponse { router.get("/", route({ test: { response: { body: "UserProfileResponse" } } }), async (req: Request, res: Response) => { if (req.params.id === "@me") req.params.id = req.user_id; + + const { guild_id, with_mutual_guilds } = req.query; + const user = await User.getPublicUser(req.params.id, { relations: ["connected_accounts"] }); - let mutual_guilds: object[] = []; - let premium_guild_since; - const requested_member = await Member.find({ where: { id: req.params.id } }); - const self_member = await Member.find({ where: { id: req.user_id } }); + var mutual_guilds: object[] = []; + var premium_guild_since; + + if (with_mutual_guilds == "true") { + const requested_member = await Member.find({ where: { id: req.params.id } }); + const self_member = await Member.find({ where: { id: req.user_id } }); - for (const rmem of requested_member) { - if (rmem.premium_since) { - if (premium_guild_since) { - if (premium_guild_since > rmem.premium_since) { + for (const rmem of requested_member) { + if (rmem.premium_since) { + if (premium_guild_since) { + if (premium_guild_since > rmem.premium_since) { + premium_guild_since = rmem.premium_since; + } + } else { premium_guild_since = rmem.premium_since; } - } else { - premium_guild_since = rmem.premium_since; } - } - for (const smem of self_member) { - if (smem.guild_id === rmem.guild_id) { - mutual_guilds.push({ id: rmem.guild_id, nick: rmem.nick }); + for (const smem of self_member) { + if (smem.guild_id === rmem.guild_id) { + mutual_guilds.push({ id: rmem.guild_id, nick: rmem.nick }); + } } } } + + const guild_member = + guild_id && typeof guild_id == "string" + ? await Member.findOneOrFail({ id: req.params.id, guild_id: guild_id }, { relations: ["roles"] }) + : undefined; + + // TODO: make proper DTO's in util? + + const userDto = { + username: user.username, + discriminator: user.discriminator, + id: user.id, + public_flags: user.public_flags, + avatar: user.avatar, + accent_color: user.accent_color, + banner: user.banner, + bio: req.user_bot ? null : user.bio, + bot: user.bot + }; + + const guildMemberDto = guild_member + ? { + avatar: user.avatar, // TODO + banner: user.banner, // TODO + bio: req.user_bot ? null : user.bio, // TODO + communication_disabled_until: null, // TODO + deaf: guild_member.deaf, + flags: user.flags, + is_pending: guild_member.pending, + pending: guild_member.pending, // why is this here twice, discord? + joined_at: guild_member.joined_at, + mute: guild_member.mute, + nick: guild_member.nick, + premium_since: guild_member.premium_since, + roles: guild_member.roles.map((x) => x.id).filter((id) => id != guild_id), + user: userDto + } + : undefined; + res.json({ connected_accounts: user.connected_accounts, premium_guild_since: premium_guild_since, // TODO premium_since: user.premium_since, // TODO mutual_guilds: mutual_guilds, // TODO {id: "", nick: null} when ?with_mutual_guilds=true - user: { - username: user.username, - discriminator: user.discriminator, - id: user.id, - public_flags: user.public_flags, - avatar: user.avatar, - accent_color: user.accent_color, - banner: user.banner, - bio: req.user_bot ? null : user.bio, - bot: user.bot - } + user: userDto, + guild_member: guildMemberDto }); }); diff --git a/src/api/routes/users/@me/index.ts b/src/api/routes/users/@me/index.ts
index fcb0a9df..563300dc 100644 --- a/src/api/routes/users/@me/index.ts +++ b/src/api/routes/users/@me/index.ts
@@ -1,5 +1,7 @@ import { route } from "@fosscord/api"; import { + adjustEmail, + Config, emitEvent, FieldErrors, generateToken, @@ -45,6 +47,13 @@ router.patch("/", route({ body: "UserModifySchema" }), async (req: Request, res: } } + if (body.email) { + body.email = adjustEmail(body.email); + if (!body.email && Config.get().register.email.required) + throw FieldErrors({ email: { message: req.t("auth:register.EMAIL_INVALID"), code: "EMAIL_INVALID" } }); + if (!body.password) throw FieldErrors({ password: { message: req.t("auth:register.INVALID_PASSWORD"), code: "INVALID_PASSWORD" } }); + } + if (body.new_password) { if (!body.password && !user.email) { throw FieldErrors({ diff --git a/src/util/config/types/RegisterConfiguration.ts b/src/util/config/types/RegisterConfiguration.ts
index 939605a6..68946272 100644 --- a/src/util/config/types/RegisterConfiguration.ts +++ b/src/util/config/types/RegisterConfiguration.ts
@@ -9,6 +9,7 @@ export class RegisterConfiguration { disabled: boolean = false; requireCaptcha: boolean = true; requireInvite: boolean = false; + allowGuests: boolean = true; guestsRequireInvite: boolean = true; allowNewRegistration: boolean = true; allowMultipleAccounts: boolean = true; diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts
index 23fc6544..b17fdba0 100644 --- a/src/util/entities/Channel.ts +++ b/src/util/entities/Channel.ts
@@ -181,10 +181,16 @@ export class Channel extends BaseClass { for (let 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); + // Categories and voice skip these checks on discord.com + const skipChecksTypes = [ChannelType.GUILD_CATEGORY, ChannelType.GUILD_VOICE]; + if ((channel.type && !skipChecksTypes.includes(channel.type)) || guild.features.includes("IRC_LIKE_CHANNEL_NAMES")) { + if (channel.name.includes(" ")) throw new HTTPError("Channel name cannot include invalid characters", 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.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); + } else channel.name = channel.name.trim(); //category names are trimmed client side on discord.com } if (!guild.features.includes("ALLOW_UNNAMED_CHANNELS")) { diff --git a/src/util/schemas/UserModifySchema.ts b/src/util/schemas/UserModifySchema.ts
index d69f83f4..622497d9 100644 --- a/src/util/schemas/UserModifySchema.ts +++ b/src/util/schemas/UserModifySchema.ts
@@ -15,4 +15,5 @@ export interface UserModifySchema { password?: string; new_password?: string; code?: string; + email?: string; } diff --git a/src/util/util/InvisibleCharacters.ts b/src/util/util/InvisibleCharacters.ts
index 4c809e48..9bffec58 100644 --- a/src/util/util/InvisibleCharacters.ts +++ b/src/util/util/InvisibleCharacters.ts
@@ -1,9 +1,10 @@ // List from https://invisible-characters.com/ export const InvisibleCharacters = [ "\u{9}", //Tab - "\u{20}", //Space + "\u{c}", //Form feed + //'\u{20}', //Space //categories can have spaces in them "\u{ad}", //Soft hyphen - "\u{34f}", //Combining grapheme joiner + // '\u{34f}', //Combining grapheme joiner "\u{61c}", //Arabic letter mark "\u{115f}", //Hangul choseong filler "\u{1160}", //Hangul jungseong filler @@ -23,12 +24,12 @@ export const InvisibleCharacters = [ "\u{200a}", //Hair space "\u{200b}", //Zero width space "\u{200c}", //Zero width non-joiner - "\u{200d}", //Zero width 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{2060}', //Word joiner -- WJ is required in some languages that don't use spaces to split words "\u{2061}", //Function application "\u{2062}", //Invisible times "\u{2063}", //Invisible separator