中继答 504 并说"可能已经执行了,重试前请先确认"——这句话诚实的前提是它保持为真。 批次是串行处理的,所以满邮箱里第八个信封可以在它被签名之后 8 个上游超时才轮到; 那时手机早已被告知失败、用户可能已经重试。再执行它,就把一次诚实的"未知"变成了 一条重复发出的短信。 现在 agent 在动任何东西之前先比对自己的截止时间(策略里的 requestTtlSeconds), 超龄一律以 expired 拒绝并落审计。判定放在新鲜度检查之后、策略判定之前:它比签名 更便宜,而且一个过期请求无论路径是否在白名单里都不该执行。 为了让这条规则**可达**,策略新增一条断言:TTL 不得大于时钟偏移窗口。否则新鲜度 检查会先触发,这条规则永远不会被执行——而"永不触发的规则"是出事时才会被发现坏了 的那种东西。 单个上游调用的超时也移进了策略(agentUpstreamTimeoutSeconds)。"中继期限必须长于 一次上游调用"这个比较,与二进制里的常量是比不了的;现在两侧从同一个文件读,策略 加载时就能拒绝一组自相矛盾的数值。原来那个 20s 常量保留为默认值的来源,不再硬编码。 测试两项:一个请求在期限内被转发、一个超龄请求被拒且**没有被转发**(计数按路径, 否则首次转发前的 /api/auth/status 探测会让断言以错误的理由通过);另一项断言策略 本身满足上述两个关系。变异验证:关掉判定,第一项失败。 Go 全包、Node 119 项、Swift 101 项通过。
43 lines
1.4 KiB
JSON
43 lines
1.4 KiB
JSON
{
|
|
"schemaVersion": 1,
|
|
"name": "msa-agent-policy",
|
|
"comment": "Authorisation surface for relay-issued commands. Deliberately narrower than the web console proxy policy: this is what the iPhone app can actually ask for, nothing more.",
|
|
"egress": {
|
|
"mode": "loopback-only",
|
|
"portOnly": true,
|
|
"comment": "The agent config carries a port, never a host. Outbound connections are dialed to 127.0.0.1/::1 by the transport itself, so there is no host field to misconfigure and no DNS-rebinding path.",
|
|
"dialedHosts": ["127.0.0.1", "::1"]
|
|
},
|
|
"authPaths": {
|
|
"pattern": "^/api/(?:auth(?:/|$)|login(?:/|$)|logout(?:/|$))",
|
|
"proxied": false,
|
|
"comment": "The agent logs into the local SimAdmin itself and holds the credential. Login material never traverses the relay in either direction."
|
|
},
|
|
"read": [
|
|
"/api/health",
|
|
"/api/device",
|
|
"/api/sim",
|
|
"/api/network",
|
|
"/api/network/signal-strength",
|
|
"/api/stats",
|
|
"/api/stats/cpu",
|
|
"/api/connectivity",
|
|
"/api/sms/list"
|
|
],
|
|
"write": {
|
|
"/api/sms/send": ["POST"],
|
|
"/api/sms/batch-delete": ["POST"]
|
|
},
|
|
"dangerous": ["/api/sms/send", "/api/sms/batch-delete"],
|
|
"limits": {
|
|
"dangerousWritesPerMinute": 6,
|
|
"agentUpstreamTimeoutSeconds": 20,
|
|
"maxRequestBytes": 262144,
|
|
"maxResponseBytes": 262144,
|
|
"requestTtlSeconds": 30,
|
|
"clockSkewSeconds": 120,
|
|
"replayCacheSize": 4096,
|
|
"mailboxDepth": 8
|
|
}
|
|
}
|