107 lines
5.4 KiB
TypeScript
107 lines
5.4 KiB
TypeScript
import type { Metadata } from "next";
|
|
import Link from "next/link";
|
|
import { PublicShell, StatusPill } from "../components/Shells";
|
|
import {
|
|
checksumVerificationCommand,
|
|
getDaemonReleaseState,
|
|
} from "../daemon-release";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
export const metadata: Metadata = {
|
|
title: "下载主机端 daemon",
|
|
description: "下载并核验用于 NekoNest Cloud 免费公测的 Windows 或 Linux 主机端 daemon。",
|
|
};
|
|
|
|
const unavailableCopy = {
|
|
not_configured: {
|
|
title: "兼容 Cloud 的公开构建尚未上架。",
|
|
body: "下载清单还没有同时配置兼容版本、三个平台包和各自 SHA-256,因此入口保持关闭。闭测参与者可以继续使用单独提供并完成核验的构建。",
|
|
},
|
|
invalid_config: {
|
|
title: "下载清单未通过安全校验。",
|
|
body: "版本、HTTPS 下载地址或 SHA-256 有一项不完整。修复前不会把用户送到不确定的二进制文件。",
|
|
},
|
|
incompatible_version: {
|
|
title: "现有发布版本不兼容 Cloud 接入。",
|
|
body: "下载入口只接受实现控制面激活交接的 daemon。旧版仍可用于自托管,但不会作为 Cloud 客户端展示。",
|
|
},
|
|
} as const;
|
|
|
|
export default async function DownloadPage() {
|
|
const release = await getDaemonReleaseState();
|
|
return (
|
|
<PublicShell>
|
|
<div className="public-page download-page">
|
|
<header className="download-hero">
|
|
<StatusPill tone={release.available ? "good" : "warn"}>
|
|
{release.available ? `CLOUD DAEMON v${release.version}` : "DOWNLOAD GATED"}
|
|
</StatusPill>
|
|
<h1>{release.available ? "下载、核验,再连接。" : unavailableCopy[release.reason].title}</h1>
|
|
<p>
|
|
{release.available
|
|
? "选择主机平台,下载固定版本压缩包,并在解压和运行前核对 SHA-256。主机无需开放入站端口。"
|
|
: unavailableCopy[release.reason].body}
|
|
</p>
|
|
<small>Cloud 最低兼容版本:v{release.minimumVersion} · macOS 暂未正式支持</small>
|
|
</header>
|
|
|
|
{release.available ? (
|
|
<>
|
|
<section className="download-section" aria-labelledby="download-platform-title">
|
|
<div className="download-heading">
|
|
<span className="eyebrow">CHOOSE PLATFORM / 选择平台</span>
|
|
<h2 id="download-platform-title">三个包,三个独立摘要。</h2>
|
|
<p>Linux 可运行 <code>uname -m</code> 确认架构;Windows 当前只提供 x64。</p>
|
|
</div>
|
|
<div className="download-grid">
|
|
{release.assets.map((asset) => (
|
|
<article className="download-card" key={`${asset.platform}-${asset.architecture}`}>
|
|
<span className="download-platform">{asset.platform === "windows" ? "WINDOWS" : "LINUX"}</span>
|
|
<h3>{asset.label}</h3>
|
|
<code className="download-filename">{asset.filename}</code>
|
|
<a className="button button-primary" href={asset.downloadUrl} rel="noopener noreferrer">下载 v{release.version}</a>
|
|
<div className="checksum-block">
|
|
<strong>发布摘要</strong>
|
|
<code>{asset.sha256}</code>
|
|
</div>
|
|
<details>
|
|
<summary>查看校验命令</summary>
|
|
<pre><code>{checksumVerificationCommand(asset)}</code></pre>
|
|
</details>
|
|
</article>
|
|
))}
|
|
</div>
|
|
</section>
|
|
|
|
<section className="download-proof">
|
|
<div>
|
|
<span className="eyebrow">VERIFY THE RELEASE / 核对发布</span>
|
|
<h2>摘要校验不是代码签名。</h2>
|
|
<p>SHA-256 只能证明下载文件与控制台公布的字节一致。当前发布流水线尚未提供 Windows Authenticode 或其他发布者代码签名,因此这项能力仍是扩大公测前的门禁。</p>
|
|
</div>
|
|
<div className="download-proof-actions">
|
|
<a className="button button-secondary" href={release.checksumsUrl} rel="noopener noreferrer">下载 checksums.txt</a>
|
|
<a className="button button-secondary" href={release.releasePageUrl} rel="noopener noreferrer">查看 v{release.version} 发布记录</a>
|
|
<Link className="button button-primary" href="/dashboard/hosts/new">已下载,开始配对</Link>
|
|
</div>
|
|
</section>
|
|
</>
|
|
) : (
|
|
<section className="download-gated" aria-labelledby="download-gated-title">
|
|
<div>
|
|
<span className="eyebrow">FAIL CLOSED / 暂停分发</span>
|
|
<h2 id="download-gated-title">不提供“先下最新版试试”的按钮。</h2>
|
|
<p>Release 的“最新版”可能仍只适用于自托管。Cloud 必须同时确认最低兼容版本、固定 HTTPS 地址和每个平台的 SHA-256 后,才会显示直接下载入口。</p>
|
|
</div>
|
|
<div className="download-gated-actions">
|
|
<a className="button button-secondary" href="https://github.com/klarkxy/nekonest/releases" rel="noopener noreferrer">仅查看上游发布记录</a>
|
|
<Link className="button button-primary" href="/readiness">查看公测门禁</Link>
|
|
</div>
|
|
</section>
|
|
)}
|
|
</div>
|
|
</PublicShell>
|
|
);
|
|
}
|