From 9f4f7cac6512330481ea3e2de0633fc893788c33 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Fri, 5 May 2023 11:09:05 -0400 Subject: [PATCH] initial pomelo implementation --- assets/openapi.json | Bin 573286 -> 576003 bytes assets/schemas.json | Bin 18300690 -> 18409703 bytes src/api/routes/auth/forgot.ts | 2 +- .../messages/#message_id/crosspost.ts | 1 + .../channels/#channel_id/messages/index.ts | 5 +- src/api/routes/guilds/#guild_id/bans.ts | 2 + .../guilds/#guild_id/messages/search.ts | 2 + src/api/routes/oauth2/authorize.ts | 6 +++ src/api/routes/users/#id/relationships.ts | 2 + src/api/routes/users/@me/index.ts | 2 + src/api/routes/users/@me/relationships.ts | 21 +++++--- src/connections/Discord/index.ts | 3 ++ src/util/config/types/GeneralConfiguration.ts | 1 + src/util/dtos/UserDTO.ts | 16 +++--- src/util/entities/User.ts | 47 +++++++++++++----- src/util/schemas/RelationshipPostSchema.ts | 1 + .../schemas/responses/GuildBansResponse.ts | 2 + .../responses/GuildWidgetJsonResponse.ts | 2 + .../responses/UserRelationsResponse.ts | 2 + src/util/util/email/index.ts | 3 ++ 20 files changed, 93 insertions(+), 27 deletions(-) diff --git a/assets/openapi.json b/assets/openapi.json index da2b20f10cd5cafd0f3ad42aa24f079def69421a..d1796bbdef491193990912dc8c25a4cb72426106 100644 GIT binary patch delta 1088 zcmcIjO-NKx80FsYy*F=YbhMFX(iwXw`4bXKBh;ca!VD6fD2gI#B>S;+v_c|6vJ`YV zbj^=8VMIs~`uvHjVCpV|W(=a1@p54sp=mn{>)!XK%r?1caUZ<*Otf|K3`3P1c$3h zU@~j^MxJt|Io5&)r$`ygiG+uIv<}~oK{vh*D7*0PC{ZUn6D33vc~EO7eh~NZx(D*n zIz$yrS;XIKCeciio=sJQsmt^LHf7UGT$D2c>&Pq`6re68nSseaE-I!_w zN5p2-uH#G1dob#zwL@Oo_7_j>G2xCm4t`0ow}077`LY+*YUH&tG`|uzi`O*hEg4&J ze1eugsL*l#KFn~d37%6|<_wKR#b8#y>M)cnD*5tHsM&7gpiLDGIopyhpH;rl*+SPg zjCYeG=xqcSKX)8LhC^=j39BpJYB|Q|NX3Q{swIDk4L^KA!5{aa6eFXGhMqnsWvMbn zpcbKdhwi}m7pncvfZ-^zcAt=@6r-fbsM#EvBw=&uBKsv;tx(8Mb-@bRV1gspPKtEF z;gmK=IyRfu`PEx+txBr=XK2^kC}W}mv!(-l;U#?gBQTg6AO$Ekx3Jly|KS2vxit?b z39p}kZo3`-ktXf2XGrU4zu4AM$EpTTv&c*VRz4>6c;+4WcsKzeqIWvyF^rfHLhoD9 zadiN4(TI^kK9GcTgWYsHKRKVZx?giF1GiJA;IQ39E(ZBoW(tM3L9~40)1wldjV%T3 h*LJX+2yA6mI2#QO^7<1YMJ!b;O)M8rg!D&GegY4np1uG8 delta 674 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 D@MEQ| delta 16390 zcmds;`%_a_5Xa|20^t$NMG|6!lnD4nqX^V0BcdSn0X{&hAVvoet0Gm3jEd0uBo@dJ zWdUu76a`;st7f%`fjYM13!+oSik4{Aq7{j+4kHS^A&!3nJJa88l6&Wq@9v(nd(NKw z_w~O7McsD=CwA7MvST^x3Ath7TC~)S+{Hk8m-oOO=8_;Zmjs`(2k!Ufpm~~ zP5Yt@8K_#d(^2$*dH5MLtz{2@rDUiSOwo=hpjx+JF<4%W=B{4dnxU++J%%7(DC|K-Ubrzw9^iCB?O8Mj|AKI5pati2^=v`>JmX= z?OyoxDB%tYi(_n7zcVCYK{dOb!rZ97-T!M6#a)h)WfWlOIa|ud#1QGGGJ>&Xqqn5W z%IUOkEb($EC)56Iqg=h0fQ|x2k#vj#oEqV)p@=nno#}5RG4=67Lk^P6W^?WgOC~Y( zPc9>;ktlvMVN@{1RDwfRDw7XV45yvdW4%bg`bXnPG8T4wgiIj`uF#0_nIyq=JY&L_ zBw%r6XfQ?14Obn)g&5mBX%mTTj-E;aRt8UfOcC0^fq5ud9%&|#{jxZ!u!3Up%r;F| zQ78ruEWrCcGrypqW6Ka~Ay9CW=dI1<%e5jl11$yz59o6TaGUKCwR8k(p076aeZ;8( zF{3^c4^w8B`J@}nC-44rmj%#Tu%YEH5X(mbpr$Di(v`2E^obp zFSYh|W59gHbv#P6Yl zqq`bjP)JA4?MEoU)-mXYr=IK;QqlSNi&VFV58UyU;h-|GLdazXOoT$dv#<4|E2Mkc z$*os>u)GuWe#hNh7vNLG@IbF|9tg^aDj9T-v-kUOm-7Hm9IDXeGesE#Y+v;Rjq&ci zDqi}l6VwN>to31&BhS4!nRSEoyXV{?cZQb&X74&I2mPxBp(ygxU8I|SZq3z4k>qaK zmWtUV;FOb<`zd8K$i=&rQOk}8@V%SRIZFF9D#+?K#t@!yL3NTo*F9@KqIY08Q6SStN=?0>kG=<1>+&-5F20o(sks=+d$;E$QMli z3dP`4)5b#14S6W!9v;GiTDM>pjQuVP!Ls^* z8@5I_(6n8+VAGOVG3V&Ty(C~s%Wq{Q;G<5LbN(-J1N!tv7Yq--x{Sn>9DNN1*d|+2 zZc3n_W7@SF`$)hJ?|v^L0q-8(yqg59%v{WfGa}-zK-cArU2W#U9kB@DFq#UkG)Ex*fl`T+ccTmU)Y&Su>}a+ z=_UcJ-TmE6ycha*8^uBzxpPjP6i3bX&bY@2amkVHIL5jWJ{a^`xk9TMF1B{>xE*QR zClBlEo&MJK;-HVKZteMRyseEr1>}zXN&@BWc|M@2oy%>O``EcdfH%(>M<4GdNyxRF zsJRr8WGv;{i7P1r=sb6*B##0NDT781H0oD5G7%Khr15^46SIOsxH0mw3sXfBWl!D; z88?dD0Nm?Vd}HSb5i^;@h($ diff --git a/src/api/routes/auth/forgot.ts b/src/api/routes/auth/forgot.ts index 6fa86021c..7a7911644 100644 --- a/src/api/routes/auth/forgot.ts +++ b/src/api/routes/auth/forgot.ts @@ -111,7 +111,7 @@ router.post( }) .catch((e) => { console.error( - `Failed to send password reset email to ${user.username}#${user.discriminator}: ${e}`, + `Failed to send password reset email to ${user.handle}: ${e}`, ); throw new HTTPError("Failed to send password reset email", 500); }); diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts b/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts index 5ca645c00..ed2670ca1 100644 --- a/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts +++ b/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts @@ -43,6 +43,7 @@ router.post( username: "", avatar: "", discriminator: "", + global_name: "", public_flags: 64, }, attachments: [], diff --git a/src/api/routes/channels/#channel_id/messages/index.ts b/src/api/routes/channels/#channel_id/messages/index.ts index a5bfcfd73..8b028f431 100644 --- a/src/api/routes/channels/#channel_id/messages/index.ts +++ b/src/api/routes/channels/#channel_id/messages/index.ts @@ -171,11 +171,14 @@ router.get( if ((y.user_ids || []).includes(req.user_id)) y.me = true; delete y.user_ids; }); + const { pomeloEnabled } = Config.get().general; if (!x.author) x.author = User.create({ id: "4", - discriminator: "0000", + discriminator: pomeloEnabled ? "0" : "0000", username: "Spacebar Ghost", + global_name: "spacebarghost", + display_name: "Spacebar Ghost", public_flags: 0, }); x.attachments?.forEach((y: Attachment) => { diff --git a/src/api/routes/guilds/#guild_id/bans.ts b/src/api/routes/guilds/#guild_id/bans.ts index 9aeb27f0e..ede9f4bde 100644 --- a/src/api/routes/guilds/#guild_id/bans.ts +++ b/src/api/routes/guilds/#guild_id/bans.ts @@ -70,6 +70,8 @@ router.get( user: { username: user.username, discriminator: user.discriminator, + global_name: user.global_name, + display_name: user.display_name, id: user.id, avatar: user.avatar, public_flags: user.public_flags, diff --git a/src/api/routes/guilds/#guild_id/messages/search.ts b/src/api/routes/guilds/#guild_id/messages/search.ts index 637d1e438..bf5fc4cd4 100644 --- a/src/api/routes/guilds/#guild_id/messages/search.ts +++ b/src/api/routes/guilds/#guild_id/messages/search.ts @@ -149,6 +149,8 @@ router.get( avatar: x.author?.avatar, avatar_decoration: null, discriminator: x.author?.discriminator, + global_name: x.author?.global_name, + display_name: x.author?.display_name, public_flags: x.author?.public_flags, }, attachments: x.attachments, diff --git a/src/api/routes/oauth2/authorize.ts b/src/api/routes/oauth2/authorize.ts index 2f2351f38..11255b98f 100644 --- a/src/api/routes/oauth2/authorize.ts +++ b/src/api/routes/oauth2/authorize.ts @@ -89,6 +89,8 @@ router.get( "username", "avatar", "discriminator", + "global_name", + "display_name", "public_flags", ], }); @@ -137,6 +139,8 @@ router.get( avatar: user.avatar, avatar_decoration: null, // TODO discriminator: user.discriminator, + global_name: user.global_name, + display_name: user.display_name, public_flags: user.public_flags, }, application: { @@ -159,6 +163,8 @@ router.get( avatar: bot.avatar, avatar_decoration: null, // TODO discriminator: bot.discriminator, + global_name: bot.global_name, + display_name: bot.display_name, public_flags: bot.public_flags, bot: true, approximated_guild_count: 0, // TODO diff --git a/src/api/routes/users/#id/relationships.ts b/src/api/routes/users/#id/relationships.ts index 3737ca004..0008e75d0 100644 --- a/src/api/routes/users/#id/relationships.ts +++ b/src/api/routes/users/#id/relationships.ts @@ -58,6 +58,8 @@ router.get( username: relation_user.username, avatar: relation_user.avatar, discriminator: relation_user.discriminator, + global_name: relation_user.global_name, + display_name: relation_user.display_name, public_flags: relation_user.public_flags, }); } diff --git a/src/api/routes/users/@me/index.ts b/src/api/routes/users/@me/index.ts index ad11a4281..1d2095427 100644 --- a/src/api/routes/users/@me/index.ts +++ b/src/api/routes/users/@me/index.ts @@ -140,6 +140,7 @@ router.patch( newToken = (await generateToken(user.id)) as string; } + // TODO: pomelo: disallow if pomelo is enabled if (body.username) { const check_username = body?.username?.replace(/\s/g, ""); if (!check_username) { @@ -162,6 +163,7 @@ router.patch( } } + // TODO: pomelo: disallow if pomelo is enabled if (body.discriminator) { if ( await User.findOne({ diff --git a/src/api/routes/users/@me/relationships.ts b/src/api/routes/users/@me/relationships.ts index bce0a6549..083426020 100644 --- a/src/api/routes/users/@me/relationships.ts +++ b/src/api/routes/users/@me/relationships.ts @@ -114,19 +114,26 @@ router.post( }, }), async (req: Request, res: Response) => { + const { pomeloEnabled } = Config.get().general; + const where = pomeloEnabled + ? { + // TODO: pomelo: should we use username or add global_name property to the request? + global_name: req.body.username, + } + : { + discriminator: String(req.body.discriminator).padStart( + 4, + "0", + ), //Discord send the discriminator as integer, we need to add leading zeroes + username: req.body.username, + }; return await updateRelationship( req, res, await User.findOneOrFail({ relations: ["relationships", "relationships.to"], select: userProjection, - where: { - discriminator: String(req.body.discriminator).padStart( - 4, - "0", - ), //Discord send the discriminator as integer, we need to add leading zeroes - username: req.body.username, - }, + where, }), req.body.type, ); diff --git a/src/connections/Discord/index.ts b/src/connections/Discord/index.ts index 731086f1a..206aa6719 100644 --- a/src/connections/Discord/index.ts +++ b/src/connections/Discord/index.ts @@ -31,6 +31,8 @@ interface UserResponse { id: string; username: string; discriminator: string; + global_name: string; + display_name?: string; avatar_url: string | null; } @@ -128,6 +130,7 @@ export default class DiscordConnection extends Connection { if (exists) return null; + // TODO: pomelo return await this.createConnection({ user_id: userId, external_id: userInfo.id, diff --git a/src/util/config/types/GeneralConfiguration.ts b/src/util/config/types/GeneralConfiguration.ts index cff8c527b..df3dfbcdc 100644 --- a/src/util/config/types/GeneralConfiguration.ts +++ b/src/util/config/types/GeneralConfiguration.ts @@ -29,4 +29,5 @@ export class GeneralConfiguration { image: string | null = null; instanceId: string = Snowflake.generate(); autoCreateBotUsers: boolean = false; + pomeloEnabled: boolean = false; } diff --git a/src/util/dtos/UserDTO.ts b/src/util/dtos/UserDTO.ts index a24c8d960..5687bcefb 100644 --- a/src/util/dtos/UserDTO.ts +++ b/src/util/dtos/UserDTO.ts @@ -19,17 +19,21 @@ import { User } from "../entities"; export class MinimalPublicUserDTO { - avatar?: string | null; - discriminator: string; id: string; - public_flags: number; username: string; + global_name: string; + display_name?: string; + discriminator: string; + public_flags: number; + avatar?: string | null; constructor(user: User) { - this.avatar = user.avatar; - this.discriminator = user.discriminator; this.id = user.id; - this.public_flags = user.public_flags; this.username = user.username; + this.global_name = user.global_name; + this.display_name = user.display_name; + this.discriminator = user.discriminator; + this.public_flags = user.public_flags; + this.avatar = user.avatar; } } diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts index c6582b00a..0620640bf 100644 --- a/src/util/entities/User.ts +++ b/src/util/entities/User.ts @@ -37,6 +37,8 @@ import { UserSettings } from "./UserSettings"; export enum PublicUserEnum { username, + global_name, + display_name, discriminator, id, public_flags, @@ -90,8 +92,14 @@ export class User extends BaseClass { @Column() username: string; // username max length 32, min 2 (should be configurable) + @Column({nullable: true}) + global_name: string; // puyo: pomelo + + @Column({nullable: true}) + display_name?: string; // puyo: pomelo + @Column() - discriminator: string; // opaque string: 4 digits on discord.com + discriminator: string; // opaque string: 4 digits on discord.com, 0 for pomelo @Column({ nullable: true }) avatar?: string; // hash of the user avatar @@ -323,6 +331,13 @@ export class User extends BaseClass { } } + public get handle(): string { + const {pomeloEnabled} = Config.get().general; + + // if pomelo is enabled, global_name should be set + return pomeloEnabled ? this.global_name as string : `${this.username}#${this.discriminator}`; + } + static async register({ email, username, @@ -337,19 +352,25 @@ export class User extends BaseClass { id?: string; req?: Request; }) { + const {pomeloEnabled} = Config.get().general; + // trim special uf8 control characters -> Backspace, Newline, ... username = trimSpecial(username); - const discriminator = await User.generateDiscriminator(username); - if (!discriminator) { - // We've failed to generate a valid and unused discriminator - throw FieldErrors({ - username: { - code: "USERNAME_TOO_MANY_USERS", - message: - req?.t("auth:register.USERNAME_TOO_MANY_USERS") || "", - }, - }); + let discriminator: string | undefined; + if(pomeloEnabled) discriminator = "0"; + else { + discriminator = await User.generateDiscriminator(username); + if (!discriminator) { + // We've failed to generate a valid and unused discriminator + throw FieldErrors({ + username: { + code: "USERNAME_TOO_MANY_USERS", + message: + req?.t("auth:register.USERNAME_TOO_MANY_USERS") || "", + }, + }); + } } // TODO: save date_of_birth @@ -364,6 +385,8 @@ export class User extends BaseClass { const user = User.create({ username: username, + global_name: username, // TODO: convert to lowercase, strip special characters,etc??? + // display_name: username, // TODO: how should we do this? discriminator, id: id || Snowflake.generate(), email: email, @@ -391,7 +414,7 @@ export class User extends BaseClass { if (!Config.get().defaults.user.verified && email) { await Email.sendVerifyEmail(user, email).catch((e) => { console.error( - `Failed to send verification email to ${user.username}#${user.discriminator}: ${e}`, + `Failed to send verification email to ${user.handle}: ${e}`, ); }); } diff --git a/src/util/schemas/RelationshipPostSchema.ts b/src/util/schemas/RelationshipPostSchema.ts index 066ecfd8e..f0a5fc32a 100644 --- a/src/util/schemas/RelationshipPostSchema.ts +++ b/src/util/schemas/RelationshipPostSchema.ts @@ -16,6 +16,7 @@ along with this program. If not, see . */ +// TODO: pomelo? export interface RelationshipPostSchema { discriminator: string; username: string; diff --git a/src/util/schemas/responses/GuildBansResponse.ts b/src/util/schemas/responses/GuildBansResponse.ts index 77c95a48d..aa53105d2 100644 --- a/src/util/schemas/responses/GuildBansResponse.ts +++ b/src/util/schemas/responses/GuildBansResponse.ts @@ -21,6 +21,8 @@ export interface GuildBansResponse { user: { username: string; discriminator: string; + global_name: string; + display_name: string | null; id: string; avatar: string | null; public_flags: number; diff --git a/src/util/schemas/responses/GuildWidgetJsonResponse.ts b/src/util/schemas/responses/GuildWidgetJsonResponse.ts index bd6923041..60e8e7cc7 100644 --- a/src/util/schemas/responses/GuildWidgetJsonResponse.ts +++ b/src/util/schemas/responses/GuildWidgetJsonResponse.ts @@ -30,6 +30,8 @@ export interface GuildWidgetJsonResponse { members: { id: string; username: string; + global_name: string; + display_name: string | null; discriminator: string; avatar: string | null; status: ClientStatus; diff --git a/src/util/schemas/responses/UserRelationsResponse.ts b/src/util/schemas/responses/UserRelationsResponse.ts index 808dd3d33..59db277f6 100644 --- a/src/util/schemas/responses/UserRelationsResponse.ts +++ b/src/util/schemas/responses/UserRelationsResponse.ts @@ -19,6 +19,8 @@ import { User } from "@spacebar/util"; export type UserRelationsResponse = (Pick & Pick & + Pick & + Pick & Pick & Pick & Pick)[]; diff --git a/src/util/util/email/index.ts b/src/util/util/email/index.ts index 619cc5c3f..6d34e2349 100644 --- a/src/util/util/email/index.ts +++ b/src/util/util/email/index.ts @@ -112,9 +112,12 @@ export const Email: { ) { const { instanceName } = Config.get().general; + // TODO: pomelo: display_name should take precedence over username if pomelo is enabled. maybe we should use global_name as the username? const replacements = [ ["{instanceName}", instanceName], ["{userUsername}", user.username], + ["{userGlobalName}", user.global_name], + ["{userDisplayName}", user.display_name], ["{userDiscriminator}", user.discriminator], ["{userId}", user.id], ["{phoneNumber}", user.phone?.slice(-4)],