Initial commit: 91dj android client dev_1.0.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
//图片解密:前 100 字节与 key 循环异或
|
||||
class ImageCrypto {
|
||||
//jpg/png/gif 文件头,都对不上视为加密图
|
||||
static final List<Uint8List> _featuresList = [
|
||||
Uint8List.fromList([0xff, 0xd8, 0xff]), //jpg,jpeg
|
||||
Uint8List.fromList([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]), //png
|
||||
Uint8List.fromList([0x47, 0x49, 0x46]), //gif
|
||||
];
|
||||
|
||||
static const int _minLen = 6; //最小字节数
|
||||
static const int _encryptedLen = 100; //加密图片的数据长度
|
||||
static final Uint8List _decryptKey = Uint8List.fromList('2019ysapp7527'.codeUnits); //加密key
|
||||
|
||||
static Uint8List? decrypt(Uint8List? imgBytes) {
|
||||
if (imgBytes?.isNotEmpty != true) {
|
||||
return imgBytes;
|
||||
}
|
||||
//不足 6 字节视为坏图,抛给调用方走失败(沿用老逻辑比对 6 字节魔数时越界抛错的行为)
|
||||
if (imgBytes!.length < _minLen) {
|
||||
throw RangeError.range(imgBytes.length, 0, imgBytes.length - 1, 'length');
|
||||
}
|
||||
if (_isEncrypted(imgBytes)) {
|
||||
imgBytes = _xor(imgBytes, _decryptKey, _encryptedLen);
|
||||
}
|
||||
return imgBytes;
|
||||
}
|
||||
|
||||
static bool _isEncrypted(Uint8List imgBytes) {
|
||||
bool isMismatch = false;
|
||||
int featuresLen = _featuresList.length;
|
||||
for (int i = 0; i < featuresLen; i++) {
|
||||
isMismatch = false;
|
||||
for (int j = 0; j < _featuresList[i].length; j++) {
|
||||
if (_featuresList[i][j] != imgBytes[j]) {
|
||||
isMismatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isMismatch) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isMismatch;
|
||||
}
|
||||
|
||||
//前 length 字节与 key 循环异或(原地修改)
|
||||
static Uint8List _xor(Uint8List src, Uint8List key, int length) {
|
||||
int srcLen = src.length;
|
||||
int keyLen = key.length;
|
||||
if (length > srcLen || length <= 0) {
|
||||
length = srcLen;
|
||||
}
|
||||
for (var i = 0; i < length; i += keyLen) {
|
||||
for (var j = 0; j < keyLen && i + j < length; j++) {
|
||||
src[i + j] ^= key[j];
|
||||
}
|
||||
}
|
||||
return src;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
import '../debug_log.dart';
|
||||
|
||||
//图片磁盘缓存目录(2025-07 ~ 2026-06 的版本经 loadAndDecrypt 往里存过原图,当前无写入方,保留统计和清理给老用户兜底)
|
||||
class ImageDiskCache {
|
||||
static Future<String> findSavePath() async {
|
||||
final directory = await getTemporaryDirectory();
|
||||
|
||||
String saveDir = '${directory.path}/cacheImage';
|
||||
Directory root = Directory(saveDir);
|
||||
if (!root.existsSync()) {
|
||||
debugLog(saveDir);
|
||||
await root.create();
|
||||
}
|
||||
return saveDir;
|
||||
}
|
||||
|
||||
static Future<void> emptyCache() async {
|
||||
try {
|
||||
String saveDir = await findSavePath();
|
||||
Directory root = Directory(saveDir);
|
||||
if (root.existsSync()) {
|
||||
await root.delete(recursive: true);
|
||||
}
|
||||
} catch (e) {
|
||||
debugLog(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user