Files
OpenParty/core/database/DatabaseManager.js
ibratabian17 103d8259b3 feat: Hash user authentication tickets for enhanced security
Implement SHA256 hashing for user authentication tickets before storage. This prevents sensitive tokens from being stored in plain text, significantly improving security.

Changes include:
*   Hashing tickets in `AccountRouteHandler` and `UbiservicesRouteHandler` during profile updates and login flows.
*   Introducing dedicated `updateUserTicket` methods in `AccountRepository` and `AccountService`.
*   Adjusting the `Account` model to handle tickets separately.
*   Adding a new `config` table to the database schema.
2025-07-17 17:52:51 +07:00

174 lines
7.7 KiB
JavaScript

const sqlite3 = require('sqlite3').verbose();
const path = require('path');
const { getSavefilePath } = require('../helper');
const Logger = require('../utils/logger');
const DB_PATH = path.join(getSavefilePath(), 'openparty.db');
class DatabaseManager {
constructor() {
this.logger = new Logger('DatabaseManager');
if (DatabaseManager._instance) {
this.logger.info('Returning existing instance.');
return DatabaseManager._instance;
}
this._db = null;
DatabaseManager._instance = this;
this.logger.info('New instance created.');
}
static getInstance() {
if (!DatabaseManager._instance) {
DatabaseManager._instance = new DatabaseManager();
}
return DatabaseManager._instance;
}
initialize() {
if (this._db) {
this.logger.info('Database already initialized (this._db is set).');
return Promise.resolve(this._db);
}
this.logger.info('Starting database initialization...');
return new Promise((resolve, reject) => {
this._db = new sqlite3.Database(DB_PATH, (err) => {
if (err) {
this.logger.error('Error connecting to database:', err.message);
this._db = null;
reject(err);
} else {
this.logger.info('Connected to the SQLite database. this._db is now set.');
this._db.serialize(() => {
// Create most_played table
this._db.run(`CREATE TABLE IF NOT EXISTS most_played (
mapName TEXT PRIMARY KEY,
playCount INTEGER DEFAULT 0
)`, (err) => {
if (err) {
this.logger.error('Error creating most_played table:', err.message);
return reject(err);
}
});
// Create leaderboard table
this._db.run(`CREATE TABLE IF NOT EXISTS leaderboard (
id INTEGER PRIMARY KEY AUTOINCREMENT,
mapName TEXT NOT NULL,
profileId TEXT NOT NULL,
username TEXT NOT NULL,
score INTEGER NOT NULL,
timestamp TEXT NOT NULL,
UNIQUE(mapName, profileId)
)`, (err) => {
if (err) {
this.logger.error('Error creating leaderboard table:', err.message);
return reject(err);
}
});
// Create dotw (Dance of the Week) table
this._db.run(`CREATE TABLE IF NOT EXISTS dotw (
id INTEGER PRIMARY KEY AUTOINCREMENT,
mapName TEXT NOT NULL,
profileId TEXT NOT NULL,
username TEXT NOT NULL,
score INTEGER NOT NULL,
timestamp TEXT NOT NULL,
weekNumber INTEGER NOT NULL,
gameVersion TEXT,
rank INTEGER,
name TEXT,
avatar TEXT,
country TEXT,
platformId TEXT,
alias TEXT,
aliasGender INTEGER,
jdPoints INTEGER,
portraitBorder TEXT,
UNIQUE(mapName, profileId, weekNumber)
)`, (err) => {
if (err) {
this.logger.error('Error creating dotw table:', err.message);
return reject(err);
}
});
// Create user_profiles table
this._db.run(`CREATE TABLE IF NOT EXISTS user_profiles (
profileId TEXT PRIMARY KEY,
userId TEXT, -- Already present
username TEXT,
nickname TEXT,
name TEXT,
email TEXT,
password TEXT, -- Consider hashing if storing sensitive passwords
ticket TEXT,
alias TEXT,
aliasGender INTEGER,
avatar TEXT,
country TEXT,
platformId TEXT,
jdPoints INTEGER,
portraitBorder TEXT,
rank INTEGER,
scores TEXT, -- JSON stored as TEXT
favorites TEXT, -- JSON stored as TEXT
songsPlayed TEXT, -- JSON array stored as TEXT
progression TEXT, -- JSON stored as TEXT
history TEXT, -- JSON stored as TEXT
skin TEXT,
diamondPoints INTEGER,
unlockedAvatars TEXT, -- JSON array stored as TEXT
unlockedSkins TEXT, -- JSON array stored as TEXT
unlockedAliases TEXT, -- JSON array stored as TEXT
unlockedPortraitBorders TEXT, -- JSON array stored as TEXT
wdfRank INTEGER,
stars INTEGER,
unlocks INTEGER,
populations TEXT, -- JSON array stored as TEXT
inProgressAliases TEXT, -- JSON array stored as TEXT
language TEXT,
firstPartyEnv TEXT,
syncVersions TEXT, -- JSON stored as TEXT
otherPids TEXT, -- JSON array stored as TEXT
stats TEXT, -- JSON stored as TEXT
mapHistory TEXT, -- JSON stored as TEXT
createdAt TEXT,
updatedAt TEXT
)`, (err) => {
if (err) {
this.logger.error('Error creating user_profiles table:', err.message);
reject(err);
}
});
// Create config table
this._db.run(`CREATE TABLE IF NOT EXISTS config (
key TEXT PRIMARY KEY,
value TEXT
)`, (err) => {
if (err) {
this.logger.error('Error creating config table:', err.message);
return reject(err);
}
this.logger.info('All tables created. Resolving initialize promise.');
resolve(this._db);
});
});
}
});
});
}
getDb() {
this.logger.info(`getDb() called. this._db is: ${this._db ? 'set' : 'null'}`);
if (!this._db) {
throw new Error('DatabaseManager: Database not initialized. Call initialize() first.');
}
return this._db;
}
}
module.exports = DatabaseManager;