monitor/core/lib/player/idUtils.ts
2025-04-16 22:30:27 +07:00

160 lines
5.0 KiB
TypeScript

import type { PlayerIdsObjectType } from "@shared/otherTypes";
import consts from "@shared/consts";
/**
* Validates a single identifier and return its parts lowercased
*/
export const parsePlayerId = (idString: string) => {
if (typeof idString !== 'string') {
return { isIdValid: false, idType: null, idValue: null, idlowerCased: null };
}
const idlowerCased = idString.toLocaleLowerCase();
const [idType, idValue] = idlowerCased.split(':', 2);
if (idType === "ip") {
return { isIdValid: false, idType, idValue, idlowerCased };
}
return { isIdValid: true, idType, idValue, idlowerCased };
}
/**
* Get valid, invalid and license identifier from array of ids
*/
export const parsePlayerIds = (ids: string[]) => {
let invalidIdsArray: string[] = [];
let validIdsArray: string[] = [];
const validIdsObject: PlayerIdsObjectType = {}
for (const idString of ids) {
if (typeof idString !== 'string') continue;
const { isIdValid, idType, idValue } = parsePlayerId(idString);
if (isIdValid) {
validIdsArray.push(idString);
validIdsObject[idType as keyof PlayerIdsObjectType] = idValue;
} else {
invalidIdsArray.push(idString);
}
}
return { invalidIdsArray, validIdsArray, validIdsObject };
}
/**
* Get valid and invalid player HWIDs
*/
export const filterPlayerHwids = (hwids: string[]) => {
let invalidHwidsArray: string[] = [];
let validHwidsArray: string[] = [];
for (const hwidString of hwids) {
if (typeof hwidString !== 'string') continue;
if (consts.regexValidHwidToken.test(hwidString)) {
validHwidsArray.push(hwidString);
} else {
invalidHwidsArray.push(hwidString);
}
}
return { invalidHwidsArray, validHwidsArray };
}
/**
* Attempts to parse a user-provided string into an array of valid identifiers.
* This function is lenient and will attempt to parse any string into an array of valid identifiers.
* For non-prefixed ids, it will attempt to parse it as discord, fivem, steam, or license.
* Returns an array of valid ids/hwids, and array of invalid identifiers.
*
* Stricter version of this function is parsePlayerIds
*/
export const parseLaxIdsArrayInput = (fullInput: string) => {
const validIds: string[] = [];
const validHwids: string[] = [];
const invalids: string[] = [];
if (typeof fullInput !== 'string') {
return { validIds, validHwids, invalids };
}
const inputs = fullInput.toLowerCase().split(/[,;\s]+/g).filter(Boolean);
for (const input of inputs) {
if (input.includes(':')) {
if (consts.regexValidHwidToken.test(input)) {
validHwids.push(input);
} else if (Object.values(consts.validIdentifiers).some((regex) => regex.test(input))) {
validIds.push(input);
} else {
const [type, value] = input.split(':', 1);
if (consts.validIdentifierParts[type as keyof typeof consts.validIdentifierParts]?.test(value)) {
validIds.push(input);
} else {
invalids.push(input);
}
}
} else if (consts.validIdentifierParts.discord.test(input)) {
validIds.push(`discord:${input}`);
} else if (consts.validIdentifierParts.fivem.test(input)) {
validIds.push(`fivem:${input}`);
} else if (consts.validIdentifierParts.license.test(input)) {
validIds.push(`license:${input}`);
} else if (consts.validIdentifierParts.steam.test(input)) {
validIds.push(`steam:${input}`);
} else {
invalids.push(input);
}
}
return { validIds, validHwids, invalids };
}
/**
* Extracts the fivem:xxxxxx identifier from the nameid field from the userInfo oauth response.
* Example: https://forum.cfx.re/internal/user/271816 -> fivem:271816
*/
export const getIdFromOauthNameid = (nameid: string) => {
try {
const res = /\/user\/(\d{1,8})/.exec(nameid);
//@ts-expect-error
return `fivem:${res[1]}`;
} catch (error) {
return false;
}
}
/**
* Shortens an ID/HWID string to just leading and trailing 4 characters.
* Unicode symbol alternatives: ‥,…,~,≈,-,•,◇
*/
export const shortenId = (id: string) => {
if (typeof id !== 'string') throw new Error(`id is not a string`);
const [idType, idValue] = id.split(':', 2);
if (!idType || !idValue) {
return id; // Invalid format, return as is
}
if (idValue.length <= 10) {
return id; // Do not shorten if ID value is 10 characters or fewer
}
const start = idValue.slice(0, 4);
const end = idValue.slice(-4);
return `${idType}:${start}${end}`;
}
/**
* Returns a string of shortened IDs/HWIDs
*/
export const summarizeIdsArray = (ids: string[]) => {
if (!Array.isArray(ids)) return '<invalid list>';
if (ids.length === 0) return '<empty list>';
const shortList = ids.map(shortenId).join(', ');
return `[${shortList}]`;
}