223 lines
14 KiB
C#
223 lines
14 KiB
C#
using Fleet.Core;
|
||
using System.Text.Json;
|
||
|
||
namespace MoShiro.Backend.Api;
|
||
|
||
/// <summary><c>return_session</c>:跨域的前端用——不设 Cookie,把会话令牌放在响应里,之后用 <c>Authorization: Bearer</c> 带上。</summary>
|
||
public sealed record LoginRequest(string Username, string Password, bool? ReturnSession);
|
||
|
||
/// <summary>浏览器 <c>navigator.credentials.create</c> 要的参数;二进制字段都是 base64url。</summary>
|
||
public sealed record PasskeyCreationOptionsDto(string Challenge, string RpId, string RpName, string UserId, string UserName, IReadOnlyList<string> ExcludeCredentials, int TimeoutMs);
|
||
|
||
/// <summary>浏览器 <c>navigator.credentials.get</c> 要的参数(可发现凭证:不需要先输用户名)。</summary>
|
||
/// <param name="AllowCredentials">列出时限定可选的 passkey(凭证 id);登录的挑战不带。</param>
|
||
public sealed record PasskeyRequestOptionsDto(string Challenge, string RpId, int TimeoutMs, IReadOnlyList<string>? AllowCredentials = null);
|
||
|
||
/// <param name="Class"><c>enroll</c>(加节点)、<c>revoke</c>(吊销和删除)、<c>credential</c>(改凭证,用一次就没有)。</param>
|
||
public sealed record RegisterPasskeyRequest(string Name, string CredentialId, string AttestationObject, string ClientDataJson, IReadOnlyList<string>? Transports);
|
||
|
||
public sealed record PasskeyLoginRequest(string CredentialId, string AuthenticatorData, string ClientDataJson, string Signature, bool? ReturnSession);
|
||
|
||
public sealed record PasskeyDto(string Id, string Name, DateTimeOffset CreatedAt, DateTimeOffset? LastUsedAt, IReadOnlyList<string> Transports);
|
||
|
||
public sealed record LoginResponse(string UserId, string Username, string CsrfToken, DateTimeOffset ExpiresAt, string? SessionToken);
|
||
|
||
/// <param name="AuthMethod">会话是怎么登录的:<c>password</c> 或 <c>passkey</c>(能力相同,信任类操作都要提权窗口);API 令牌为空。</param>
|
||
public sealed record MeDto(string Kind, IReadOnlyList<string> Capabilities, string? UserId, string? Username, string? CsrfToken, string? AuthMethod = null);
|
||
|
||
public sealed record LocalLimitsDto(double MaxTotalMbps, long MaxTotalPps, IReadOnlyList<string> AllowedTargetCidrs, int MaxConcurrentTests);
|
||
|
||
public sealed record RejectedDto(string Id, string Reason);
|
||
|
||
public sealed record HeartbeatDto(int Sessions, long PpsIn, long PpsOut, long DroppedInvalid, long DroppedRateLimited, long QueueBytes, DateTimeOffset At);
|
||
|
||
public sealed record AgentDto(
|
||
string Id,
|
||
string Name,
|
||
string Status,
|
||
bool Online,
|
||
bool ProbeConnected,
|
||
IReadOnlyList<ConnectedProbeDto> Probes,
|
||
HostDto? Host,
|
||
string PublicHost,
|
||
int ProbeTcpPort,
|
||
IReadOnlyList<int> ProbeUdpPorts,
|
||
IReadOnlyList<string> Labels,
|
||
bool PublicVisible,
|
||
IReadOnlyList<string> Kinds,
|
||
string? AgentVersion,
|
||
LocalLimitsDto? LocalLimits,
|
||
long TaskVersion,
|
||
long AppliedTaskVersion,
|
||
IReadOnlyList<RejectedDto> Rejected,
|
||
HeartbeatDto? Heartbeat,
|
||
int EndpointChanges,
|
||
DateTimeOffset CreatedAt,
|
||
DateTimeOffset? LastSeenAt,
|
||
string Ipv6Host = "",
|
||
bool Ipv6Supported = false,
|
||
Ipv6DiagnosticDto? Ipv6 = null,
|
||
bool PublicHostAuto = true,
|
||
bool Ipv6HostAuto = true,
|
||
string? AddedBy = null);
|
||
|
||
public sealed record Ipv6DiagnosticDto(bool? AddressConfigured, bool SocketSupported, bool? Listening, bool? HasGlobalAddress, bool? HasDefaultRoute, string State,
|
||
string NetworkScope = "unknown", bool? HostHasGlobalAddress = null, bool? HostHasDefaultRoute = null);
|
||
|
||
/// <summary>merge-patch:缺省或为 null 的字段不修改。</summary>
|
||
/// <param name="PublicHostAuto">true:撤销手填,回到自动识别(<c>ipv6_host_auto</c> 同理)。手填 <c>public_host</c> 或 <c>ipv6_host</c> 就是手动,自动识别不再覆盖。</param>
|
||
public sealed record AgentPatchRequest(string? Name, IReadOnlyList<string>? Labels, string? PublicHost, bool? PublicVisible, string? Ipv6Host = null, bool? PublicHostAuto = null, bool? Ipv6HostAuto = null);
|
||
|
||
/// <param name="Role"><c>agent</c> 或 <c>probe</c>:用这个令牌注册出来的是哪种节点。</param>
|
||
public sealed record JoinTokenDto(string Id, string? Note, IReadOnlyList<string> Labels, bool AutoApprove, int MaxUses, int Uses, DateTimeOffset ExpiresAt, DateTimeOffset? RevokedAt, DateTimeOffset CreatedAt, string Role = "agent", string? CreatedBy = null);
|
||
|
||
/// <param name="Controllers">属主:允许授权这个节点 extension 会话的 passkey 凭证 id(必须是操作员集合里的);缺省是集合里的全部。没有建立信任根时忽略。</param>
|
||
public sealed record CreateJoinTokenRequest(string? Note, IReadOnlyList<string>? Labels, bool? AutoApprove, int? MaxUses, int? ExpiresInHours, string? Role = null, IReadOnlyList<string>? Controllers = null);
|
||
|
||
/// <summary>令牌明文只在创建的响应里出现一次。</summary>
|
||
/// <summary>面板是不是还没有任何用户(需要首次初始化)。</summary>
|
||
public sealed record SetupStatusDto(bool NeedsSetup);
|
||
|
||
/// <param name="ClaimCode">首次启动时写在后端日志里的认领码(或者部署时指定的 <c>MoShiro__ClaimCode</c>)。</param>
|
||
public sealed record SetupRequest(string? ClaimCode, string? Username, string? Password, bool? ReturnSession);
|
||
|
||
public sealed record InstallCommandsDto(string Linux, string Macos, string Windows);
|
||
|
||
/// <param name="Env">要存成 <c>.env</c> 的内容(只有公开的值)。</param>
|
||
/// <param name="Url">compose 文件的下载地址。</param>
|
||
/// <param name="Sha256">compose 文件的 SHA-256:命令下载之后先核对它。</param>
|
||
/// <param name="Linux">Linux(Podman):建目录、写 .env、下载、核对哈希、启动,合在一起的一段命令。</param>
|
||
/// <param name="Macos">macOS(Docker Desktop);Agent 需要 Linux 宿主网络,所以是空的。</param>
|
||
/// <param name="Windows">Windows(Docker Desktop,PowerShell);Agent 同样是空的。</param>
|
||
public sealed record ComposeInstallDto(string Env, string Url, string Sha256, string Linux, string Macos, string Windows);
|
||
|
||
/// <summary>下一版里新增的 passkey。</summary>
|
||
public sealed record ProposedCredentialDto(string Id, string Name, DateTimeOffset CreatedAt);
|
||
|
||
/// <param name="Added">相对当前生效的集合新增的 passkey;签名之前必须看一眼是不是自己加的。</param>
|
||
/// <param name="Removed">相对当前生效的集合移除的 passkey 凭证 id。</param>
|
||
/// <param name="ServerKeyChanged">服务器密钥有变化(换了新的)。</param>
|
||
public sealed record TrustProposalDto(string Statement, int Version, string Challenge, IReadOnlyList<ProposedCredentialDto> Added, IReadOnlyList<string> Removed, bool ServerKeyChanged);
|
||
|
||
/// <param name="Genesis">创世版本的指纹:安装命令里固定到节点上的就是它。还没建立信任根时为空。</param>
|
||
/// <param name="InSync">当前生效的集合和已注册的 passkey、域名一致;不一致(比如新加了 passkey)就要签一个新版本。</param>
|
||
/// <param name="Proposal">下一个要签的版本(<c>challenge</c> 就是 WebAuthn 的挑战)。</param>
|
||
/// <param name="Operators">当前操作员集合里的 passkey 凭证 id:加入码的 <c>controllers</c> 只能从这里选。</param>
|
||
/// <param name="OperatorDetails">每个操作员是哪个账户的哪把 passkey(对不上已注册的 passkey 时名称和账户为空)。</param>
|
||
/// <param name="InstallShSha256">面板提供的安装脚本的 SHA-256(命令里核对的就是它)。</param>
|
||
/// <param name="InstallMatchesRelease">和 CI 签名的发布清单里记的哈希是否一致;没有清单或清单里没记时为空。不一致说明这个面板提供的脚本不是 CI 构建出来的那份。</param>
|
||
public sealed record TrustStateDto(bool Initialized, string? Genesis, int Version, bool InSync, TrustProposalDto? Proposal, string InstallUrl = "", IReadOnlyList<string>? Operators = null, string InstallShSha256 = "", string InstallPs1Sha256 = "", bool? InstallMatchesRelease = null, string ServerKey = "", bool ServerKeyListed = false, IReadOnlyList<NodeOwnerDto>? OperatorDetails = null);
|
||
|
||
public sealed record CreatedJoinTokenDto(JoinTokenDto Token, string Plaintext, InstallCommandsDto InstallCommands, ComposeInstallDto Compose);
|
||
|
||
/// <summary>Agent 眼中连着的一个 Probe(Agent 上报)。</summary>
|
||
public sealed record ConnectedProbeDto(string ProbeId, string? Version, string? Remote, DateTimeOffset ConnectedSince, string IpVersion = "ipv4");
|
||
|
||
/// <summary>某个 Probe 现在连着的一个 Agent。</summary>
|
||
public sealed record ProbeConnectionDto(string AgentId, string AgentName, bool AgentOnline, string? Version, string? Remote, DateTimeOffset ConnectedSince, string IpVersion = "ipv4");
|
||
|
||
public sealed record ProbeDto(string Id, string Name, DateTimeOffset CreatedAt, DateTimeOffset? RevokedAt, bool Revoked, bool Online, IReadOnlyList<ProbeConnectionDto> Connections, Ipv6DiagnosticDto? Ipv6 = null, string? AddedBy = null);
|
||
|
||
/// <summary>一对(Probe,Agent)的线路开关:<c>linked</c> 是最终结果,<c>override</c> 是手动设置(<c>null</c> = 跟随自动连接),<c>connected</c> 是现在有没有连着。</summary>
|
||
public sealed record LinkDto(string ProbeId, string ProbeName, string AgentId, string AgentName, bool Linked, bool? Override, bool Connected);
|
||
|
||
public sealed record LinkMatrixDto(bool AutoLink, IReadOnlyList<LinkDto> Items);
|
||
|
||
public sealed record SetLinkRequest(bool? Enabled);
|
||
|
||
/// <summary>Isp:telecom / unicom / mobile / broadnet / other 是手动指定,auto 是回到自动识别;不传就不改。</summary>
|
||
public sealed record PatchProbeRequest(string? Name, string? Isp = null);
|
||
|
||
public sealed record TaskDto(
|
||
string Id,
|
||
string Scope,
|
||
string? AgentId,
|
||
string? BaseTaskId,
|
||
string Kind,
|
||
string? Target,
|
||
IReadOnlyDictionary<string, JsonElement> Params,
|
||
string Schedule,
|
||
bool Enabled,
|
||
DateTimeOffset UpdatedAt);
|
||
|
||
public sealed record CreateTaskRequest(
|
||
string Scope,
|
||
string Kind,
|
||
string? Target,
|
||
Dictionary<string, JsonElement>? Params,
|
||
string? Schedule,
|
||
bool? Enabled,
|
||
string? AgentId,
|
||
string? BaseTaskId);
|
||
|
||
public sealed record PatchTaskRequest(Dictionary<string, JsonElement>? Params, string? Schedule, bool? Enabled, string? Target);
|
||
|
||
public sealed record StartTestRequestDto(string Plan, Dictionary<string, JsonElement>? Params);
|
||
|
||
public sealed record RawChunkMetaDto(
|
||
string ChunkId,
|
||
string AgentId,
|
||
string Series,
|
||
string Kind,
|
||
string? TaskId,
|
||
string? TestId,
|
||
int? Phase,
|
||
DateTimeOffset Start,
|
||
int DurationMs,
|
||
bool Partial,
|
||
int Bytes);
|
||
|
||
public sealed record ApiTokenDto(string Id, string Name, IReadOnlyList<string> Capabilities, DateTimeOffset CreatedAt, DateTimeOffset? LastUsedAt, DateTimeOffset? ExpiresAt, DateTimeOffset? RevokedAt);
|
||
|
||
/// <param name="Capabilities">能力列表(见 /api/admin/capabilities);写蕴含读,只能是创建者自己拥有能力的子集。</param>
|
||
/// <param name="ExpiresInDays">有效天数;缺省不过期。</param>
|
||
public sealed record CreateApiTokenRequest(string Name, IReadOnlyList<string> Capabilities, int? ExpiresInDays = null);
|
||
|
||
public sealed record CapabilityDto(string Id, bool Trust, bool Reserved, IReadOnlyList<string> Implies);
|
||
|
||
public sealed record CapabilityGroupDto(string Id, IReadOnlyList<CapabilityDto> Capabilities);
|
||
|
||
public sealed record CapabilityPresetDto(string Id, IReadOnlyList<string> Capabilities);
|
||
|
||
public sealed record CapabilityCatalogDto(IReadOnlyList<CapabilityGroupDto> Groups, IReadOnlyList<CapabilityPresetDto> Presets);
|
||
|
||
public sealed record CreatedApiTokenDto(ApiTokenDto Token, string Plaintext);
|
||
|
||
public sealed record SettingDto(string Key, string Type, string Value, string Default, string Description);
|
||
|
||
public sealed record UserDto(string Id, string Username, DateTimeOffset CreatedAt);
|
||
|
||
public sealed record CreateUserRequest(string Username, string Password);
|
||
|
||
public sealed record ChangePasswordRequest(string Password);
|
||
|
||
public sealed record RecomputeDto(string State, IReadOnlyList<string> Metrics, long WindowsDone, long WindowsTotal, DateTimeOffset? From, DateTimeOffset? To, int QueueLength);
|
||
|
||
/// <summary>管理端看的构建信息:每个节点自报的版本、tag、提交和构建时间,以及系统。</summary>
|
||
/// <summary>节点的一个属主:节点报上来的(安装时固定在节点本地的)passkey 凭证 id,以及它在面板上对应的 passkey 名称和账户(对不上任何已注册的 passkey 时为空)。</summary>
|
||
public sealed record NodeOwnerDto(string CredentialId, string? Passkey, string? Account);
|
||
|
||
public sealed record NodeBuildDto(string Id, string Kind, string? Os, string? OsName, string? Arch, string? Version, string? Tag, string? Commit, string? BuiltAt, NodeUpdateDto? Update = null, IReadOnlyList<NodeOwnerDto>? Owners = null);
|
||
|
||
/// <summary>节点宿主机上的更新器报告的状态(<c>up_to_date</c>、<c>available</c>、<c>applying</c>、<c>failed</c>、<c>rolled_back</c>、<c>invalid</c>);没装更新器的节点没有这个字段。</summary>
|
||
public sealed record NodeUpdateDto(string State, string? CurrentDigest, string? AvailableTag, string? AvailableVersion, string? Error, DateTimeOffset? At);
|
||
|
||
/// <summary>面板登记的最新发布清单(CI 签名的;验签在节点上)。</summary>
|
||
public sealed record ReleaseDto(string Component, long Seq, string Tag, string Version, string Digest, string Channel = "release");
|
||
|
||
public sealed record PublishReleaseRequest(string? Manifest, string? Signature);
|
||
|
||
/// <summary>一把发布公钥:指纹是 SPKI 的 SHA-256(小写十六进制)。</summary>
|
||
public sealed record ReleaseKeyDto(string Fingerprint, string PublicKey);
|
||
|
||
/// <summary>可信资产来源:官方发布密钥(始终信任)和可选的自有发布公钥(默认没有)。</summary>
|
||
public sealed record ReleaseKeysDto(ReleaseKeyDto Official, ReleaseKeyDto? Custom);
|
||
|
||
public sealed record SetReleaseKeyRequest(string? PublicKey);
|
||
|
||
public sealed record BackendUpdateDto(string Channel, bool Enabled, string State, string? CurrentTag, string? CurrentDigest, ReleaseDto? Available, string? Error);
|
||
|
||
public sealed record ConfirmBackendUpdateRequest(long Seq);
|
||
|
||
public sealed record BuildInfoDto(BuildDto Backend, IReadOnlyList<NodeBuildDto> Nodes, BackendUpdateDto? BackendUpdate = null);
|