| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- import { sys } from 'cc';
- import { ANDROID, IOS } from 'cc/env';
- const STORAGE_ENCRYPTION_HEAD = 'a6072637';
- const STORAGE_ENCRYPTION_PASSWORD = 'xbd4jl';
- const STORAGE_ENCRYPTION_ENABLED = true;
- /**
- * 读取本地数据,并兼容 game_web_us2 写入的加密格式。
- */
- export function localStorageGet<T = string>(key: string, defaultValue: T = '' as T): string | T {
- let value = sys.localStorage.getItem(key);
- if (value === null) return defaultValue;
- if (value.startsWith(STORAGE_ENCRYPTION_HEAD)) {
- try {
- value = decrypt(value.substring(STORAGE_ENCRYPTION_HEAD.length));
- } catch {
- // 与原项目保持一致:解密失败时返回空字符串。
- value = '';
- }
- }
- return value;
- }
- /**
- * 加密并保存本地数据。空字符串不加密,行为与 game_web_us2 保持一致。
- */
- export function localStorageSet(key: string, value: unknown): void {
- let storageValue = value;
- if (STORAGE_ENCRYPTION_ENABLED && storageValue !== null && storageValue !== '') {
- const plainValue = typeof storageValue === 'string' ? storageValue : String(storageValue);
- storageValue = plainValue;
- try {
- storageValue = STORAGE_ENCRYPTION_HEAD + encrypt(plainValue);
- } catch {
- // 加密失败时沿用原值保存,兼容原项目行为。
- }
- }
- sys.localStorage.setItem(key, String(storageValue));
- }
- export function localStorageRemove(key: string): void {
- sys.localStorage.removeItem(key);
- }
- function encrypt(value: string, password = STORAGE_ENCRYPTION_PASSWORD): string {
- if (value === '') return '';
- const source = encodeURIComponent(value);
- const encodedPassword = encodeURIComponent(password || STORAGE_ENCRYPTION_PASSWORD);
- if (encodedPassword.length === 0) return '';
- let randomSeed = '';
- for (let index = 0; index < encodedPassword.length; index += 1) {
- randomSeed += encodedPassword.charCodeAt(index).toString();
- }
- const seedPosition = Math.floor(randomSeed.length / 5);
- const multiplier = Number.parseInt(
- randomSeed.charAt(seedPosition)
- + randomSeed.charAt(seedPosition * 2)
- + randomSeed.charAt(seedPosition * 3)
- + randomSeed.charAt(seedPosition * 4)
- + randomSeed.charAt(seedPosition * 5),
- 10,
- );
- const increment = Math.ceil(encodedPassword.length / 2);
- const modulus = Math.pow(2, 31) - 1;
- if (multiplier < 2) return '';
- let salt = Math.round(Math.random() * 1_000_000_000) % 100_000_000;
- randomSeed += salt;
- randomSeed = reduceSeed(randomSeed);
- let pseudoRandom = (multiplier * Number(randomSeed) + increment) % modulus;
- let encrypted = '';
- for (let index = 0; index < source.length; index += 1) {
- const encryptedChar = source.charCodeAt(index) ^ Math.floor((pseudoRandom / modulus) * 255);
- encrypted += encryptedChar < 16
- ? `0${encryptedChar.toString(16)}`
- : encryptedChar.toString(16);
- pseudoRandom = (multiplier * pseudoRandom + increment) % modulus;
- }
- let saltHex = salt.toString(16);
- while (saltHex.length < 8) saltHex = `0${saltHex}`;
- return encrypted + saltHex;
- }
- function decrypt(value: string, password = STORAGE_ENCRYPTION_PASSWORD): string {
- if (value === '') return '';
- const encodedPassword = encodeURIComponent(password || STORAGE_ENCRYPTION_PASSWORD);
- if (value.length < 8 || encodedPassword.length === 0) return '';
- let randomSeed = '';
- for (let index = 0; index < encodedPassword.length; index += 1) {
- randomSeed += encodedPassword.charCodeAt(index).toString();
- }
- const seedPosition = Math.floor(randomSeed.length / 5);
- const multiplier = Number.parseInt(
- randomSeed.charAt(seedPosition)
- + randomSeed.charAt(seedPosition * 2)
- + randomSeed.charAt(seedPosition * 3)
- + randomSeed.charAt(seedPosition * 4)
- + randomSeed.charAt(seedPosition * 5),
- 10,
- );
- const increment = Math.round(encodedPassword.length / 2);
- const modulus = Math.pow(2, 31) - 1;
- const salt = Number.parseInt(value.substring(value.length - 8), 16);
- const encrypted = value.substring(0, value.length - 8);
- randomSeed += salt;
- randomSeed = reduceSeed(randomSeed);
- let pseudoRandom = (multiplier * Number(randomSeed) + increment) % modulus;
- let decrypted = '';
- for (let index = 0; index < encrypted.length; index += 2) {
- const decryptedChar = Number.parseInt(encrypted.substring(index, index + 2), 16)
- ^ Math.floor((pseudoRandom / modulus) * 255);
- decrypted += String.fromCharCode(decryptedChar);
- pseudoRandom = (multiplier * pseudoRandom + increment) % modulus;
- }
- return decodeURIComponent(decrypted);
- }
- function reduceSeed(seed: string): string {
- let result = seed;
- while (result.length > 10) {
- let remaining = result;
- let total = 0;
- while (remaining.length > 0) {
- total += Number.parseInt(remaining.substring(0, 10), 10);
- remaining = remaining.substring(10);
- }
- result = total.toString();
- }
- return result;
- }
- /**
- * 进入平台判定:0=普通浏览器 1=iOS壳包 2=Android壳包 3=PWA(桌面图标/TWA 进入)
- * 用于按来源差异化展示(如提现页官网引流提示:桌面图标进入的玩家不显示)。
- * 壳包判定优先于 PWA;TWA 判定内联实现,避免 helpers→UAUtils 循环依赖。
- */
- export function getEnterPlatform(): 0 | 1 | 2 | 3 {
- if (ANDROID) return 2;
- if (IOS) return 1;
- return 0;
- }
- export function createUUID() {
- const chars: string[] = [];
- const hexDigits = '0123456789abcdef';
- for (let index = 0; index < 36; index += 1) {
- chars[index] = hexDigits.charAt(
- Math.floor(Math.random() * 16),
- );
- }
- // UUID version 4:0100
- chars[14] = '4';
- // RFC variant:10xx
- const variant = (Number.parseInt(chars[19], 16) & 0x3) | 0x8;
- chars[19] = hexDigits.charAt(variant);
- chars[8] = '-';
- chars[13] = '-';
- chars[18] = '-';
- chars[23] = '-';
- return chars.join('');
- }
- export function getUrlParams(url: string) {
- const queryIndex = url.indexOf('?');
- const params = {};
- if (queryIndex >= 0) {
- url.slice(queryIndex + 1).split('&').forEach((entry) => {
- if (!entry) return;
- const separatorIndex = entry.indexOf('=');
- const rawKey = separatorIndex >= 0 ? entry.slice(0, separatorIndex) : entry;
- const rawValue = separatorIndex >= 0 ? entry.slice(separatorIndex + 1) : '';
- try {
- const key = decodeURIComponent(rawKey.replace(/\+/g, ' '));
- params[key] = decodeURIComponent(rawValue.replace(/\+/g, ' '));
- } catch {
- // Preserve malformed values instead of crashing the native callback.
- params[rawKey] = rawValue;
- }
- });
- }
- return params;
- }
|