diff --git a/package.json b/package.json index 15f843ce..0bc74fb7 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,6 @@ "build:libs": "npm run build -w packages/core -w packages/api" }, "devDependencies": { - "concurrently": "^9.0.1" + "concurrently": "^9.1.0" } } diff --git a/packages/api/package.json b/packages/api/package.json index 69c6391e..562c6b9a 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -34,18 +34,18 @@ }, "homepage": "https://github.com/AuroraTeam/AuroraAPI#readme", "dependencies": { - "@aurora-launcher/core": "^0.23.0", - "aurora-rpc-client": "^0.3.3" + "@aurora-launcher/core": "^0.24.0", + "aurora-rpc-client": "^0.3.4" }, "devDependencies": { - "@types/ws": "^8.5.10", - "concurrently": "^9.0.1", + "@types/ws": "^8.5.13", + "concurrently": "^9.1.0", "esbuild": "^0.24.0", "import-sort-style-module": "^6.0.0", - "prettier": "^3.2.5", + "prettier": "^3.3.3", "prettier-plugin-import-sort": "0.0.7", "rimraf": "^6.0.1", - "typescript": "^5.3.3" + "typescript": "^5.6.3" }, "directories": { "example": "example" diff --git a/packages/core/.eslintignore b/packages/core/.eslintignore deleted file mode 100644 index 76add878..00000000 --- a/packages/core/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -dist \ No newline at end of file diff --git a/packages/core/.eslintrc.js b/packages/core/.eslintrc.js deleted file mode 100644 index 45730c55..00000000 --- a/packages/core/.eslintrc.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - env: { - commonjs: true, - es2021: true, - node: true, - }, - extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], - overrides: [], - parser: "@typescript-eslint/parser", - parserOptions: { - ecmaVersion: "latest", - }, - plugins: ["@typescript-eslint"], - rules: {}, -} diff --git a/packages/core/eslint.config.mjs b/packages/core/eslint.config.mjs new file mode 100644 index 00000000..2651c93e --- /dev/null +++ b/packages/core/eslint.config.mjs @@ -0,0 +1,13 @@ +import globals from "globals" +import pluginJs from "@eslint/js" +import tseslint from "typescript-eslint" + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { ignores: ["dist"] }, + { files: ["**/*.{js,mjs,cjs,ts}"] }, + { files: ["**/*.js"], languageOptions: { sourceType: "commonjs" } }, + { languageOptions: { globals: globals.node } }, + pluginJs.configs.recommended, + ...tseslint.configs.recommended, +] diff --git a/packages/core/package.json b/packages/core/package.json index abe01c8b..81098e7d 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@aurora-launcher/core", - "version": "0.23.0", + "version": "0.25.0", "description": "Base library for Aurora Launcher", "type": "commonjs", "main": "./dist/index.js", @@ -15,8 +15,8 @@ "dev": "tsup --watch", "build": "tsup", "prettier": "prettier --write src", - "lint": "eslint . --ext .ts", - "lint:fix": "npm run lint -- --fix", + "lint": "eslint", + "lint:fix": "eslint --fix", "prepublishOnly": "npm run build" }, "repository": { @@ -43,21 +43,22 @@ "src" ], "devDependencies": { - "@tsconfig/node20": "^20.1.2", - "@tsconfig/strictest": "^2.0.3", - "@types/node": "^20.11.24", - "@typescript-eslint/eslint-plugin": "^7.1.1", - "@typescript-eslint/parser": "^7.1.1", - "eslint": "^8.56.0", + "@eslint/js": "^9.14.0", + "@tsconfig/node20": "^20.1.4", + "@tsconfig/strictest": "^2.0.5", + "@types/node": "^22.9.0", + "eslint": "^9.14.0", + "globals": "^15.12.0", "import-sort-style-module": "^6.0.0", - "prettier": "^3.2.5", + "prettier": "^3.3.3", "prettier-plugin-import-sort": "0.0.7", - "tsup": "^8.0.2", - "typescript": "^5.3.3" + "tsup": "^8.3.5", + "typescript": "^5.6.3", + "typescript-eslint": "^8.13.0" }, "dependencies": { - "adm-zip": "^0.5.10", + "adm-zip": "^0.5.16", "p-map": "^7.0.2", - "undici": "^6.7.0" + "undici": "^6.20.1" } } diff --git a/packages/core/src/helpers/HashHelper.ts b/packages/core/src/helpers/HashHelper.ts index 5c395533..95aae9c4 100644 --- a/packages/core/src/helpers/HashHelper.ts +++ b/packages/core/src/helpers/HashHelper.ts @@ -2,11 +2,34 @@ import { BinaryLike, createHash } from "crypto" import { readFile } from "fs/promises" export class HashHelper { - static getHash(str: BinaryLike, type: string) { - return createHash(type).update(str).digest("hex") + /** + * Получить хеш данных + * @param data Данные + * @param type Тип хеша + * @returns Хеш данных + */ + static getHash(data: BinaryLike, type: string) { + return createHash(type).update(data).digest("hex") } + /** + * Получить хеш файла + * @param path Путь до файла + * @param type Тип хеша + * @returns Хеш файла + */ static async getHashFromFile(path: string, type: string) { return this.getHash(await readFile(path), type) } + + /** + * Сверить хеш файла с предоставленным хешем + * @param path Путь до файла + * @param type Тип хеша + * @param fileHash Хеш файла + * @returns `true` в случае совпадения, `false` в противном случае + */ + static async compareFileHash(path: string, type: string, fileHash: string) { + return (await this.getHashFromFile(path, type)) === fileHash + } } diff --git a/packages/core/src/helpers/HttpHelper.ts b/packages/core/src/helpers/HttpHelper.ts index 07849ace..7757d0cb 100644 --- a/packages/core/src/helpers/HttpHelper.ts +++ b/packages/core/src/helpers/HttpHelper.ts @@ -41,7 +41,7 @@ export class HttpHelper { try { const { statusCode } = await request(url, { method: "HEAD" }) return statusCode >= 200 && statusCode < 300 - } catch (error) { + } catch { return false } } @@ -233,16 +233,14 @@ export class HttpHelper { private static async verifyFileHash(file: File) { if (!file.sha1) return false - let currentHash try { - currentHash = await HashHelper.getHashFromFile( + return await HashHelper.compareFileHash( file.destinationPath, "sha1", + file.sha1, ) - } catch (error) { + } catch { return false } - - return file.sha1 === currentHash } } diff --git a/packages/core/src/helpers/JsonHelper.ts b/packages/core/src/helpers/JsonHelper.ts index c7c18364..08bc14bd 100644 --- a/packages/core/src/helpers/JsonHelper.ts +++ b/packages/core/src/helpers/JsonHelper.ts @@ -1,5 +1,4 @@ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type JsonData = Record | any[] +export type JsonData = unknown /** * Класс хелпер для работы с JSON diff --git a/packages/core/src/helpers/ZipHelper.ts b/packages/core/src/helpers/ZipHelper.ts index 65ef4574..43b8492d 100644 --- a/packages/core/src/helpers/ZipHelper.ts +++ b/packages/core/src/helpers/ZipHelper.ts @@ -1,6 +1,7 @@ import { extname } from "path" import AdmZip from "adm-zip" +import { HashHelper } from "./HashHelper" export class ZipHelper { /** @@ -18,7 +19,7 @@ export class ZipHelper { onProgress?: (size: number) => void, ) { const zip = new AdmZip(archive) - const extractedFiles: string[] = [] + const extractedFiles: { path: string; sha1: string }[] = [] zip.getEntries().forEach((entry) => { if ( @@ -29,7 +30,11 @@ export class ZipHelper { return onProgress && onProgress(entry.header.compressedSize) - extractedFiles.push(entry.entryName) + const sha1 = HashHelper.getHash(entry.getData(), "sha1") + extractedFiles.push({ + path: entry.entryName, + sha1, + }) zip.extractEntryTo(entry, destDir, true, true) }) diff --git a/packages/esbuild-decorators/index.js b/packages/esbuild-decorators/index.js index c9d9d8bd..1ed0d7c7 100644 --- a/packages/esbuild-decorators/index.js +++ b/packages/esbuild-decorators/index.js @@ -31,7 +31,7 @@ export const esbuildDecorators = () => ({ const result = await swc.transformFile(args.path, { jsc, - sourceMaps: true, + sourceMaps: false, configFile: false, swcrc: false, }); @@ -46,7 +46,7 @@ export const esbuildDecorators = () => ({ : source; }); code += `//# sourceMappingURL=data:application/json;base64,${Buffer.from( - JSON.stringify(map) + JSON.stringify(map), ).toString("base64")}`; } return { diff --git a/packages/esbuild-decorators/package.json b/packages/esbuild-decorators/package.json index c900983b..a19a7ca6 100644 --- a/packages/esbuild-decorators/package.json +++ b/packages/esbuild-decorators/package.json @@ -15,7 +15,7 @@ } }, "dependencies": { - "@swc/core": "^1.7.26" + "@swc/core": "^1.9.1" }, "repository": { "type": "git", diff --git a/packages/launcher b/packages/launcher index 009b0991..ae56199f 160000 --- a/packages/launcher +++ b/packages/launcher @@ -1 +1 @@ -Subproject commit 009b0991f93968240960981002b981594f85f496 +Subproject commit ae56199fff4b3c3e380a23903f00f47675f1c941 diff --git a/packages/server/.eslintignore b/packages/server/.eslintignore deleted file mode 100644 index 76add878..00000000 --- a/packages/server/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -dist \ No newline at end of file diff --git a/packages/server/.eslintrc.js b/packages/server/.eslintrc.js deleted file mode 100644 index dec98d7f..00000000 --- a/packages/server/.eslintrc.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - env: { - es2021: true, - node: true, - }, - extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], - overrides: [], - parser: "@typescript-eslint/parser", - parserOptions: { - ecmaVersion: "latest", - }, - plugins: ["@typescript-eslint", "node"], - rules: { - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-empty-function": "off", - }, -}; diff --git a/packages/server/eslint.config.mjs b/packages/server/eslint.config.mjs new file mode 100644 index 00000000..6bf65c64 --- /dev/null +++ b/packages/server/eslint.config.mjs @@ -0,0 +1,18 @@ +import pluginJs from "@eslint/js"; +import globals from "globals"; +import tseslint from "typescript-eslint"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { ignores: ["dist"] }, + { files: ["**/*.{js,mjs,cjs,ts}"] }, + { files: ["**/*.js"], languageOptions: { sourceType: "commonjs" } }, + { languageOptions: { globals: globals.node } }, + pluginJs.configs.recommended, + ...tseslint.configs.recommended, + { + rules: { + "@typescript-eslint/no-explicit-any": "off", + }, + }, +]; diff --git a/packages/server/package.json b/packages/server/package.json index 943f2ff2..4ed03cdc 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@aurora-launcher/server", - "version": "0.0.5-dev.2", + "version": "0.0.5-dev.3", "description": "LauncherServer for AuroraLauncher", "keywords": [ "minecraft", @@ -27,43 +27,43 @@ "dev": "node scripts/dev.mjs", "build:dev": "node scripts/build.mjs", "build:prod": "node scripts/build.mjs --prod", - "build:bin": "pkg dist/LauncherServer.js -t node20-linux-x64,node20-macos-x64,node20-win-x64 --out-path dist --compress GZip", + "build:bin": "pkg dist/LauncherServer.js -t node22-linux-x64,node22-macos-x64,node22-win-x64 --out-path dist --compress GZip", "clean": "rimraf dist", "prettier": "prettier --write src", "typecheck": "tsc --noEmit", - "lint": "eslint . --ext .ts", - "lint:fix": "eslint . --ext .ts --fix", + "lint": "eslint", + "lint:fix": "eslint --fix", "start": "node ." }, "devDependencies": { "@aurora-launcher/esbuild-decorators": "^0.0.1", - "@types/adm-zip": "^0.5.5", - "@types/cli-progress": "^3.11.5", + "@eslint/js": "^9.14.0", + "@types/adm-zip": "^0.5.6", + "@types/cli-progress": "^3.11.6", "@types/hjson": "^2.4.6", "@types/lodash-es": "^4.17.12", - "@types/node": "^20.11.24", + "@types/node": "^22.9.0", "@types/prompts": "^2.4.9", "@types/semver": "^7.5.8", "@types/uuid": "^10.0.0", - "@types/ws": "^8.5.10", - "@typescript-eslint/eslint-plugin": "^7.1.1", - "@typescript-eslint/parser": "^7.1.1", - "@yao-pkg/pkg": "^5.11.4", - "concurrently": "^9.0.1", + "@types/ws": "^8.5.13", + "@yao-pkg/pkg": "^6.1.0", + "concurrently": "^9.1.0", "esbuild": "^0.24.0", - "eslint": "^8.56.0", - "eslint-plugin-node": "^11.1.0", + "eslint": "^9.14.0", + "globals": "^15.12.0", "import-sort-style-module": "^6.0.0", "minimist": "^1.2.8", - "nodemon": "^3.1.0", - "prettier": "^3.2.5", + "nodemon": "^3.1.7", + "prettier": "^3.3.3", "prettier-plugin-import-sort": "0.0.7", "rimraf": "^6.0.1", - "typescript": "^5.3.3" + "typescript": "^5.6.3", + "typescript-eslint": "^8.13.0" }, "dependencies": { - "@aurora-launcher/core": "^0.23.0", - "aurora-rpc-server": "^0.1.5", + "@aurora-launcher/core": "^0.24.0", + "aurora-rpc-server": "^0.1.6", "chalk": "^5.3.0", "chokidar": "^4.0.1", "class-transformer": "^0.5.1", @@ -74,19 +74,19 @@ "hjson": "^3.2.2", "lodash-es": "^4.17.21", "mssql": "^11.0.1", - "mysql2": "^3.9.2", - "oracledb": "^6.3.0", - "pg": "^8.11.3", + "mysql2": "^3.11.4", + "oracledb": "^6.6.0", + "pg": "^8.13.1", "prompts": "^2.4.2", "raw-body": "^3.0.0", - "reflect-metadata": "^0.2.1", - "semver": "^7.6.0", + "reflect-metadata": "^0.2.2", + "semver": "^7.6.3", "source-map-support": "^0.5.21", "sqlite3": "^5.1.7", "strip-ansi": "^7.1.0", "typedi": "^0.10.0", "typeorm": "^0.3.20", - "uuid": "^10.0.0" + "uuid": "^11.0.2" }, "importSort": { ".js, .mjs, .ts": { diff --git a/packages/server/src/components/api/webserver/requests/AbstractRequest.ts b/packages/server/src/components/api/webserver/requests/AbstractRequest.ts index 9ab23e9f..6c5ec4eb 100644 --- a/packages/server/src/components/api/webserver/requests/AbstractRequest.ts +++ b/packages/server/src/components/api/webserver/requests/AbstractRequest.ts @@ -7,7 +7,6 @@ export abstract class AbstractRequest { abstract emit(req: WebRequest, res: WebResponse): PromiseOr; - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types protected isInvalidValue(param: any): boolean { return typeof param !== "string" || param.trim().length === 0; } diff --git a/packages/server/src/components/api/webserver/requests/InjectorRequest.ts b/packages/server/src/components/api/webserver/requests/InjectorRequest.ts index c874bb41..8e73c7e3 100644 --- a/packages/server/src/components/api/webserver/requests/InjectorRequest.ts +++ b/packages/server/src/components/api/webserver/requests/InjectorRequest.ts @@ -2,6 +2,7 @@ import { AuthlibManager } from "@root/components/authlib"; import { ConfigManager } from "@root/components/config"; import { Service } from "typedi"; +import { SkinManager } from "../../../skin"; import { WebRequest } from "../WebRequest"; import { WebResponse } from "../WebResponse"; import { AbstractRequest } from "./AbstractRequest"; @@ -19,13 +20,14 @@ export class InjectorWebRequest extends AbstractRequest { } async emit(_: WebRequest, res: WebResponse): Promise { + const skinManeger = new SkinManager(this.configManager.config.skin); res.json({ meta: { serverName: this.configManager.config.projectName || "Aurora Launcher", implementationName: "aurora-launchserver", implementationVersion: "0.0.1", }, - skinDomains: this.configManager.config.api.injector.skinDomains, + skinDomains: [skinManeger.getDomainUrl()], signaturePublickey: this.authlibManager.getPublicKey(), }); } diff --git a/packages/server/src/components/api/webserver/requests/authlib/accountsHost/ProfilesRequest.ts b/packages/server/src/components/api/webserver/requests/authlib/accountsHost/ProfilesRequest.ts index 0633c8c7..deddb057 100644 --- a/packages/server/src/components/api/webserver/requests/authlib/accountsHost/ProfilesRequest.ts +++ b/packages/server/src/components/api/webserver/requests/authlib/accountsHost/ProfilesRequest.ts @@ -20,7 +20,7 @@ export class ProfilesWebRequest extends AbstractRequest { try { data = JsonHelper.fromJson(req.body); - } catch (error) { + } catch { return res.error(400, "BadRequestException"); } diff --git a/packages/server/src/components/api/webserver/requests/authlib/sessionHost/ProfileRequest.ts b/packages/server/src/components/api/webserver/requests/authlib/sessionHost/ProfileRequest.ts index 46632aec..ac97e7fb 100644 --- a/packages/server/src/components/api/webserver/requests/authlib/sessionHost/ProfileRequest.ts +++ b/packages/server/src/components/api/webserver/requests/authlib/sessionHost/ProfileRequest.ts @@ -28,7 +28,7 @@ export class ProfileWebRequest extends AbstractRequest { let user; try { user = await this.authProvider.profile(UUIDHelper.getWithDashes(uuid)); - } catch (error) { + } catch { res.raw.statusCode = 204; res.raw.end(); return; diff --git a/packages/server/src/components/api/webserver/requests/release-server/DownloadReleaseRequest.ts b/packages/server/src/components/api/webserver/requests/release-server/DownloadReleaseRequest.ts index 258efe97..35d3341a 100644 --- a/packages/server/src/components/api/webserver/requests/release-server/DownloadReleaseRequest.ts +++ b/packages/server/src/components/api/webserver/requests/release-server/DownloadReleaseRequest.ts @@ -7,14 +7,14 @@ import { WebResponse } from "../../WebResponse"; import { AbstractRequest } from "../AbstractRequest"; import { writeFileSync } from "fs"; import { resolve } from "path" -import { token } from "./Token"; +import { TokenManager } from "./Token"; @Service() export class DownloadRelease extends AbstractRequest { method = "POST"; url = /^\/release\/upload/; - constructor(private verifyManager: VerifyManager) { + constructor(private verifyManager: VerifyManager, private tokenManager: TokenManager) { super(); } @@ -28,7 +28,7 @@ export class DownloadRelease extends AbstractRequest { res.raw.statusCode = 500 res.raw.end() } - if ( decryptedToken == token){ + if ( decryptedToken == this.tokenManager.getToken() ){ writeFileSync(resolve(StorageHelper.releaseDir, req.raw.headers["content-disposition"]), req.file) } res.raw.end() diff --git a/packages/server/src/components/api/webserver/requests/release-server/GetTokenRequest.ts b/packages/server/src/components/api/webserver/requests/release-server/GetTokenRequest.ts index e1525bd7..e6728524 100644 --- a/packages/server/src/components/api/webserver/requests/release-server/GetTokenRequest.ts +++ b/packages/server/src/components/api/webserver/requests/release-server/GetTokenRequest.ts @@ -1,22 +1,20 @@ import { Service } from "typedi"; -import { VerifyManager } from "@root/components/secure/VerifyManager"; import { WebRequest } from "../../WebRequest"; import { WebResponse } from "../../WebResponse"; import { AbstractRequest } from "../AbstractRequest"; -import { token } from "./Token"; +import { TokenManager } from "./Token"; @Service() export class GetToken extends AbstractRequest { method = "GET"; url = /^\/release\/get_token$/; - constructor(private verifyManager: VerifyManager) { + constructor(private tokenManager: TokenManager) { super(); } async emit(req: WebRequest, res: WebResponse): Promise { - const encryptedToken = this.verifyManager.encryptToken(token) - res.json({token: encryptedToken}) + res.json({token: this.tokenManager.getEncryptedToken()}) } } diff --git a/packages/server/src/components/api/webserver/requests/release-server/Token.ts b/packages/server/src/components/api/webserver/requests/release-server/Token.ts index 0971a082..6dc957cf 100644 --- a/packages/server/src/components/api/webserver/requests/release-server/Token.ts +++ b/packages/server/src/components/api/webserver/requests/release-server/Token.ts @@ -1,2 +1,17 @@ import { SecureHelper } from "@root/utils"; -export const token = SecureHelper.generateRandomToken(32) \ No newline at end of file +import { VerifyManager } from "@root/components/secure/VerifyManager"; +import { Service } from "typedi"; + +@Service() +export class TokenManager { + constructor(private verifyManager: VerifyManager) {} + private token = SecureHelper.generateRandomToken(32) + private encryptedToken = this.verifyManager.encryptToken(this.token) + + public getToken(){ + return this.token + } + public getEncryptedToken(){ + return this.encryptedToken + } +} \ No newline at end of file diff --git a/packages/server/src/components/auth/AuthManager.ts b/packages/server/src/components/auth/AuthManager.ts index 799295e1..1a3ecd05 100644 --- a/packages/server/src/components/auth/AuthManager.ts +++ b/packages/server/src/components/auth/AuthManager.ts @@ -4,6 +4,7 @@ import { Service } from "typedi"; import { ConfigManager } from "../config"; import { LangManager } from "../langs"; import { AuthProvider, AuthProviderConstructor } from "./providers"; +import { SkinManager } from "../skin/SkinManager"; @Service() export class AuthManager { @@ -23,6 +24,7 @@ export class AuthManager { } const Provider = AuthManager.authProviders.get(providerType); - return new Provider(configManager.config); + const skinManager = new SkinManager(configManager.config.skin); + return new Provider(configManager.config, skinManager); } } diff --git a/packages/server/src/components/auth/providers/AcceptAuthProvider.ts b/packages/server/src/components/auth/providers/AcceptAuthProvider.ts index 0fb46052..ed1d1352 100644 --- a/packages/server/src/components/auth/providers/AcceptAuthProvider.ts +++ b/packages/server/src/components/auth/providers/AcceptAuthProvider.ts @@ -2,6 +2,7 @@ import { randomUUID } from "crypto"; import { AuthResponseData } from "@aurora-launcher/core"; import { LauncherServerConfig } from "@root/components/config/utils/LauncherServerConfig"; +import { SkinManager } from "../../skin"; import { v5 } from "uuid"; import { @@ -13,17 +14,23 @@ import { export class AcceptAuthProvider implements AuthProvider { private projectID: string; + private skinManager: SkinManager; private sessionsDB: UserData[] = []; - constructor({ projectID }: LauncherServerConfig) { + constructor({ projectID }: LauncherServerConfig, skinManager: SkinManager) { this.projectID = projectID; + this.skinManager = skinManager; } auth(username: string): AuthResponseData { + + const userUUID = v5(username, this.projectID) const data = { username, - userUUID: v5(username, this.projectID), + userUUID, accessToken: randomUUID(), + skinUrl: this.skinManager.getSkin(userUUID, username), + capeUrl: this.skinManager.getCape(userUUID, username), }; const userIndex = this.sessionsDB.findIndex((user) => user.username === username); @@ -80,4 +87,6 @@ interface UserData { userUUID: string; accessToken: string; serverId: string; + skinUrl?: string; + capeUrl?: string; } diff --git a/packages/server/src/components/auth/providers/AuthProvider.ts b/packages/server/src/components/auth/providers/AuthProvider.ts index 77717eba..c3d5c2cd 100644 --- a/packages/server/src/components/auth/providers/AuthProvider.ts +++ b/packages/server/src/components/auth/providers/AuthProvider.ts @@ -1,8 +1,9 @@ import { AuthResponseData } from "@aurora-launcher/core"; import { LauncherServerConfig } from "@root/components/config/utils/LauncherServerConfig"; +import { SkinManager } from "../../skin/SkinManager"; export interface AuthProviderConstructor { - new (configManager: LauncherServerConfig): AuthProvider; + new (configManager: LauncherServerConfig, skinManager: SkinManager): AuthProvider; } export interface AuthProvider { diff --git a/packages/server/src/components/auth/providers/DatabaseAuthProvider.ts b/packages/server/src/components/auth/providers/DatabaseAuthProvider.ts index 59c967d2..b3e3bc66 100644 --- a/packages/server/src/components/auth/providers/DatabaseAuthProvider.ts +++ b/packages/server/src/components/auth/providers/DatabaseAuthProvider.ts @@ -13,14 +13,17 @@ import { import { randomUUID } from "crypto"; import { ResponseError } from "aurora-rpc-server"; import { DatabasePasswordProvider } from "./DatabasePasswordProvider"; +import { SkinManager } from "../../skin/SkinManager"; export class DatabaseAuthProvider implements AuthProvider { private userRepository; + private skinManager: SkinManager; private passwordProvider; - constructor({ auth }: LauncherServerConfig) { + constructor({ auth }: LauncherServerConfig, skinManager: SkinManager) { const authConfig = auth; this.passwordProvider = new DatabasePasswordProvider(authConfig); + this.skinManager = skinManager; if (!authConfig.properties.tableName) { LogHelper.fatal("tableName not defined"); @@ -47,8 +50,8 @@ export class DatabaseAuthProvider implements AuthProvider { const userData = { username, userUUID: user.userUUID, - skinUrl: user.skinUrl, - capeUrl: user.capeUrl, + skinUrl: this.skinManager.getSkin(user.userUUID, username), + capeUrl: this.skinManager.getCape(user.userUUID, username), accessToken: randomUUID(), }; @@ -82,8 +85,8 @@ export class DatabaseAuthProvider implements AuthProvider { return { userUUID: user.userUUID, - skinUrl: user.skinUrl, - capeUrl: user.capeUrl, + skinUrl: this.skinManager.getSkin(user.userUUID, username), + capeUrl: this.skinManager.getCape(user.userUUID, username), }; } @@ -93,8 +96,8 @@ export class DatabaseAuthProvider implements AuthProvider { return { username: user.username, - skinUrl: user.skinUrl, - capeUrl: user.capeUrl, + skinUrl: this.skinManager.getSkin(userUUID, user.username), + capeUrl: this.skinManager.getCape(userUUID, user.username), }; } @@ -135,14 +138,6 @@ const getUserEntity = (properties: DatabaseAuthProviderConfig["properties"]) => type: String, name: properties.serverIdColumn, }, - skinUrl: { - type: String, - name: properties.skinUrlColumn, - }, - capeUrl: { - type: String, - name: properties.capeUrlColumn, - }, }, }); }; @@ -165,8 +160,6 @@ export class DatabaseAuthProviderConfig extends AuthProviderConfig { passwordColumn: string; accessTokenColumn: string; serverIdColumn: string; - skinUrlColumn: string; - capeUrlColumn: string; }; } @@ -178,6 +171,4 @@ interface UserEntity { userUUID: string; accessToken: string; serverID: string; - skinUrl: string; - capeUrl: string; } diff --git a/packages/server/src/components/auth/providers/DatabasePasswordProvider.ts b/packages/server/src/components/auth/providers/DatabasePasswordProvider.ts index be1f4b3e..e305c402 100644 --- a/packages/server/src/components/auth/providers/DatabasePasswordProvider.ts +++ b/packages/server/src/components/auth/providers/DatabasePasswordProvider.ts @@ -72,7 +72,7 @@ export class DatabasePasswordProvider { result.push((pass: string, salt: string) => HashHelper.getHash(inner(pass, salt), algo), ); - } catch (error) { + } catch { throw new Error(`Unsupported algorithm: ${algo}`); } } diff --git a/packages/server/src/components/auth/providers/JsonAuthProvider.ts b/packages/server/src/components/auth/providers/JsonAuthProvider.ts index 614fa874..39eb4932 100644 --- a/packages/server/src/components/auth/providers/JsonAuthProvider.ts +++ b/packages/server/src/components/auth/providers/JsonAuthProvider.ts @@ -9,22 +9,28 @@ import { ProfileResponseData, ProfilesResponseData, } from "./AuthProvider"; +import { SkinManager } from "../../skin/SkinManager"; export class JsonAuthProvider implements AuthProvider { private config: JsonAuthProviderConfig; + private skinManager: SkinManager; - constructor({ auth }: LauncherServerConfig) { + constructor({ auth }: LauncherServerConfig, skinManager: SkinManager) { this.config = auth; + this.skinManager = skinManager; } async auth(login: string, password: string): Promise { try { - return this.parseResponse( - await HttpHelper.postJson>(this.config.authUrl, { - login, - password, - }), - ); + const response: ApiResponse = await HttpHelper.postJson>(this.config.authUrl, { + login, + password, + }); + if (response.success === true) { + response.result.capeUrl = this.skinManager.getCape(response.result.userUUID, response.result.username); + response.result.skinUrl = this.skinManager.getSkin(response.result.userUUID, response.result.username); + } + return this.parseResponse(response); } catch (error) { throw new ResponseError(error.message, 200); } @@ -41,20 +47,26 @@ export class JsonAuthProvider implements AuthProvider { } async hasJoined(username: string, serverID: string): Promise { - return this.parseResponse( - await HttpHelper.postJson>( - this.config.hasJoinedUrl, - { username, serverID }, - ), + const response: ApiResponse = await HttpHelper.postJson>( + this.config.hasJoinedUrl, + { username, serverID }, ); + if (response.success === true) { + response.result.capeUrl = this.skinManager.getCape(response.result.userUUID, username); + response.result.skinUrl = this.skinManager.getSkin(response.result.userUUID, username); + } + return this.parseResponse(response); } async profile(userUUID: string): Promise { - return this.parseResponse( - await HttpHelper.postJson>(this.config.profileUrl, { - userUUID, - }), - ); + const response: ApiResponse = await HttpHelper.postJson>(this.config.profileUrl, { + userUUID, + }); + if (response.success === true) { + response.result.capeUrl = this.skinManager.getCape(userUUID, response.result.username); + response.result.skinUrl = this.skinManager.getSkin(userUUID, response.result.username); + } + return this.parseResponse(response); } async profiles(usernames: string[]): Promise { @@ -90,4 +102,19 @@ interface ApiError { error: string; } +interface ApiAuthResponseData { + username: string + userUUID: string + accessToken: string + token:string +} + +interface ApiHasJoinedResponseData { + userUUID: string; +} + +interface ApiProfileResponseData { + username: string; +} + type ApiResponse = ApiResult | ApiError; diff --git a/packages/server/src/components/authlib/AuthlibManager.ts b/packages/server/src/components/authlib/AuthlibManager.ts index 2c21d057..0fd96595 100644 --- a/packages/server/src/components/authlib/AuthlibManager.ts +++ b/packages/server/src/components/authlib/AuthlibManager.ts @@ -18,7 +18,7 @@ export class AuthlibManager { try { this.readAndSetKeys(); LogHelper.info(langManager.getTranslate.AuthlibManager.keysExists); - } catch (error) { + } catch { this.generateKeys(); this.readAndSetKeys(); } diff --git a/packages/server/src/components/commands/commands/updates/DownloadClientCommand.ts b/packages/server/src/components/commands/commands/updates/DownloadClientCommand.ts index ec46c069..aadad465 100644 --- a/packages/server/src/components/commands/commands/updates/DownloadClientCommand.ts +++ b/packages/server/src/components/commands/commands/updates/DownloadClientCommand.ts @@ -1,17 +1,17 @@ import { + ClientsManager, CommandsManager, ConfigManager, FabricManager, + ForgeManager, LangManager, MirrorManager, MojangManager, + NeoForgeManager, ProfilesManager, - ClientsManager, QuiltManager, - ForgeManager, - NeoForgeManager, } from "@root/components"; -import { Watcher } from "@root/components/watcher/Watcher" +import { Watcher } from "@root/components/watcher/Watcher"; import { AbstractCommand, Category, LogHelper } from "@root/utils"; import { Service } from "typedi"; diff --git a/packages/server/src/components/config/utils/ApiConfig.ts b/packages/server/src/components/config/utils/ApiConfig.ts index c6485ab7..f9a96705 100644 --- a/packages/server/src/components/config/utils/ApiConfig.ts +++ b/packages/server/src/components/config/utils/ApiConfig.ts @@ -8,9 +8,6 @@ export class ApiConfig { }; disableListing: boolean; hideListing: boolean; - injector: { - skinDomains: string[]; - }; static getDefaultConfig(): ApiConfig { return { @@ -23,9 +20,6 @@ export class ApiConfig { }, disableListing: false, hideListing: false, - injector: { - skinDomains: [], - }, }; } } diff --git a/packages/server/src/components/config/utils/LauncherServerConfig.ts b/packages/server/src/components/config/utils/LauncherServerConfig.ts index 4a223f3d..6837dc15 100644 --- a/packages/server/src/components/config/utils/LauncherServerConfig.ts +++ b/packages/server/src/components/config/utils/LauncherServerConfig.ts @@ -6,6 +6,7 @@ import { HjsonCommented, HjsonHelper } from "@root/utils"; import { instanceToPlain, plainToInstance } from "class-transformer"; import { ApiConfig } from "./ApiConfig"; +import { SkinConfig } from "./SkinConfig"; export class LauncherServerConfig extends HjsonCommented { configVersion: number; @@ -16,6 +17,7 @@ export class LauncherServerConfig extends HjsonCommented { env: Environment; mirrors: string[]; auth: AuthProviderConfig; + skin: SkinConfig; api: ApiConfig; static getDefaults(): LauncherServerConfig { @@ -28,6 +30,7 @@ export class LauncherServerConfig extends HjsonCommented { config.env = Environment.DEV; config.mirrors = []; config.auth = AuthProviderConfig.getDefaultConfig(); + config.skin = SkinConfig.getDefaultConfig(); config.api = ApiConfig.getDefaultConfig(); return config; } diff --git a/packages/server/src/components/config/utils/SkinConfig.ts b/packages/server/src/components/config/utils/SkinConfig.ts new file mode 100644 index 00000000..7adba815 --- /dev/null +++ b/packages/server/src/components/config/utils/SkinConfig.ts @@ -0,0 +1,11 @@ +export class SkinConfig { + skinUrl: string; + capeUrl: string; + + static getDefaultConfig(): SkinConfig { + return { + skinUrl: "https://skins.danielraybone.com/v1/skin/{username}", + capeUrl: "https://skins.danielraybone.com/v1/cape/{username}", + }; + } +} diff --git a/packages/server/src/components/download/DownloadManagers/Mirror.ts b/packages/server/src/components/download/DownloadManagers/Mirror.ts index 33ac529a..61426467 100644 --- a/packages/server/src/components/download/DownloadManagers/Mirror.ts +++ b/packages/server/src/components/download/DownloadManagers/Mirror.ts @@ -2,11 +2,11 @@ import { resolve } from "path"; import { URL } from "url"; import { HttpHelper, ZipHelper } from "@aurora-launcher/core"; +import { Profile } from "@aurora-launcher/core"; import { LogHelper, ProgressHelper, StorageHelper } from "@root/utils"; import { Service } from "typedi"; import { MojangManager } from "./Mojang"; -import { Profile } from "@aurora-launcher/core"; @Service() export class MirrorManager extends MojangManager { @@ -17,20 +17,23 @@ export class MirrorManager extends MojangManager { */ async downloadClient(fileName: string, clientName: string) { const mirror = await this.checkMirror(fileName); - if (!mirror) return LogHelper.error( - this.langManager.getTranslate.DownloadManager.MirrorManager.client.notFound, + if (!mirror) + return LogHelper.error( + this.langManager.getTranslate.DownloadManager.MirrorManager.client.notFound, + ); + const mirrorProfiles: Profile = await HttpHelper.getResourceFromJson( + new URL(`/profiles/${fileName}.json`, mirror), ); - const mirrorProfiles: Profile = await HttpHelper.getResourceFromJson(new URL(`/profiles/${fileName}.json`, mirror)); - + const profileUUID = await super.downloadClient(mirrorProfiles.version, clientName); if (!profileUUID) return; if (await HttpHelper.existsResource(new URL(`/clients/${fileName}.zip`, mirror))) { - await this.installClient(fileName, clientName, mirror) + await this.installClient(fileName, clientName, mirror); } if (await HttpHelper.existsResource(new URL(`/libraries/${fileName}.zip`, mirror))) { - await this.installLibraries(fileName, mirror) + await this.installLibraries(fileName, mirror); } this.profilesManager.editProfile(profileUUID, () => ({ @@ -49,7 +52,7 @@ export class MirrorManager extends MojangManager { return await HttpHelper.existsResource(new URL(`/profiles/${fileName}.json`, url)); }); - return mirror + return mirror; } async installClient(fileName: string, clientName: string, mirror: string) { @@ -58,16 +61,24 @@ export class MirrorManager extends MojangManager { progressBar.start(0, 0, { filename: `${fileName}.zip` }); const clientDirPath = resolve(StorageHelper.clientsDir, clientName); - try{ - const client = await HttpHelper.downloadFile(new URL(`/clients/${fileName}.zip`, mirror), null, { - saveToTempFile: true, - onProgress(progress) { - progress.total && progressBar.setTotal(progress.total); - progressBar.update(progress.transferred); + try { + const client = await HttpHelper.downloadFile( + new URL(`/clients/${fileName}.zip`, mirror), + null, + { + saveToTempFile: true, + onProgress(progress) { + if (progress.total) { + progressBar.setTotal(progress.total); + } + progressBar.update(progress.transferred); + }, }, - }) + ); - LogHelper.info(this.langManager.getTranslate.DownloadManager.MirrorManager.client.unpacking); + LogHelper.info( + this.langManager.getTranslate.DownloadManager.MirrorManager.client.unpacking, + ); ZipHelper.unzip(client, clientDirPath); return true; @@ -83,20 +94,30 @@ export class MirrorManager extends MojangManager { } async installLibraries(fileName: string, mirror: string) { - LogHelper.info(this.langManager.getTranslate.DownloadManager.MirrorManager.client.downloadLib); + LogHelper.info( + this.langManager.getTranslate.DownloadManager.MirrorManager.client.downloadLib, + ); const progressBar = ProgressHelper.getDownloadProgressBar(); progressBar.start(0, 0, { filename: `${fileName}.zip` }); - try{ - const client = await HttpHelper.downloadFile(new URL(`/libraries/${fileName}.zip`, mirror), null, { - saveToTempFile: true, - onProgress(progress) { - progress.total && progressBar.setTotal(progress.total); - progressBar.update(progress.transferred); + try { + const client = await HttpHelper.downloadFile( + new URL(`/libraries/${fileName}.zip`, mirror), + null, + { + saveToTempFile: true, + onProgress(progress) { + if (progress.total) { + progressBar.setTotal(progress.total); + } + progressBar.update(progress.transferred); + }, }, - }) + ); - LogHelper.info(this.langManager.getTranslate.DownloadManager.MirrorManager.client.unpackingLib); + LogHelper.info( + this.langManager.getTranslate.DownloadManager.MirrorManager.client.unpackingLib, + ); ZipHelper.unzip(client, StorageHelper.librariesDir); return true; @@ -111,16 +132,18 @@ export class MirrorManager extends MojangManager { } } - async findAsync(array: string[], predicate: (item: string, index: number, items: string[]) => Promise) { + async findAsync( + array: string[], + predicate: (item: string, index: number, items: string[]) => Promise, + ) { for (const [index, item] of array.entries()) { try { - if (await predicate(item, index, array)) { - return item - } + if (await predicate(item, index, array)) { + return item; + } } catch { - return undefined + return undefined; } } } - } diff --git a/packages/server/src/components/download/DownloadManagers/Mojang.ts b/packages/server/src/components/download/DownloadManagers/Mojang.ts index 49a8e16d..eb920f9f 100644 --- a/packages/server/src/components/download/DownloadManagers/Mojang.ts +++ b/packages/server/src/components/download/DownloadManagers/Mojang.ts @@ -64,7 +64,7 @@ export class MojangManager extends AbstractDownloadManager { try { await mkdir(clientDirPath); - } catch (err) { + } catch { return LogHelper.error(this.langManager.getTranslate.DownloadManager.dirExist); } @@ -137,7 +137,7 @@ export class MojangManager extends AbstractDownloadManager { // this.langManager.getTranslate.DownloadManager.MojangManager // .assets.downloadErr // ); - LogHelper.info( + LogHelper.error( this.langManager.getTranslate.DownloadManager.MojangManager.client .downloadAssetsErr, ); @@ -192,7 +192,7 @@ export class MojangManager extends AbstractDownloadManager { }, ); } catch (error) { - LogHelper.info( + LogHelper.error( this.langManager.getTranslate.DownloadManager.MojangManager.client.downloadLibErr, ); LogHelper.debug(error); diff --git a/packages/server/src/components/index.ts b/packages/server/src/components/index.ts index dacd9e68..26af1bc2 100644 --- a/packages/server/src/components/index.ts +++ b/packages/server/src/components/index.ts @@ -12,3 +12,4 @@ export * from "./update"; export * from "./secure"; export * from "./args"; export * from "./watcher"; +export * from "./skin"; diff --git a/packages/server/src/components/secure/VerifyManager.ts b/packages/server/src/components/secure/VerifyManager.ts index 57dc6846..25e381ce 100644 --- a/packages/server/src/components/secure/VerifyManager.ts +++ b/packages/server/src/components/secure/VerifyManager.ts @@ -14,7 +14,7 @@ export class VerifyManager { constructor() { try { this.readAndSetKey(); - } catch (error) { + } catch { this.generateKeys(); this.readAndSetKey(); } diff --git a/packages/server/src/components/skin/SkinManager.ts b/packages/server/src/components/skin/SkinManager.ts new file mode 100644 index 00000000..32d28608 --- /dev/null +++ b/packages/server/src/components/skin/SkinManager.ts @@ -0,0 +1,23 @@ +import { SkinConfig } from "../config/utils/SkinConfig"; + +export class SkinManager { + private skinUrl: string; + private capeUrl: string; + + constructor(skin: SkinConfig) { + this.skinUrl = skin.skinUrl; + this.capeUrl = skin.capeUrl; + } + + getSkin(uuid: string, username: string): string { + return this.skinUrl.replace("{uuid}", uuid).replace("{username}", username); + } + + getCape(uuid: string, username: string) { + return this.capeUrl.replace("{uuid}", uuid).replace("{username}", username); + } + + getDomainUrl() { + return new URL(this.skinUrl).hostname; + } +} diff --git a/packages/server/src/components/skin/index.ts b/packages/server/src/components/skin/index.ts new file mode 100644 index 00000000..fb4505b2 --- /dev/null +++ b/packages/server/src/components/skin/index.ts @@ -0,0 +1 @@ +export * from "./SkinManager"; \ No newline at end of file diff --git a/packages/server/src/components/watcher/WatchService.ts b/packages/server/src/components/watcher/WatchService.ts new file mode 100644 index 00000000..57a5ca56 --- /dev/null +++ b/packages/server/src/components/watcher/WatchService.ts @@ -0,0 +1,22 @@ +import { LogHelper } from "@root/utils"; +import { FSWatcher, watch } from "chokidar"; + +export class WatchService { + #watcherInstance: FSWatcher; + #timer: NodeJS.Timeout; + + subscribe(dir: string, cwd: string, reload: (path: string) => void) { + this.#watcherInstance = watch(dir, { ignoreInitial: true, cwd }).on( + "all", + (event, path) => { + if (this.#timer) clearTimeout(this.#timer); + this.#timer = setTimeout(() => reload(path), 3000); + LogHelper.debug(event, path); + }, + ); + } + + async unsubscribe() { + await this.#watcherInstance.close(); + } +} diff --git a/packages/server/src/components/watcher/Watcher.ts b/packages/server/src/components/watcher/Watcher.ts index 6044f2ba..e7841011 100644 --- a/packages/server/src/components/watcher/Watcher.ts +++ b/packages/server/src/components/watcher/Watcher.ts @@ -1,44 +1,40 @@ import { sep } from "path"; + +import { StorageHelper } from "@root/utils"; import { Service } from "typedi"; -import { FSWatcher, watch } from 'chokidar'; -import { LogHelper, StorageHelper } from "@root/utils"; -import { ProfilesManager } from "../profiles/ProfilesManager"; + import { ClientsManager } from "../clients/ClientsManager"; +import { ProfilesManager } from "../profiles/ProfilesManager"; +import { WatchService } from "./WatchService"; @Service() export class Watcher { - #prcess1:FSWatcher - #prcess2:FSWatcher + #clientsWatcher = new WatchService(); + #profilesWatcher = new WatchService(); constructor( - private readonly profilesManager:ProfilesManager, - private readonly clientsManager:ClientsManager + private readonly profilesManager: ProfilesManager, + private readonly clientsManager: ClientsManager, ) { this.subscription(); } - async subscription() { - - this.#prcess1 = watch(StorageHelper.clientsDir, {ignoreInitial: true, cwd: StorageHelper.clientsDir}) - .on('all', (event, path) => this.reloadClient(event, path)); - - this.#prcess2 = watch(StorageHelper.profilesDir, {ignoreInitial: true, cwd: '.'}) - .on('all', (event, path) => this.reloadProfile(event, path)); + subscription() { + this.#clientsWatcher.subscribe( + StorageHelper.clientsDir, + StorageHelper.clientsDir, + (path) => { + const dir = path.split(sep); + this.clientsManager.hashClients(dir[0]); + }, + ); + this.#profilesWatcher.subscribe(StorageHelper.profilesDir, ".", () => + this.profilesManager.reloadProfiles(), + ); } async closeWatcher() { - await this.#prcess1.close() - await this.#prcess2.close() - } - - private reloadClient(event:string, path:string) { - LogHelper.debug(event, path); - const dir = path.split(sep); - this.clientsManager.hashClients(dir[0]); - } - - private reloadProfile(event:string, path:string) { - LogHelper.debug(event, path); - this.profilesManager.reloadProfiles(); + await this.#clientsWatcher.unsubscribe(); + await this.#profilesWatcher.unsubscribe(); } -} \ No newline at end of file +} diff --git a/packages/server/src/utils/helpers/HjsonHelper.ts b/packages/server/src/utils/helpers/HjsonHelper.ts index e5270eda..56d921d0 100644 --- a/packages/server/src/utils/helpers/HjsonHelper.ts +++ b/packages/server/src/utils/helpers/HjsonHelper.ts @@ -1,6 +1,6 @@ import { parse, stringify } from "hjson"; -// eslint-disable-next-line @typescript-eslint/no-explicit-any + export type HjsonData = Record | any[]; /** diff --git a/packages/server/src/utils/helpers/LogHelper.ts b/packages/server/src/utils/helpers/LogHelper.ts index eb2a688e..ea0fde6c 100644 --- a/packages/server/src/utils/helpers/LogHelper.ts +++ b/packages/server/src/utils/helpers/LogHelper.ts @@ -19,18 +19,25 @@ const LOG_LEVELS = { }; export class LogHelper { - private static readonly isDevEnabled: boolean = process.argv.includes("--dev") || process.env.AURORA_IS_DEV === "true"; + private static readonly isDevEnabled: boolean = + process.argv.includes("--dev") || process.env.AURORA_IS_DEV === "true"; private static readonly isDebugEnabled: boolean = - process.argv.includes("--debug") || process.env.AURORA_IS_DEBUG === "true" || this.isDevEnabled; + process.argv.includes("--debug") || + process.env.AURORA_IS_DEBUG === "true" || + this.isDevEnabled; - private static getLogFilePath(): string { - const dateStr = new Date() - .toISOString() - .slice(0, 19) - .replace(/[-:]/g, ".") - .replace("T", "-"); + static getFormatedDate() { + const date = new Date(); + const numFmt = (num: number) => (num < 10 ? `0${num}` : num); + + return `${numFmt(date.getFullYear())}-${numFmt(date.getMonth() + 1)}-${numFmt(date.getDate())} ${numFmt(date.getHours())}:${numFmt(date.getMinutes())}:${numFmt(date.getSeconds())}`; + } - return resolve(StorageHelper.logsDir, `LauncherServer-${dateStr}.log`); + private static getLogFilePath(): string { + return resolve( + StorageHelper.logsDir, + `LauncherServer_${this.getFormatedDate().replace(" ", "_").replace(/:/g, "-")}.log`, + ); } private static readonly logFileStream = createWriteStream(LogHelper.getLogFilePath(), { @@ -70,7 +77,7 @@ export class LogHelper { private static log(level: keyof typeof LOG_LEVELS, msg: any, ...args: any[]) { const coloredStr = [ - chalk.gray(new Date().toLocaleString()), + chalk.gray(this.getFormatedDate()), LOG_LEVELS[level](` [${level}] `), msg, ].join(""); @@ -99,8 +106,8 @@ export class LogHelper { chalk.blue("AuroraTeam (https://github.com/AuroraTeam)") + chalk.green("\nLicensed under the MIT License") + chalk.green("\nDocumentation page: ") + - chalk.blue("https://docs.aurora-launcher.ru/") - ) + chalk.blue("https://docs.aurora-launcher.ru/"), + ), ); } }