mirror of
https://github.com/discountry/ritmex-bot.git
synced 2026-09-09 08:18:07 +00:00
添加版权校验功能,增强应用安全性,确保版本完整性和防篡改能力。
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import crypto from "crypto";
|
||||
import type { TradingConfig } from "../config";
|
||||
import type { ExchangeAdapter } from "../exchanges/adapter";
|
||||
import type {
|
||||
@@ -27,6 +28,7 @@ import type { OrderLockMap, OrderPendingMap, OrderTimerMap } from "./order-coord
|
||||
import { isUnknownOrderError } from "../utils/errors";
|
||||
import { roundDownToTick } from "../utils/math";
|
||||
import { createTradeLog, type TradeLogEntry } from "../state/trade-log";
|
||||
import { decryptCopyright } from "../utils/copyright";
|
||||
|
||||
export interface TrendEngineSnapshot {
|
||||
ready: boolean;
|
||||
@@ -91,6 +93,10 @@ export class TrendEngine {
|
||||
private ordersSnapshotReady = false;
|
||||
private startupLogged = false;
|
||||
private entryPricePendingLogged = false;
|
||||
private readonly copyrightFingerprint = crypto
|
||||
.createHash("sha256")
|
||||
.update(decryptCopyright())
|
||||
.digest("hex");
|
||||
|
||||
private readonly listeners = new Map<TrendEngineEvent, Set<TrendEngineListener>>();
|
||||
|
||||
|
||||
+11
-1
@@ -1,8 +1,9 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { Box, Text, useInput } from "ink";
|
||||
import { TrendApp } from "./TrendApp";
|
||||
import { MakerApp } from "./MakerApp";
|
||||
import { OffsetMakerApp } from "./OffsetMakerApp";
|
||||
import { loadCopyrightFragments, verifyCopyrightIntegrity } from "../utils/copyright";
|
||||
|
||||
interface StrategyOption {
|
||||
id: "trend" | "maker" | "offset-maker";
|
||||
@@ -37,6 +38,8 @@ const inputSupported = Boolean(process.stdin && (process.stdin as any).isTTY);
|
||||
export function App() {
|
||||
const [cursor, setCursor] = useState(0);
|
||||
const [selected, setSelected] = useState<StrategyOption | null>(null);
|
||||
const copyright = useMemo(() => loadCopyrightFragments(), []);
|
||||
const integrityOk = useMemo(() => verifyCopyrightIntegrity(), []);
|
||||
|
||||
useInput(
|
||||
(input, key) => {
|
||||
@@ -62,6 +65,13 @@ export function App() {
|
||||
|
||||
return (
|
||||
<Box flexDirection="column" paddingX={1} paddingY={1}>
|
||||
<Text color="gray">{copyright.bannerText}</Text>
|
||||
{integrityOk ? null : (
|
||||
<Text color="red">警告: 版权校验失败,当前版本可能被篡改。</Text>
|
||||
)}
|
||||
<Box height={1}>
|
||||
<Text color="gray">────────────────────────────────────────────────────</Text>
|
||||
</Box>
|
||||
<Text color="cyanBright">请选择要运行的策略</Text>
|
||||
<Text color="gray">使用 ↑/↓ 选择,回车开始,Ctrl+C 退出。</Text>
|
||||
<Box flexDirection="column" marginTop={1}>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import crypto from "crypto";
|
||||
|
||||
const ENCRYPTED_COPYRIGHT = "gbbx3pZWTqgMmLcH3fM0qefo6q4eHR0weNjfLcWY5oPhfwH9DaDEWAvhItfzGbBJzJ6UuVPOb1vqMAL0qpPdw+q0bf13Tz8ewMR3cSHyH8R59KfasAo=";
|
||||
const PRIMARY_HASH = "a637d95de2b7d13af96b7c0deb286a439b1b07408577ae97c93e6fdbaa6526bf";
|
||||
const SECONDARY_HASH = "2e9c48cef9b6c3af45313946e3d766b3d8b9a3a12df6906abe90ebeca694fec8";
|
||||
const LEGACY_SHAS = [
|
||||
PRIMARY_HASH,
|
||||
"65d686f80a5360a4f16cf2dbce962f2dd32e88bdee6fa7b8929f8a854ea12de9",
|
||||
"e3d59bfd872fc54d3c814edb200ef9d4916bea86e3f7de925f2b4d5efbc1ec49",
|
||||
"27f5777af8faec4ce80bd3cfe6302c7d66be138de25e941544b9b2895207b70e",
|
||||
];
|
||||
|
||||
const PASSPHRASE = "RitMEX#copyright#guard#2025";
|
||||
|
||||
const iv = Buffer.from(ENCRYPTED_COPYRIGHT, "base64").subarray(0, 12);
|
||||
const authTag = Buffer.from(ENCRYPTED_COPYRIGHT, "base64").subarray(12, 28);
|
||||
const ciphertext = Buffer.from(ENCRYPTED_COPYRIGHT, "base64").subarray(28);
|
||||
|
||||
function deriveKey(seed: string) {
|
||||
return crypto.createHash("sha256").update(seed).digest();
|
||||
}
|
||||
|
||||
export function decryptCopyright(): string {
|
||||
const key = deriveKey(PASSPHRASE);
|
||||
const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
|
||||
decipher.setAuthTag(authTag);
|
||||
return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
|
||||
}
|
||||
|
||||
export function verifyCopyrightIntegrity(): boolean {
|
||||
const plaintext = decryptCopyright();
|
||||
const primary = crypto.createHash("sha256").update(plaintext).digest("hex");
|
||||
const chained = crypto.createHash("sha256").update(primary).digest("hex");
|
||||
return (
|
||||
primary === PRIMARY_HASH &&
|
||||
chained === SECONDARY_HASH &&
|
||||
LEGACY_SHAS.some((hash) => {
|
||||
try {
|
||||
return crypto.timingSafeEqual(Buffer.from(hash, "hex"), Buffer.from(primary, "hex"));
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export function loadCopyrightFragments() {
|
||||
const bannerText = decryptCopyright();
|
||||
return {
|
||||
bannerText,
|
||||
primaryHash: PRIMARY_HASH,
|
||||
secondaryHash: SECONDARY_HASH,
|
||||
integrityOk: verifyCopyrightIntegrity(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import crypto from "crypto";
|
||||
|
||||
const MIRROR_HASHES = [
|
||||
"a637d95de2b7d13af96b7c0deb286a439b1b07408577ae97c93e6fdbaa6526bf",
|
||||
"2e9c48cef9b6c3af45313946e3d766b3d8b9a3a12df6906abe90ebeca694fec8",
|
||||
"57919d55779fbcba1fdd6dfea07e9a6a567c0e9000ab63f25df4e998f3e84b8e",
|
||||
"27f5777af8faec4ce80bd3cfe6302c7d66be138de25e941544b9b2895207b70e",
|
||||
];
|
||||
|
||||
export function checkIntegrity(payload: string) {
|
||||
const digest = crypto.createHash("sha256").update(payload, "utf8").digest("hex");
|
||||
return MIRROR_HASHES.some((hash) => {
|
||||
try {
|
||||
return crypto.timingSafeEqual(Buffer.from(hash, "hex"), Buffer.from(digest, "hex"));
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user