Move sessions to db table instead of JWTs

This commit is contained in:
Andrew Glaze
2025-05-23 11:52:06 -04:00
parent 62260ffc73
commit 49cd62da1d
11 changed files with 114 additions and 101 deletions

View File

@@ -1,4 +1,5 @@
import Vapor
import Fluent
import SwiftMsgpack
import JWT
@@ -13,11 +14,24 @@ struct ToolController: RouteCollection {
func signup(req: Request) async throws -> Response {
let body = try req.content.decode(SignupReq.self, using: MsgPackDecoder())
let session = try await req.jwt.verify(body.access_token, as: SessionPayload.self)
guard session.type == SessionType.ZAT.rawValue else {
guard
let session = try await Session.query(on: req.db).filter(\.$id == body.access_token).first(),
session.type == SessionType.ZAT
else {
throw Abort(.forbidden, reason: "Invalid access token")
}
let accountId = session.$account.id
if let player = try await Player.query(on: req.db).filter(\.$account.$id == accountId).first() {
} else {
guard let account = try await Account.query(on: req.db).filter(\.$id == accountId).first() else {
throw Abort(.forbidden, reason: "Account ID does not exist")
}
// Create new Player
let player = try Player.createDefault(account: account)
try await player.save(on: req.db)
}
throw Abort(.notImplemented)
}

View File

@@ -61,12 +61,24 @@ struct AuthController: RouteCollection {
let idpId = body.whiteKey
var account: Account? = nil
if let rawAccountId = req.headers["playerId"].first, let accountId = Int(rawAccountId) {
if let existingAccount = try await Account.query(on: req.db).filter(\.$id == accountId).first() {
account = existingAccount
}
if
let rawAccountId = req.headers["playerId"].first,
let accountId = Int(rawAccountId),
let existingAccount = try await Account.query(on: req.db).filter(\.$id == accountId).first()
{
account = existingAccount
// Delete old sessions
try await Session.query(on: req.db)
.filter(\.$account.$id == existingAccount.requireID())
.filter(\.$type ~~ [.ZAT, .ZRT])
.delete()
} else if let existingAccount = try await Account.query(on: req.db).filter(\.$idpId == idpId).first() {
account = existingAccount
// Delete old sessions
try await Session.query(on: req.db)
.filter(\.$account.$id == existingAccount.requireID())
.filter(\.$type ~~ [.ZAT, .ZRT])
.delete()
} else {
account = Account(appId: body.appId, idpAlias: idpAlias, idpCode: "zd3", idpId: idpId, status: "normal")
try await account!.create(on: req.db)
@@ -75,6 +87,7 @@ struct AuthController: RouteCollection {
guard let account = account else {
throw Abort(.badRequest)
}
print("got here")
if account.idpAlias != idpAlias {
account.idpAlias = idpAlias
@@ -84,11 +97,13 @@ struct AuthController: RouteCollection {
let zatExpiry = Date.now.advanced(by: 43200)
let zrtExpiry = Date.now.advanced(by: 2592000)
let zatTokenJWT = generateToken(accountId: try account.requireID(), expires: zatExpiry, type: .ZAT)
let zrtTokenJWT = generateToken(accountId: try account.requireID(), expires: zrtExpiry, type: .ZRT)
let zatSession = try Session(account: account, expires: zatExpiry, type: .ZAT)
let zrtSession = try Session(account: account, expires: zrtExpiry, type: .ZRT)
try await zatSession.create(on: req.db)
try await zrtSession.create(on: req.db)
let zatToken = try await req.jwt.sign(zatTokenJWT)
let zrtToken = try await req.jwt.sign(zrtTokenJWT)
let zatToken = try zatSession.requireID()
let zrtToken = try zrtSession.requireID()
let res = LoginDeviceRes(
zatExpiryTime: Int(zatExpiry.timeIntervalSince1970) * 1000,
@@ -119,18 +134,20 @@ struct AuthController: RouteCollection {
@Sendable
func zatLogin(req: Request) async throws -> LoginDeviceRes {
let body = try req.content.decode(ZatLoginReq.self, as: .json)
if let session = try? await req.jwt.verify(body.zat, as: SessionPayload.self) {
guard session.type == SessionType.ZAT.rawValue && session.accountId.value == body.playerId else {
if let session = try await Session.query(on: req.db).filter(\.$id == body.zat).first() {
guard let accountId = Int(body.playerId), session.type == SessionType.ZAT && session.$account.id == accountId else {
throw Abort(.badRequest, reason: "Invalid zat provided.")
}
try await session.delete(on: req.db)
}
guard
let accountId = Int(body.playerId),
let account = try await Account.query(on: req.db)
.filter(\.$id == accountId)
.first()
else {
throw Abort(.badRequest, reason: "Invalid playerId")
throw Abort(.unauthorized, reason: "Invalid playerId")
}
account.lastLogin = Date.now
@@ -138,8 +155,9 @@ struct AuthController: RouteCollection {
let zatExpiry = Date.now.advanced(by: 43200)
let session = generateToken(accountId: try account.requireID(), expires: zatExpiry, type: SessionType.ZAT)
let zatToken = try await req.jwt.sign(session)
let session = try Session(account: account, expires: zatExpiry, type: SessionType.ZAT)
try await session.create(on: req.db)
let zatToken = try session.requireID()
return LoginDeviceRes(
zatExpiryTime: Int(zatExpiry.timeIntervalSince1970) * 1000,
zrtExpiryTime: nil,
@@ -303,8 +321,3 @@ struct PushOptionResponse: Content {
let player: String
}
enum SessionType: Int {
case ZAT = 0
case ZRT = 1
case VIEWER = 2
}

View File

@@ -1,5 +1,5 @@
import Vapor
import JWT
import Fluent
struct OpenApiController: RouteCollection {
func boot(routes: any RoutesBuilder) throws {
@@ -17,10 +17,13 @@ struct OpenApiController: RouteCollection {
guard let zatToken = req.headers["zat"].first else {
throw Abort(.badRequest, reason: "Missing zat header.")
}
let jwt = try await req.jwt.verify(zatToken, as: SessionPayload.self)
guard jwt.accountId.value == beat.playerId else {
guard let session = try await Session.query(on: req.db).filter(\.$id == zatToken).first(),
let playerId = Int(beat.playerId),
session.$account.id == playerId else {
throw Abort(.unauthorized, reason: "zat invalid")
}
return "{}"
}
@@ -29,8 +32,9 @@ struct OpenApiController: RouteCollection {
guard let zatToken = req.headers["zat"].first else {
throw Abort(.badRequest, reason: "Missing zat header.")
}
let jwt = try await req.jwt.verify(zatToken, as: SessionPayload.self)
guard jwt.accountId.value == beat.playerId else {
guard let session = try await Session.query(on: req.db).filter(\.$id == zatToken).first(),
let playerId = Int(beat.playerId),
session.$account.id == playerId else {
throw Abort(.unauthorized, reason: "zat invalid")
}
return "{}"