package com.battery.device.bts;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 新威 BTS 对外接口的**只读命令白名单**(ADR-0068 §1)。
*
*
启用厂商对外接口等于同时打开了控制通道:厂商协议里 {@code start}/{@code stop}/{@code reset}/
* {@code broadcaststop} 与只读命令走同一条管道、同一套报文格式,服务端不做区分。
* 因此"只观测不控制"这条不变量在新威这条路上**不是服务端保证,而是代码纪律**,
* 落点就是这里:每条出站请求在发出前按 {@code } 取值比对白名单,不在白名单内的一律拒绝。
*
* 为什么拦在传输层而不是各调用处:调用处会随需求增加,白名单只有一处才可能被审计。
* 独立成类而不写在传输类里,是为了让这条边界能被单独测到(不需要真的有一条管道)。
*/
final class NewareBtsReadOnlyCommands
{
/** 允许发送的命令,全部是只读命令;取值来自《BTS API技术协议》与现场实测(ADR-0068)。 */
private static final Set ALLOWED = Set.of(
"getdevinfo", "getchlstatus", "inquire", "inquiredf", "download",
"downloadsteplayer", "downloadlog", "getparallel", "getpause");
private static final Pattern COMMAND = Pattern.compile("\\s*([A-Za-z_][A-Za-z0-9_]*)\\s*");
private NewareBtsReadOnlyCommands()
{
}
/**
* 校验请求只含白名单内的命令,返回解析出的命令名(小写)。
*
* 没有 {@code } 的报文不是本协议的请求,同样拒绝——放行一个解析不出命令的报文,
* 等于把"这道门"的判定权交给厂商服务端。
*
* @param request 完整请求报文
* @return 请求里的命令名(小写)
* @throws BtsTransportException 缺少命令,或命令不在只读白名单内
*/
static String requireAllowed(String request)
{
Matcher matcher = request == null ? null : COMMAND.matcher(request);
if (matcher == null || !matcher.find())
throw new BtsTransportException(BtsTransportException.Reason.READ_ONLY_REJECTED,
"BTS 请求缺少 ,拒绝发出", null);
String command = matcher.group(1).toLowerCase(Locale.ROOT);
if (!ALLOWED.contains(command))
throw new BtsTransportException(BtsTransportException.Reason.READ_ONLY_REJECTED,
"BTS 只读白名单外的命令被拒绝:" + command, null);
return command;
}
}