130 lines
4.3 KiB
JavaScript
130 lines
4.3 KiB
JavaScript
import * as PlayerModel from '../models/player.js'
|
|
import { createHash } from 'crypto'
|
|
import { generateToken, uuidToNoSymboUUID } from '../generator.js'
|
|
|
|
export const authenticate = {
|
|
method: 'POST',
|
|
url: '/authserver/authenticate',
|
|
schema: {
|
|
body: {
|
|
"type": "object",
|
|
"properties": {
|
|
"username": {
|
|
"type": "string"
|
|
},
|
|
"password": {
|
|
"type": "string"
|
|
},
|
|
"clientToken": {
|
|
"type": "string"
|
|
},
|
|
"requestUser": {
|
|
"type": "boolean"
|
|
},
|
|
"agent": {
|
|
"type": "object",
|
|
"properties": {
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"version": {
|
|
"type": "integer"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
response: {
|
|
200: {
|
|
"type": "object",
|
|
"properties": {
|
|
"accessToken": {
|
|
"type": "string"
|
|
},
|
|
"clientToken": {
|
|
"type": "string"
|
|
},
|
|
"availableProfiles": {
|
|
"type": "array",
|
|
"items": [{...PlayerModel.PlayerSeriliazationSchema}]
|
|
},
|
|
"selectedProfile": PlayerModel.PlayerSeriliazationSchema,
|
|
"user": PlayerModel.PlayerAccountSerializationSchema
|
|
}
|
|
}
|
|
}
|
|
},
|
|
preHandler: async function(req, rep) {
|
|
this.conf.custom.overridePrehandler('/authserver/authenticate')
|
|
},
|
|
handler: async function (req, rep) {
|
|
let { username, password, clientToken, requestUser, agent } = req.body
|
|
const player = await this.models.Player.findOne({ email: username, password: createHash('sha256').update(password).digest().toString('hex').toLowerCase() })
|
|
if(!player || !player.permissions.some((it) => {
|
|
return it.node === 'login' && it.allowed && (it.duration === 0 || it.startDate + it.duration > Date.now())
|
|
})) {
|
|
return await rep.code(401).send({
|
|
error: "Unauthorized",
|
|
errorMessage: "用户名或密码错误",
|
|
cause: "用户名或密码错误"
|
|
})
|
|
}
|
|
|
|
if(!clientToken) {
|
|
clientToken = createHash('sha256').update( "" + Math.random() * 1.048596).digest().toString('hex')
|
|
}
|
|
|
|
const [token, key] = await generateToken(clientToken, requestUser, agent)
|
|
this.log.info(`/authserver/authenticate > 为玩家 ${username} 生成令牌: ${token} | 随机 key = ${key}`)
|
|
|
|
const account = {
|
|
id: uuidToNoSymboUUID(player.uuid),
|
|
properties: [
|
|
{
|
|
preferredLanguage: "zh_CN"
|
|
}
|
|
]
|
|
}
|
|
|
|
const textures = {
|
|
timestamp: 0,
|
|
profileId: uuidToNoSymboUUID(player.uuid),
|
|
profileName: player.username,
|
|
textures: { }
|
|
}
|
|
|
|
if(player.textures.skin && player.textures.skin != 0) { // Must be '!=' if this change to '!==' will never works
|
|
textures.textures.SKIN = {
|
|
url: player.textures.skin,
|
|
metadata
|
|
}
|
|
}
|
|
|
|
const profile = {
|
|
uuid: uuidToNoSymboUUID(player.uuid),
|
|
name: player.username,
|
|
properties: [
|
|
{
|
|
name: "texturs",
|
|
value: Buffer.from(JSON.stringify(textures)).toString('base64')
|
|
}
|
|
]
|
|
}
|
|
|
|
new this.models.Token({
|
|
uuid: player.uuid,
|
|
token: token,
|
|
expireDate: Date.now() + 1000 * 60 * 60 * 24 * 15,
|
|
deadDate: Date.now() + 1000 * 60 * 60 * 24 * 30,
|
|
state: 'alive'
|
|
}).save()
|
|
|
|
return await rep.send({
|
|
accessToken: token,
|
|
clientToken: clientToken,
|
|
availableProfiles: [ profile ],
|
|
selectedProfile: profile,
|
|
user: account
|
|
})
|
|
}
|
|
} |