import { Buffer } from "node:buffer" import config from "../config.ts" import User from "../data/User.ts" import crypto from 'node:crypto' import Token from "./Token.ts" import TokenType from "./TokenType.ts" function normalizeKey(key: string, keyLength = 32) { const hash = crypto.createHash('sha256') hash.update(key) const keyBuffer = hash.digest() return keyLength ? keyBuffer.slice(0, keyLength) : keyBuffer } export default class TokenManager { // TODO: 單令牌 -》 單 + 刷新 with 多設備管理 static makeAuth(user: User) { return crypto.createHash("sha256").update(user.bean.id + user.getPassword() + config.salt).digest().toString('hex') } static encode(token: Token) { return crypto.createCipheriv("aes-256-gcm", normalizeKey(config.aes_key), '01234567890123456').update( JSON.stringify(token) ).toString('hex') } static decode(token: string) { try { return JSON.parse(crypto.createDecipheriv("aes-256-gcm", normalizeKey(config.aes_key), '01234567890123456').update( Buffer.from(token, 'hex') ).toString()) as Token } catch(e) { return {} as Token } } static make(user: User, time_: number | null | undefined, device_id: string, tokenType: TokenType = "access_token") { const time = (time_ || Date.now()) return this.encode({ author: user.bean.id, auth: this.makeAuth(user), made_time: time, expired_time: time + (tokenType == 'access_token' ? (1000 * 60 * 60 * 2) : (40 * 1000 * 60 * 60 * 24)), device_id: device_id, type: tokenType }) } /** * 根据时间, 用户, 设备 ID (和类型 (默认访问令牌)) 检验令牌 */ static checkToken(token: Token, deviceId?: string, type: TokenType = 'access_token') { if (token.expired_time < Date.now()) return false if (!token.author || !User.findById(token.author)) return false if (deviceId != null) if (token.device_id != deviceId) return false if (token.type != type) return false return true } }