下载地址增加 key 认证
agent二进制下载地址增加 key 认证,防止刷流量
This commit is contained in:
1 parent
fd7a083139
commit
9ae1fea7d8
6 files changed
+57
-46
No files matched your search
@@ -58,6 +58,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
|||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
||||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||||
|
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
|
||||||
|
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4=
|
github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4=
|
||||||
|
|||||||
@@ -16,13 +16,14 @@ type AgentHandler struct {
|
|||||||
tamperService *service.TamperService
|
tamperService *service.TamperService
|
||||||
ddnsService *service.DDNSService
|
ddnsService *service.DDNSService
|
||||||
sshLoginService *service.SSHLoginService
|
sshLoginService *service.SSHLoginService
|
||||||
|
apiKeyService *service.ApiKeyService
|
||||||
wsManager *ws.Manager
|
wsManager *ws.Manager
|
||||||
upgrader websocket.Upgrader
|
upgrader websocket.Upgrader
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAgentHandler(logger *zap.Logger, agentService *service.AgentService, trafficService *service.TrafficService,
|
func NewAgentHandler(logger *zap.Logger, agentService *service.AgentService, trafficService *service.TrafficService,
|
||||||
metricService *service.MetricService, monitorService *service.MonitorService, tamperService *service.TamperService,
|
metricService *service.MetricService, monitorService *service.MonitorService, tamperService *service.TamperService,
|
||||||
ddnsService *service.DDNSService, sshLoginService *service.SSHLoginService, wsManager *ws.Manager) *AgentHandler {
|
ddnsService *service.DDNSService, sshLoginService *service.SSHLoginService, apiKeyService *service.ApiKeyService, wsManager *ws.Manager) *AgentHandler {
|
||||||
|
|
||||||
h := &AgentHandler{
|
h := &AgentHandler{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
@@ -33,6 +34,7 @@ func NewAgentHandler(logger *zap.Logger, agentService *service.AgentService, tra
|
|||||||
tamperService: tamperService,
|
tamperService: tamperService,
|
||||||
ddnsService: ddnsService,
|
ddnsService: ddnsService,
|
||||||
sshLoginService: sshLoginService,
|
sshLoginService: sshLoginService,
|
||||||
|
apiKeyService: apiKeyService,
|
||||||
wsManager: wsManager,
|
wsManager: wsManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,13 @@ func (h *AgentHandler) GetAgentVersion(c echo.Context) error {
|
|||||||
func (h *AgentHandler) DownloadAgent(c echo.Context) error {
|
func (h *AgentHandler) DownloadAgent(c echo.Context) error {
|
||||||
filename := c.Param("filename")
|
filename := c.Param("filename")
|
||||||
|
|
||||||
|
// 校验 API Key
|
||||||
|
apiKey := c.QueryParam("key")
|
||||||
|
if _, err := h.apiKeyService.ValidateApiKey(c.Request().Context(), apiKey); err != nil {
|
||||||
|
h.logger.Warn("download agent failed: invalid api key", zap.String("key", apiKey))
|
||||||
|
return orz.NewError(401, "无效的 API 密钥")
|
||||||
|
}
|
||||||
|
|
||||||
// 从嵌入的文件系统读取
|
// 从嵌入的文件系统读取
|
||||||
agentFile, err := pika.AgentFS().Open(fmt.Sprintf("pika-%s", filename))
|
agentFile, err := pika.AgentFS().Open(fmt.Sprintf("pika-%s", filename))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -135,7 +142,7 @@ detect_platform() {
|
|||||||
|
|
||||||
# 下载探针
|
# 下载探针
|
||||||
download_agent() {
|
download_agent() {
|
||||||
local download_url="` + serverUrl + `/api/agent/downloads/agent-$PLATFORM"
|
local download_url="` + serverUrl + `/api/agent/downloads/agent-$PLATFORM?key=` + token + `"
|
||||||
local temp_file="/tmp/pika-agent-download"
|
local temp_file="/tmp/pika-agent-download"
|
||||||
|
|
||||||
echo_info "正在下载探针..."
|
echo_info "正在下载探针..."
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func InitializeApp(logger *zap.Logger, db *gorm.DB, cfg *config.AppConfig) (*App
|
|||||||
tamperService := service.NewTamperService(logger, db, manager, notificationService)
|
tamperService := service.NewTamperService(logger, db, manager, notificationService)
|
||||||
ddnsService := service.NewDDNSService(logger, db, propertyService, manager)
|
ddnsService := service.NewDDNSService(logger, db, propertyService, manager)
|
||||||
sshLoginService := service.NewSSHLoginService(logger, db, manager, geoIPService, notificationService)
|
sshLoginService := service.NewSSHLoginService(logger, db, manager, geoIPService, notificationService)
|
||||||
agentHandler := handler.NewAgentHandler(logger, agentService, trafficService, metricService, monitorService, tamperService, ddnsService, sshLoginService, manager)
|
agentHandler := handler.NewAgentHandler(logger, agentService, trafficService, metricService, monitorService, tamperService, ddnsService, sshLoginService, apiKeyService, manager)
|
||||||
apiKeyHandler := handler.NewApiKeyHandler(logger, apiKeyService)
|
apiKeyHandler := handler.NewApiKeyHandler(logger, apiKeyService)
|
||||||
alertService := service.NewAlertService(logger, db, propertyService, monitorService, notifier)
|
alertService := service.NewAlertService(logger, db, propertyService, monitorService, notifier)
|
||||||
alertHandler := handler.NewAlertHandler(logger, alertService)
|
alertHandler := handler.NewAlertHandler(logger, alertService)
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ func (c *Config) GetDownloadURL() string {
|
|||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
filename += ".exe"
|
filename += ".exe"
|
||||||
}
|
}
|
||||||
return c.Endpoint() + "/api/agent/downloads/" + filename
|
return c.Endpoint() + "/api/agent/downloads/" + filename + "?key=" + c.Server.APIKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Endpoint() string {
|
func (c *Config) Endpoint() string {
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import React, {type ReactElement, useCallback, useEffect, useMemo, useState} from 'react';
|
import React, { type ReactElement, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import {Alert, App, Button, Card, Select, Space, Tabs, Typography} from 'antd';
|
import { Alert, App, Button, Card, Select, Space, Tabs, Typography } from 'antd';
|
||||||
import {CopyIcon} from 'lucide-react';
|
import { CopyIcon } from 'lucide-react';
|
||||||
import {listApiKeys} from '@/api/apiKey.ts';
|
import { listApiKeys } from '@/api/apiKey.ts';
|
||||||
import {getServerUrl} from '@/api/agent.ts';
|
import { getServerUrl } from '@/api/agent.ts';
|
||||||
import type {ApiKey} from '@/types';
|
import type { ApiKey } from '@/types';
|
||||||
import linuxPng from '../../assets/os/linux.png';
|
import linuxPng from '../../assets/os/linux.png';
|
||||||
import applePng from '../../assets/os/apple.png';
|
import applePng from '../../assets/os/apple.png';
|
||||||
import windowsPng from '../../assets/os/win11.png';
|
import windowsPng from '../../assets/os/win11.png';
|
||||||
import {useNavigate} from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import copy from 'copy-to-clipboard';
|
import copy from 'copy-to-clipboard';
|
||||||
|
|
||||||
const {Paragraph, Text} = Typography;
|
const { Paragraph, Text } = Typography;
|
||||||
const {TabPane} = Tabs;
|
const { TabPane } = Tabs;
|
||||||
|
|
||||||
// 常量定义
|
// 常量定义
|
||||||
const AGENT_NAME = 'pika-agent';
|
const AGENT_NAME = 'pika-agent';
|
||||||
@@ -42,7 +42,7 @@ const AgentInstall = () => {
|
|||||||
// 服务器地址相关状态
|
// 服务器地址相关状态
|
||||||
const [backendServerUrl, setBackendServerUrl] = useState<string>('');
|
const [backendServerUrl, setBackendServerUrl] = useState<string>('');
|
||||||
|
|
||||||
const {message} = App.useApp();
|
const { message } = App.useApp();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const frontendUrl = useMemo(() => window.location.origin, []);
|
const frontendUrl = useMemo(() => window.location.origin, []);
|
||||||
|
|
||||||
@@ -86,37 +86,37 @@ const AgentInstall = () => {
|
|||||||
const osConfigs: Record<OSType, OSConfig> = useMemo(() => ({
|
const osConfigs: Record<OSType, OSConfig> = useMemo(() => ({
|
||||||
'linux-amd64': {
|
'linux-amd64': {
|
||||||
name: 'Linux (amd64)',
|
name: 'Linux (amd64)',
|
||||||
icon: <img src={linuxPng} alt="Linux" className="h-4 w-4"/>,
|
icon: <img src={linuxPng} alt="Linux" className="h-4 w-4" />,
|
||||||
downloadUrl: '/api/agent/downloads/agent-linux-amd64',
|
downloadUrl: '/api/agent/downloads/agent-linux-amd64',
|
||||||
},
|
},
|
||||||
'linux-arm64': {
|
'linux-arm64': {
|
||||||
name: 'Linux (arm64)',
|
name: 'Linux (arm64)',
|
||||||
icon: <img src={linuxPng} alt="Linux" className="h-4 w-4"/>,
|
icon: <img src={linuxPng} alt="Linux" className="h-4 w-4" />,
|
||||||
downloadUrl: '/api/agent/downloads/agent-linux-arm64',
|
downloadUrl: '/api/agent/downloads/agent-linux-arm64',
|
||||||
},
|
},
|
||||||
'linux-loong64': {
|
'linux-loong64': {
|
||||||
name: 'Linux (loongarch64)',
|
name: 'Linux (loongarch64)',
|
||||||
icon: <img src={linuxPng} alt="Linux" className={'h-4 w-4'}/>,
|
icon: <img src={linuxPng} alt="Linux" className={'h-4 w-4'} />,
|
||||||
downloadUrl: '/api/agent/downloads/agent-linux-loong64',
|
downloadUrl: '/api/agent/downloads/agent-linux-loong64',
|
||||||
},
|
},
|
||||||
'darwin-amd64': {
|
'darwin-amd64': {
|
||||||
name: 'macOS (amd64)',
|
name: 'macOS (amd64)',
|
||||||
icon: <img src={applePng} alt="macOS" className="h-4 w-4"/>,
|
icon: <img src={applePng} alt="macOS" className="h-4 w-4" />,
|
||||||
downloadUrl: '/api/agent/downloads/agent-darwin-amd64',
|
downloadUrl: '/api/agent/downloads/agent-darwin-amd64',
|
||||||
},
|
},
|
||||||
'darwin-arm64': {
|
'darwin-arm64': {
|
||||||
name: 'macOS (arm64)',
|
name: 'macOS (arm64)',
|
||||||
icon: <img src={applePng} alt="macOS" className="h-4 w-4"/>,
|
icon: <img src={applePng} alt="macOS" className="h-4 w-4" />,
|
||||||
downloadUrl: '/api/agent/downloads/agent-darwin-arm64',
|
downloadUrl: '/api/agent/downloads/agent-darwin-arm64',
|
||||||
},
|
},
|
||||||
'windows-amd64': {
|
'windows-amd64': {
|
||||||
name: 'Windows (amd64)',
|
name: 'Windows (amd64)',
|
||||||
icon: <img src={windowsPng} alt="Windows" className="h-4 w-4"/>,
|
icon: <img src={windowsPng} alt="Windows" className="h-4 w-4" />,
|
||||||
downloadUrl: '/api/agent/downloads/agent-windows-amd64.exe',
|
downloadUrl: '/api/agent/downloads/agent-windows-amd64.exe',
|
||||||
},
|
},
|
||||||
'windows-arm64': {
|
'windows-arm64': {
|
||||||
name: 'Windows (arm64)',
|
name: 'Windows (arm64)',
|
||||||
icon: <img src={windowsPng} alt="Windows" className="h-4 w-4"/>,
|
icon: <img src={windowsPng} alt="Windows" className="h-4 w-4" />,
|
||||||
downloadUrl: '/api/agent/downloads/agent-windows-arm64.exe',
|
downloadUrl: '/api/agent/downloads/agent-windows-arm64.exe',
|
||||||
},
|
},
|
||||||
}), []);
|
}), []);
|
||||||
@@ -158,7 +158,7 @@ const AgentInstall = () => {
|
|||||||
<Space direction="vertical" className="w-full">
|
<Space direction="vertical" className="w-full">
|
||||||
<div>
|
<div>
|
||||||
当前访问地址: <Text code>{frontendUrl}</Text>
|
当前访问地址: <Text code>{frontendUrl}</Text>
|
||||||
<br/>
|
<br />
|
||||||
后端检测地址: <Text code>{backendServerUrl}</Text>
|
后端检测地址: <Text code>{backendServerUrl}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -170,7 +170,7 @@ const AgentInstall = () => {
|
|||||||
<div>
|
<div>
|
||||||
<Text strong>Nginx 配置示例:</Text>
|
<Text strong>Nginx 配置示例:</Text>
|
||||||
<pre className="m-0 mt-2 overflow-auto text-xs bg-gray-100 dark:bg-slate-900 p-2 rounded">
|
<pre className="m-0 mt-2 overflow-auto text-xs bg-gray-100 dark:bg-slate-900 p-2 rounded">
|
||||||
{`location / {
|
{`location / {
|
||||||
proxy_pass http://backend;
|
proxy_pass http://backend;
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_set_header X-Forwarded-Host $host;
|
proxy_set_header X-Forwarded-Host $host;
|
||||||
@@ -182,7 +182,7 @@ const AgentInstall = () => {
|
|||||||
<div>
|
<div>
|
||||||
<Text strong>Caddy 配置示例:</Text>
|
<Text strong>Caddy 配置示例:</Text>
|
||||||
<pre className="m-0 mt-2 overflow-auto text-xs bg-gray-100 dark:bg-slate-900 p-2 rounded">
|
<pre className="m-0 mt-2 overflow-auto text-xs bg-gray-100 dark:bg-slate-900 p-2 rounded">
|
||||||
{`reverse_proxy backend:8080 {
|
{`reverse_proxy backend:8080 {
|
||||||
header_up X-Forwarded-Proto {scheme}
|
header_up X-Forwarded-Proto {scheme}
|
||||||
header_up X-Forwarded-Host {host}
|
header_up X-Forwarded-Host {host}
|
||||||
}`}
|
}`}
|
||||||
@@ -191,7 +191,7 @@ const AgentInstall = () => {
|
|||||||
<div>
|
<div>
|
||||||
<Text strong>Traefik 配置说明:</Text>
|
<Text strong>Traefik 配置说明:</Text>
|
||||||
<pre className="m-0 mt-2 overflow-auto text-xs bg-gray-100 dark:bg-slate-900 p-2 rounded">
|
<pre className="m-0 mt-2 overflow-auto text-xs bg-gray-100 dark:bg-slate-900 p-2 rounded">
|
||||||
{`# Traefik 默认会自动添加 X-Forwarded-* 头部
|
{`# Traefik 默认会自动添加 X-Forwarded-* 头部
|
||||||
# 无需额外配置`}
|
# 无需额外配置`}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
@@ -240,8 +240,8 @@ const AgentInstall = () => {
|
|||||||
// 一键安装组件
|
// 一键安装组件
|
||||||
const InstallByOneClick = useCallback(() => (
|
const InstallByOneClick = useCallback(() => (
|
||||||
<Space direction="vertical" className="w-full">
|
<Space direction="vertical" className="w-full">
|
||||||
<ServerUrlChecker/>
|
<ServerUrlChecker />
|
||||||
<ApiChooser/>
|
<ApiChooser />
|
||||||
<Alert
|
<Alert
|
||||||
description="一键安装脚本仅支持 Linux/macOS 系统。"
|
description="一键安装脚本仅支持 Linux/macOS 系统。"
|
||||||
type="info"
|
type="info"
|
||||||
@@ -259,16 +259,16 @@ const AgentInstall = () => {
|
|||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
onClick={() => void copyToClipboard(installCommand)}
|
onClick={() => void copyToClipboard(installCommand)}
|
||||||
icon={<CopyIcon className="h-4 w-4"/>}
|
icon={<CopyIcon className="h-4 w-4" />}
|
||||||
style={{margin: 0, padding: 0}}
|
style={{ margin: 0, padding: 0 }}
|
||||||
disabled={!selectedApiKey}
|
disabled={!selectedApiKey}
|
||||||
>
|
>
|
||||||
复制命令
|
复制命令
|
||||||
</Button>
|
</Button>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<ServiceHelper os={AGENT_NAME}/>
|
<ServiceHelper os={AGENT_NAME} />
|
||||||
<ConfigHelper/>
|
<ConfigHelper />
|
||||||
</Space>
|
</Space>
|
||||||
), [ServerUrlChecker, ApiChooser, installCommand, copyToClipboard, selectedApiKey]);
|
), [ServerUrlChecker, ApiChooser, installCommand, copyToClipboard, selectedApiKey]);
|
||||||
|
|
||||||
@@ -297,7 +297,7 @@ ${agentCmd} version`;
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// 服务管理命令组件
|
// 服务管理命令组件
|
||||||
const ServiceHelper = useCallback(({os}: { os: string }) => (
|
const ServiceHelper = useCallback(({ os }: { os: string }) => (
|
||||||
<Card type="inner" title="服务管理命令">
|
<Card type="inner" title="服务管理命令">
|
||||||
<Paragraph type="secondary" className="mb-3 text-gray-600 dark:text-slate-400">
|
<Paragraph type="secondary" className="mb-3 text-gray-600 dark:text-slate-400">
|
||||||
注册完成后,您可以使用以下命令管理探针服务:
|
注册完成后,您可以使用以下命令管理探针服务:
|
||||||
@@ -335,10 +335,10 @@ ${agentCmd} version`;
|
|||||||
{
|
{
|
||||||
title: '1. 下载探针',
|
title: '1. 下载探针',
|
||||||
command: `# 使用 PowerShell 下载
|
command: `# 使用 PowerShell 下载
|
||||||
Invoke-WebRequest -Uri "${backendServerUrl}${config.downloadUrl}" -OutFile "${AGENT_NAME_EXE}"
|
Invoke-WebRequest -Uri "${backendServerUrl}${config.downloadUrl}?key=${selectedApiKey}" -OutFile "${AGENT_NAME_EXE}"
|
||||||
|
|
||||||
# 或者使用浏览器直接下载
|
# 或者使用浏览器直接下载
|
||||||
# ${backendServerUrl}${config.downloadUrl}`
|
# ${backendServerUrl}${config.downloadUrl}?key=${selectedApiKey}`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '2. 注册探针',
|
title: '2. 注册探针',
|
||||||
@@ -355,10 +355,10 @@ Invoke-WebRequest -Uri "${backendServerUrl}${config.downloadUrl}" -OutFile "${AG
|
|||||||
{
|
{
|
||||||
title: '1. 下载探针',
|
title: '1. 下载探针',
|
||||||
command: `# 使用 wget 下载
|
command: `# 使用 wget 下载
|
||||||
wget ${backendServerUrl}${config.downloadUrl} -O ${AGENT_NAME}
|
wget "${backendServerUrl}${config.downloadUrl}?key=${selectedApiKey}" -O ${AGENT_NAME}
|
||||||
|
|
||||||
# 或使用 curl 下载
|
# 或使用 curl 下载
|
||||||
curl -L ${backendServerUrl}${config.downloadUrl} -o ${AGENT_NAME}`
|
curl -L "${backendServerUrl}${config.downloadUrl}?key=${selectedApiKey}" -o ${AGENT_NAME}`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '2. 赋予执行权限',
|
title: '2. 赋予执行权限',
|
||||||
@@ -382,8 +382,8 @@ curl -L ${backendServerUrl}${config.downloadUrl} -o ${AGENT_NAME}`
|
|||||||
// 手动安装组件
|
// 手动安装组件
|
||||||
const InstallByManual = useCallback(() => (
|
const InstallByManual = useCallback(() => (
|
||||||
<Space direction="vertical" className="w-full">
|
<Space direction="vertical" className="w-full">
|
||||||
<ServerUrlChecker/>
|
<ServerUrlChecker />
|
||||||
<ApiChooser/>
|
<ApiChooser />
|
||||||
<Tabs
|
<Tabs
|
||||||
activeKey={selectedOS}
|
activeKey={selectedOS}
|
||||||
onChange={(key) => setSelectedOS(key as OSType)}
|
onChange={(key) => setSelectedOS(key as OSType)}
|
||||||
@@ -404,7 +404,7 @@ curl -L ${backendServerUrl}${config.downloadUrl} -o ${AGENT_NAME}`
|
|||||||
{getManualInstallSteps(key as OSType).map((step, index) => (
|
{getManualInstallSteps(key as OSType).map((step, index) => (
|
||||||
<div key={index}>
|
<div key={index}>
|
||||||
<Text strong
|
<Text strong
|
||||||
className="block mb-2 text-gray-900 dark:text-slate-100">{step.title}</Text>
|
className="block mb-2 text-gray-900 dark:text-slate-100">{step.title}</Text>
|
||||||
<pre
|
<pre
|
||||||
className="m-0 overflow-auto text-sm bg-gray-50 dark:bg-slate-800 p-3 rounded text-gray-900 dark:text-slate-100">
|
className="m-0 overflow-auto text-sm bg-gray-50 dark:bg-slate-800 p-3 rounded text-gray-900 dark:text-slate-100">
|
||||||
<code>{step.command}</code>
|
<code>{step.command}</code>
|
||||||
@@ -412,9 +412,9 @@ curl -L ${backendServerUrl}${config.downloadUrl} -o ${AGENT_NAME}`
|
|||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
onClick={() => void copyToClipboard(step.command)}
|
onClick={() => void copyToClipboard(step.command)}
|
||||||
icon={<CopyIcon className="h-4 w-4"/>}
|
icon={<CopyIcon className="h-4 w-4" />}
|
||||||
size="small"
|
size="small"
|
||||||
style={{margin: 0, padding: 0}}
|
style={{ margin: 0, padding: 0 }}
|
||||||
disabled={!selectedApiKey}
|
disabled={!selectedApiKey}
|
||||||
>
|
>
|
||||||
复制
|
复制
|
||||||
@@ -424,8 +424,8 @@ curl -L ${backendServerUrl}${config.downloadUrl} -o ${AGENT_NAME}`
|
|||||||
</Space>
|
</Space>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<ServiceHelper os={key}/>
|
<ServiceHelper os={key} />
|
||||||
<ConfigHelper/>
|
<ConfigHelper />
|
||||||
</Space>
|
</Space>
|
||||||
</TabPane>
|
</TabPane>
|
||||||
))}
|
))}
|
||||||
@@ -438,12 +438,12 @@ curl -L ${backendServerUrl}${config.downloadUrl} -o ${AGENT_NAME}`
|
|||||||
{
|
{
|
||||||
label: '一键安装',
|
label: '一键安装',
|
||||||
key: 'one-click',
|
key: 'one-click',
|
||||||
children: <InstallByOneClick/>
|
children: <InstallByOneClick />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '手动安装',
|
label: '手动安装',
|
||||||
key: 'manual',
|
key: 'manual',
|
||||||
children: <InstallByManual/>
|
children: <InstallByManual />
|
||||||
},
|
},
|
||||||
], [InstallByOneClick, InstallByManual]);
|
], [InstallByOneClick, InstallByManual]);
|
||||||
|
|
||||||
@@ -463,7 +463,7 @@ curl -L ${backendServerUrl}${config.downloadUrl} -o ${AGENT_NAME}`
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Tabs
|
<Tabs
|
||||||
style={{marginTop: 24}}
|
style={{ marginTop: 24 }}
|
||||||
tabPosition="left"
|
tabPosition="left"
|
||||||
items={tabItems}
|
items={tabItems}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in new issue
Block a user