From 3eb4453d716543d1cc907ab8c7192867d3c71049 Mon Sep 17 00:00:00 2001 From: Xeovalyte Date: Mon, 5 Jun 2023 22:41:48 +0200 Subject: [PATCH] feat: Added minecraft linking system, closes #29 --- webv2/server/api/auth.ts | 7 +-- webv2/server/api/users/[id]/index.get.ts | 18 +------- webv2/server/api/users/[id]/minecraft.get.ts | 23 ++++++++++ webv2/server/api/users/[id]/minecraft.put.ts | 45 ++++++++++++++++++++ webv2/server/utils/user.ts | 21 +++++---- 5 files changed, 86 insertions(+), 28 deletions(-) create mode 100644 webv2/server/api/users/[id]/minecraft.get.ts create mode 100644 webv2/server/api/users/[id]/minecraft.put.ts diff --git a/webv2/server/api/auth.ts b/webv2/server/api/auth.ts index fb40673..bad4e7b 100644 --- a/webv2/server/api/auth.ts +++ b/webv2/server/api/auth.ts @@ -63,7 +63,7 @@ export default defineEventHandler(async (event) => { } try { - await UserModel.updateOne({ 'discord.id': authorizationResponse.id }, { + const user = await UserModel.findOneAndUpdate({ 'discord.id': authorizationResponse.id }, { $set: { discord: { id: authorizationResponse.id, @@ -74,12 +74,13 @@ export default defineEventHandler(async (event) => { $setOnInsert: { username: authorizationResponse.username } - }, { upsert: true }) + }, { upsert: true, returnDocument: 'after' }) const token = jwt.sign({ accessToken: tokenResponse.access_token, refreshToken: tokenResponse.refresh_token, - discordId: authorizationResponse.id + discordId: authorizationResponse.id, + userId: user._id }, config.jwtSecret, { expiresIn: tokenResponse.expires_in }) setCookie(event, 'jwt', token, { httpOnly: true, maxAge: tokenResponse.expires_in * 1000 }) diff --git a/webv2/server/api/users/[id]/index.get.ts b/webv2/server/api/users/[id]/index.get.ts index 2fa94a2..2d5a1cd 100644 --- a/webv2/server/api/users/[id]/index.get.ts +++ b/webv2/server/api/users/[id]/index.get.ts @@ -1,21 +1,5 @@ export default defineEventHandler(async (event) => { const userId: string = event.context.params ? event.context.params.id : '@me' - if (userId === '@me') { - return await getCurrentUser(event) - } - - try { - const user = await UserModel.findById(userId) - - if (!user) { - throw createError({ statusCode: 400, statusMessage: 'No user was found' }) - } - - return user - } catch (e) { - console.error('Failed to get user by id', e) - - throw createError({ statusCode: 500, statusMessage: 'Failed to get user' }) - } + return await getUser(userId, event) }) diff --git a/webv2/server/api/users/[id]/minecraft.get.ts b/webv2/server/api/users/[id]/minecraft.get.ts new file mode 100644 index 0000000..98f4528 --- /dev/null +++ b/webv2/server/api/users/[id]/minecraft.get.ts @@ -0,0 +1,23 @@ +export default defineEventHandler(async (event) => { + const userId: string = event.context.params ? event.context.params.id : '@me' + + const user = await getUser(userId, event) + + if (!user.minecraft) { + throw createError({ statusCode: 400, statusMessage: 'Minecraft has not been linked' }) + } + + const minecraftProfile: any = await $fetch(`https://sessionserver.mojang.com/session/minecraft/profile/${user.minecraft.uuid}`) + + try { + user.minecraft = { uuid: user.minecraft.uuid, username: minecraftProfile.name } + + user.save() + } catch (e) { + console.error('Failed to update document', e) + + throw createError('Failed to update document') + } + + return user.minecraft +}) diff --git a/webv2/server/api/users/[id]/minecraft.put.ts b/webv2/server/api/users/[id]/minecraft.put.ts new file mode 100644 index 0000000..0c72968 --- /dev/null +++ b/webv2/server/api/users/[id]/minecraft.put.ts @@ -0,0 +1,45 @@ +import mongoose from 'mongoose' + +export default defineEventHandler(async (event) => { + const { code } = await readBody(event) + const userId: string = event.context.params ? event.context.params.id : '@me' + + let whitelistDoc + try { + whitelistDoc = await WhitelistModel.findOne({ code }) + + if (!whitelistDoc) { + throw createError({ statusCode: 500, statusMessage: 'Whitelist document was not found' }) + } + } catch (e) { + console.error('Failed to get whitelist document', e) + + throw createError('Failed to get whitelist document') + } + + const minecraftProfile: any = await $fetch(`https://sessionserver.mojang.com/session/minecraft/profile/${whitelistDoc.uuid}`) + const user = await getUser(userId, event) + + const session = await mongoose.startSession() + session.startTransaction() + + try { + whitelistDoc.connected = true + user.minecraft = { uuid: whitelistDoc.uuid, username: minecraftProfile.name } + + whitelistDoc.save({ session }) + user.save({ session }) + + await session.commitTransaction() + } catch (e) { + console.error('Failed to update documents', e) + + await session.abortTransaction() + + throw createError('Failed to update documents') + } finally { + session.endSession() + } + + return user.minecraft +}) diff --git a/webv2/server/utils/user.ts b/webv2/server/utils/user.ts index 8d1ce46..4937eb2 100644 --- a/webv2/server/utils/user.ts +++ b/webv2/server/utils/user.ts @@ -2,20 +2,20 @@ import * as jwt from 'jsonwebtoken' interface IDecodedToken { discordId: string, + userId: string, accessToken: string, refreshToken: string } -export const getCurrentUser = async (event: any) => { +export const getAuth = (event: any) => { const token = getCookie(event, 'jwt') || null if (!token) { throw createError({ statusCode: 401, statusMessage: 'JWT token is invalid' }) } - let decodedToken try { - decodedToken = jwt.verify(token, config.jwtSecret) as IDecodedToken + return jwt.verify(token, config.jwtSecret) as IDecodedToken } catch (e) { console.error('Failed to verify JWT token', e) @@ -24,19 +24,24 @@ export const getCurrentUser = async (event: any) => { statusMessage: 'JWT token is invalid' }) } +} + +export const getUser = async (userId: string, event: any) => { + if (userId === '@me') { + const auth = getAuth(event) + userId = auth.userId + } try { - const user = await UserModel.findOne({ 'discord.id': decodedToken.discordId }) + const user = await UserModel.findById(userId) if (!user) { - throw createError({ statusCode: 500, statusMessage: 'User query returned null' }) + throw createError({ statusCode: 400, statusMessage: 'No user was found' }) } - user.accessToken = decodedToken.accessToken - return user } catch (e) { - console.error('Failed to get user', e) + console.error('Failed to get user by id', e) throw createError({ statusCode: 500, statusMessage: 'Failed to get user' }) }