using Fleet.Core;
namespace Fleet.Hosting;
///
/// 节点自己要求有属主(passkey):拨号方和监听方共用这一份,启动时检查。
///
/// 属主是安装命令带来、注册时固定在 trust.json 里的 passkey 凭证 id(必须是操作员集合里的凭证)。节点据此知道自己绑定在哪个 passkey 上,
/// 才敢把更多的接口和操作交给它(extension 会话、加密内容都只认属主的 passkey);没有属主的节点没有人能授权它的敏感能力,所以不运行。
/// 这是节点本地的强制,不依赖面板:面板被攻破也改不了节点已经固定的属主。
///
///
public static class OwnerGuard
{
/// 设为 1 放行没有属主的节点(只给没有信任根的老面板)。
public const string AllowEnvironmentVariable = "MOSHIRO_ALLOW_NO_OWNER";
/// 没问题返回 null;否则是要告诉运维的原因。
public static string? Problem(TrustAnchor trust, bool require)
{
if (!require || Environment.GetEnvironmentVariable(AllowEnvironmentVariable) == "1")
{
return null;
}
if (!trust.Pinned)
{
return "this node has no owner: it was not enrolled with a trust root and owner passkeys; enroll it again with the command from the panel (or set " + AllowEnvironmentVariable + "=1 for a panel without a trust root)";
}
return trust.Controllers.Count == 0
? "none of this node's owner passkeys is in the operator set any more; enroll it again with a command from the panel"
: null;
}
/// 读身份目录里固定的信任根,检查属主;不行就记一条错误并返回 false(调用方应当退出)。
public static bool Check(string identityDirectory, bool require, INodeLog log)
{
TrustAnchor trust = TrustAnchor.Load(identityDirectory, log);
if (Problem(trust, require) is { } problem)
{
log.Error("startup failed", ("err", problem));
return false;
}
return true;
}
}