impl session tokens
This commit is contained in:
@@ -53,7 +53,7 @@ struct AuthController: RouteCollection {
|
||||
}
|
||||
|
||||
@Sendable
|
||||
func loginDevice(req: Request) async throws -> Response {
|
||||
func loginDevice(req: Request) async throws -> LoginDeviceRes {
|
||||
let body = try req.content.decode(LoginDeviceReq.self, as: .json)
|
||||
|
||||
let idpAlias = generateIdpAlias(appId: body.appId, deviceId: body.deviceId, serialNo: body.serialNo)
|
||||
@@ -72,9 +72,38 @@ struct AuthController: RouteCollection {
|
||||
}
|
||||
|
||||
guard let account = account else {
|
||||
return Response(status: .badRequest, body: "{\"error\": \"Bad Request\", \"message\": \"Invalid playerId provided.\"}")
|
||||
throw Abort(.badRequest)
|
||||
}
|
||||
return Response(status: .notImplemented)
|
||||
|
||||
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 zatToken = try await req.jwt.sign(zatTokenJWT)
|
||||
let zrtToken = try await req.jwt.sign(zrtTokenJWT)
|
||||
|
||||
let res = LoginDeviceRes(
|
||||
zatExpiryTime: Int(zatExpiry.timeIntervalSince1970) * 1000,
|
||||
zrtExpiryTime: Int(zrtExpiry.timeIntervalSince1970) * 1000,
|
||||
firstLogin: true,
|
||||
externalToken: "",
|
||||
zat: zatToken,
|
||||
zrt: zrtToken,
|
||||
player: Player(
|
||||
idpId: account.idpId,
|
||||
appId: account.appId,
|
||||
playerId: String(try account.requireID()),
|
||||
pushOption: PushOptionResponse(night: "n", player: "n"),
|
||||
regTime: Int(account.regDate.timeIntervalSince1970),
|
||||
idpAlias: idpAlias,
|
||||
firstLoginTime: Int(account.firstLogin.timeIntervalSince1970),
|
||||
status: account.status
|
||||
)
|
||||
)
|
||||
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,11 +163,8 @@ struct LoginDeviceRes: Content {
|
||||
struct Player: Content {
|
||||
let idpId: String
|
||||
let appId: String
|
||||
let lang: String
|
||||
let playerId: String
|
||||
let agreement: AgreementResponse
|
||||
let pushOption: PushOptionResponse
|
||||
let lastLoginTime: Int
|
||||
let regTime: Int
|
||||
let idpAlias: String
|
||||
let firstLoginTime: Int
|
||||
@@ -158,3 +184,9 @@ struct PushOptionResponse: Content {
|
||||
let night: String
|
||||
let player: String
|
||||
}
|
||||
|
||||
enum SessionType: Int {
|
||||
case ZAT = 0
|
||||
case ZRT = 1
|
||||
case VIEWER = 2
|
||||
}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import Fluent
|
||||
import struct Foundation.UUID
|
||||
|
||||
/// Property wrappers interact poorly with `Sendable` checking, causing a warning for the `@ID` property
|
||||
/// It is recommended you write your model with sendability checking on and then suppress the warning
|
||||
|
@@ -2,6 +2,7 @@ import NIOSSL
|
||||
import Fluent
|
||||
import FluentSQLiteDriver
|
||||
import Vapor
|
||||
import JWT
|
||||
|
||||
// configures your application
|
||||
public func configure(_ app: Application) async throws {
|
||||
@@ -14,6 +15,9 @@ public func configure(_ app: Application) async throws {
|
||||
app.http.server.configuration.hostname = "0.0.0.0"
|
||||
app.http.server.configuration.port = 8000
|
||||
|
||||
// JWT
|
||||
await app.jwt.keys.add(hmac: "secret", digestAlgorithm: .sha256)
|
||||
|
||||
// register routes
|
||||
try routes(app)
|
||||
}
|
||||
|
@@ -1,3 +1,43 @@
|
||||
import JWT
|
||||
import Fluent
|
||||
import Foundation
|
||||
|
||||
func generateIdpAlias(appId: String, deviceId: String, serialNo: String) -> String {
|
||||
return "\(appId):\(deviceId):\(serialNo)"
|
||||
}
|
||||
|
||||
func generateToken(accountId: Int, expires: Date, type: SessionType) -> SessionPayload {
|
||||
return SessionPayload(
|
||||
accountId: .init(value: String(accountId)),
|
||||
expiration: .init(value: expires),
|
||||
type: type.rawValue
|
||||
)
|
||||
}
|
||||
|
||||
struct SessionPayload: JWTPayload {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case accountId = "sub"
|
||||
case expiration = "exp"
|
||||
case type = "type"
|
||||
}
|
||||
|
||||
// The "sub" (subject) claim identifies the principal that is the
|
||||
// subject of the JWT.
|
||||
var accountId: SubjectClaim
|
||||
|
||||
// The "exp" (expiration time) claim identifies the expiration time on
|
||||
// or after which the JWT MUST NOT be accepted for processing.
|
||||
var expiration: ExpirationClaim
|
||||
|
||||
// Custom data.
|
||||
// If true, the user is an admin.
|
||||
var type: Int
|
||||
|
||||
// Run any additional verification logic beyond
|
||||
// signature verification here.
|
||||
// Since we have an ExpirationClaim, we will
|
||||
// call its verify method.
|
||||
func verify(using algorithm: some JWTAlgorithm) async throws {
|
||||
try self.expiration.verifyNotExpired()
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user