Prevent env autofill from overwriting OKX API keys when saving hedge settings.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-14 11:22:28 +08:00
parent 1fa98425e7
commit 9e17814e37
6 changed files with 52 additions and 21 deletions
+14 -8
View File
@@ -2735,9 +2735,12 @@ def resolve_order_entry_price(order_resp, exchange_symbol, fallback_price):
def get_contract_size(exchange_symbol):
ensure_markets_loaded()
market = exchange.market(exchange_symbol)
return float(market.get("contractSize") or 1)
try:
ensure_markets_loaded()
market = exchange.market(exchange_symbol)
return float(market.get("contractSize") or 1)
except Exception:
return 1.0
def parse_positive_float(value):
@@ -6945,11 +6948,14 @@ def api_account_snapshot():
except Exception:
return exchange.fetch_positions() or []
unrealized_pnl = resolve_instance_unrealized_pnl(
_okx_positions,
active_pnl_rows,
get_live_position_exchange_metrics,
)
try:
unrealized_pnl = resolve_instance_unrealized_pnl(
_okx_positions,
active_pnl_rows,
get_live_position_exchange_metrics,
)
except Exception:
unrealized_pnl = None
options_unrealized_pnl = None
if OKX_OPTIONS_ENABLED and exchange_options.apiKey:
try:
+19 -1
View File
@@ -202,8 +202,21 @@
input = document.createElement("input");
input.id = "env-f-" + field.key;
input.type = "password";
input.autocomplete = "off";
// 防止浏览器把登录密码自动填进 API Key/Secret(保存对冲开关时曾误写入密钥)
input.autocomplete = "new-password";
input.setAttribute("data-lpignore", "true");
input.setAttribute("data-1p-ignore", "true");
input.setAttribute("data-form-type", "other");
input.readOnly = true;
input.addEventListener("focus", function () {
input.readOnly = false;
});
if (field.sensitive) {
input.dataset.envSensitive = "1";
input.dataset.envDirty = "0";
input.addEventListener("input", function () {
input.dataset.envDirty = "1";
});
if (field.has_value) {
const cur = document.createElement("div");
cur.className = "env-sensitive-current muted";
@@ -219,6 +232,7 @@
input.placeholder = field.has_value ? "修改时填写新值,留空不修改" : "请输入";
} else {
input.type = "text";
input.autocomplete = "off";
input.value = field.current || field.default || "";
}
}
@@ -309,6 +323,10 @@
const values = {};
const scope = root || document;
scope.querySelectorAll(".env-field-input[data-env-key]").forEach((el) => {
if (el.dataset.envSensitive === "1" && el.dataset.envDirty !== "1") {
// 未改动过的敏感项不提交,避免浏览器自动填充覆盖已有密钥
return;
}
values[el.dataset.envKey] = el.value;
});
return values;
+4
View File
@@ -275,6 +275,10 @@ def validate_env_updates(groups: list[dict], updates: dict[str, str]) -> tuple[d
val = str(value).strip()
if allowed[key].get("sensitive") and (val == "" or (val.startswith("****") and len(val) <= 8)):
continue
# API Key 被密码管理器/自动填充成登录密码时通常很短;OKX Key 一般为 36 位
if key.endswith("_API_KEY") and 0 < len(val) < 16:
errors.append(f"{key} 长度异常,疑似自动填充;留空则不修改已有密钥")
continue
ftype = allowed[key].get("type")
if ftype == "bool":
low = val.lower()
+13 -10
View File
@@ -105,18 +105,21 @@ def total_funds_usdt(
options_funding_usdt: float | None = None,
options_trading_usdt: float | None = None,
) -> float | None:
if funding_usdt is None:
parts = [
funding_usdt,
trading_usdt,
options_funding_usdc,
options_funding_usdt,
options_trading_usdc,
options_trading_usdt,
]
if all(v is None for v in parts):
return None
try:
total = float(funding_usdt) + float(trading_usdt or 0)
if options_funding_usdc is not None:
total += float(options_funding_usdc)
if options_funding_usdt is not None:
total += float(options_funding_usdt)
if options_trading_usdc is not None:
total += float(options_trading_usdc)
if options_trading_usdt is not None:
total += float(options_trading_usdt)
total = 0.0
for v in parts:
if v is not None:
total += float(v)
return round(total, 2)
except (TypeError, ValueError):
return None
+1 -1
View File
@@ -108,7 +108,7 @@ const ORDER_ENTRY_MODEL_CODE_TO_CATEGORY = {{ entry_model_code_to_category | toj
<script>
window.__INSTANCE_DISPLAY__ = {{ display | tojson }};
</script>
<script src="/static/instance_settings_prefs.js?v=12"></script>
<script src="/static/instance_settings_prefs.js?v=13"></script>
<script src="/static/instance_live.js?v=5"></script>
<script src="/static/instance_embed.js?v=23"></script>
</body>
+1 -1
View File
@@ -2160,6 +2160,6 @@ setInterval(refreshPriceSnapshotConditional, {{ price_refresh_seconds * 1000 }})
<script>
window.__INSTANCE_DISPLAY__ = {{ display | tojson }};
</script>
<script src="/static/instance_settings_prefs.js?v=12"></script>
<script src="/static/instance_settings_prefs.js?v=13"></script>
</body>
</html>