mirror of
https://github.com/crystelf/crystelf-core.git
synced 2025-07-04 14:49:19 +00:00
关闭未认证的WebSocket连接并重构Redis服务
在WebSocket认证失败时,主动关闭连接以提高安全性。重构了Redis服务中的方法,使其更加通用,并更新了相关的导入和调用。同时,调整了数据持久化路径的生成方式,支持自定义文件名。
This commit is contained in:
parent
a996bed065
commit
4a82585c29
@ -2,9 +2,9 @@ import Redis from 'ioredis';
|
|||||||
import logger from '../../utils/core/logger';
|
import logger from '../../utils/core/logger';
|
||||||
import tools from '../../utils/core/tool';
|
import tools from '../../utils/core/tool';
|
||||||
import config from '../../utils/core/config';
|
import config from '../../utils/core/config';
|
||||||
import redisTool from '../../utils/redis/redisTools';
|
import redisTools from '../../utils/redis/redisTools';
|
||||||
import IUser from '../../types/user';
|
|
||||||
import Persistence from '../../utils/redis/persistence';
|
import Persistence from '../../utils/redis/persistence';
|
||||||
|
import IUser from '../../types/user';
|
||||||
|
|
||||||
class RedisService {
|
class RedisService {
|
||||||
private client!: Redis;
|
private client!: Redis;
|
||||||
@ -93,7 +93,7 @@ class RedisService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async setObject<T>(key: string, value: T, ttl?: number): Promise<void> {
|
public async setObject<T>(key: string, value: T, ttl?: number): Promise<void> {
|
||||||
const serialized = redisTool.serialize(value);
|
const serialized = redisTools.serialize(value);
|
||||||
await this.getClient().set(key, serialized);
|
await this.getClient().set(key, serialized);
|
||||||
|
|
||||||
if (ttl) {
|
if (ttl) {
|
||||||
@ -105,66 +105,40 @@ class RedisService {
|
|||||||
const serialized = await this.getClient().get(key);
|
const serialized = await this.getClient().get(key);
|
||||||
if (!serialized) return undefined;
|
if (!serialized) return undefined;
|
||||||
|
|
||||||
const deserialized = redisTool.deserialize<T>(serialized);
|
const deseralized = redisTools.deserialize<T>(serialized);
|
||||||
return redisTool.reviveDates(deserialized);
|
return redisTools.reviveDates(deseralized);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateUser(qq: string, updates: Partial<IUser>): Promise<IUser> {
|
public async update<T>(key: string, updates: T): Promise<T> {
|
||||||
const existing = await this.getObject<IUser>(`user:${qq}`);
|
const existing = await this.getObject<T>(key);
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
throw new Error(`用户 ${qq} 不存在`);
|
logger.error(`数据${key}不存在..`);
|
||||||
}
|
}
|
||||||
const updatedUser = { ...existing, ...updates, updatedAt: new Date() };
|
const updated = { ...existing, ...updates };
|
||||||
await this.persistUser(updatedUser);
|
await this.setObject(key, updated);
|
||||||
return updatedUser;
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async persistUser<T extends IUser>(user: T): Promise<void> {
|
public async fetch<T>(key: string, fileName: string): Promise<T | undefined> {
|
||||||
try {
|
const data = await this.getObject<T>(key);
|
||||||
await Promise.all([
|
if (data) return data;
|
||||||
this.setObject(`user:${user.qq}`, user),
|
const fromLocal = await Persistence.readDataLocal<T>(key, fileName);
|
||||||
Persistence.writeDataLocal(user.name, user),
|
if (fromLocal) {
|
||||||
]);
|
await this.setObject(key, fromLocal);
|
||||||
} catch (err) {
|
return fromLocal;
|
||||||
logger.error(err);
|
|
||||||
throw err;
|
|
||||||
}
|
}
|
||||||
|
logger.error(`数据${key}不存在..`);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async fetchUser<T extends IUser>(
|
public async persistData<T>(key: string, data: T, fileName: string): Promise<void> {
|
||||||
qq: string,
|
await this.setObject(key, data);
|
||||||
username: string
|
await Persistence.writeDataLocal(key, data, fileName);
|
||||||
): Promise<IUser | undefined> {
|
return;
|
||||||
try {
|
|
||||||
const fromRedis = await this.getObject<IUser>(`user:${qq}`);
|
|
||||||
if (fromRedis) return fromRedis;
|
|
||||||
|
|
||||||
const fromLocal = await Persistence.readDataLocal<IUser>(username);
|
|
||||||
if (fromLocal) {
|
|
||||||
await this.setObject(`user:${qq}`, fromLocal);
|
|
||||||
return fromLocal;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.error(`用户${username},qq${qq}不存在!`);
|
|
||||||
return undefined;
|
|
||||||
} catch (err) {
|
|
||||||
logger.error(err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async test(): Promise<void> {
|
public async test(): Promise<void> {
|
||||||
const testData: IUser = {
|
const user = await this.fetch<IUser>('Jerry', 'IUser');
|
||||||
name: 'Jerry',
|
logger.debug('User:', user);
|
||||||
qq: '114514',
|
|
||||||
isAdmin: true,
|
|
||||||
password: '114514',
|
|
||||||
createdAt: new Date(),
|
|
||||||
};
|
|
||||||
|
|
||||||
await this.persistUser(testData);
|
|
||||||
const user = await this.fetchUser('114514', 'Jerry');
|
|
||||||
logger.debug(user);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +83,7 @@ class WSServer {
|
|||||||
} else {
|
} else {
|
||||||
logger.warn(`Auth failed from ${ip} (invalid secret), clientId: ${msg.clientId}`);
|
logger.warn(`Auth failed from ${ip} (invalid secret), clientId: ${msg.clientId}`);
|
||||||
await WsTools.send(socket, { type: 'auth', success: false });
|
await WsTools.send(socket, { type: 'auth', success: false });
|
||||||
|
socket.close(4001, 'Authentication failed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@ import logger from '../core/logger';
|
|||||||
import fs from 'fs/promises';
|
import fs from 'fs/promises';
|
||||||
|
|
||||||
class Persistence {
|
class Persistence {
|
||||||
private static getUserDataPath(username: string): string {
|
private static getUserDataPath(username: string, fileName: string): string {
|
||||||
return path.join(paths.get('userData'), username, 'data.json');
|
return path.join(paths.get('userData'), username, `${fileName}.json`);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async ensureUserPath(username: string): Promise<void> {
|
private static async ensureUserPath(username: string): Promise<void> {
|
||||||
@ -18,9 +18,13 @@ class Persistence {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async writeDataLocal<T>(username: string, data: T): Promise<void> {
|
public static async writeDataLocal<T>(
|
||||||
|
username: string,
|
||||||
|
data: T,
|
||||||
|
fileName: string
|
||||||
|
): Promise<void> {
|
||||||
await this.ensureUserPath(username);
|
await this.ensureUserPath(username);
|
||||||
const filePath = this.getUserDataPath(username);
|
const filePath = this.getUserDataPath(username, fileName);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fs.writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8');
|
await fs.writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8');
|
||||||
@ -30,8 +34,8 @@ class Persistence {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async readDataLocal<T>(username: string): Promise<T | undefined> {
|
public static async readDataLocal<T>(username: string, fileName: string): Promise<T | undefined> {
|
||||||
const filePath = this.getUserDataPath(username);
|
const filePath = this.getUserDataPath(username, fileName);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await fs.readFile(filePath, 'utf-8');
|
const data = await fs.readFile(filePath, 'utf-8');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user