Files
MyGoNavi/frontend/src/components/connectionModal/ConnectionModalNetworkSecuritySection.tsx
Syngnat e7935db84b feat(db-connection): 新增连接后台定时探活保活能力
- 为连接配置新增 keepAlive 开关与探活间隔
- 在后端缓存连接上增加后台定时 Ping 调度与失效剔除
- 补充前端表单、Wails 模型映射与定向测试覆盖

Close #579
2026-06-20 11:24:44 +08:00

1040 lines
36 KiB
TypeScript

import React from "react";
import { Button, Checkbox, Form, Input, InputNumber, Space, Typography } from "antd";
import { t } from "../../i18n";
import { getStoredSecretPlaceholder } from "../../utils/connectionModalPresentation";
import { noAutoCapInputProps } from "../../utils/inputAutoCap";
const { Text } = Typography;
const DEFAULT_KEEPALIVE_INTERVAL_MINUTES = 240;
const MIN_KEEPALIVE_INTERVAL_MINUTES = 1;
const MAX_KEEPALIVE_INTERVAL_MINUTES = 1440;
type ConnectionModalNetworkSecuritySectionProps = Record<string, any>;
const ConnectionModalNetworkSecuritySection: React.FC<ConnectionModalNetworkSecuritySectionProps> = (props) => {
const {
activeNetworkConfig,
darkMode,
dbType,
form,
getConnectionOptionCardStyle,
handleSelectCertificateFile,
handleSelectSSHKeyFile,
initialValues,
isFileDb,
isJVM,
isSSLType,
modalInnerSectionStyle,
modalMutedTextStyle,
renderChoiceCards,
renderStoredSecretControls,
proxyType,
selectingCertificateField,
selectingSSHKey,
setActiveNetworkConfig,
sslHintText,
sslMode,
supportsSSLCAPath,
supportsSSLClientCertificate,
tunnelSectionStyle,
useHttpTunnel,
useProxy,
useSSH,
useSSL,
} = props;
if (isFileDb || isJVM) {
return null;
}
const effectiveUseSSL = useSSL || !!form.getFieldValue("useSSL");
const effectiveUseSSH = useSSH || !!form.getFieldValue("useSSH");
const effectiveUseHttpTunnel =
useHttpTunnel ||
!!form.getFieldValue("useHttpTunnel");
const effectiveUseProxy =
!effectiveUseHttpTunnel &&
(useProxy || !!form.getFieldValue("useProxy"));
const keepAliveEnabled = !!Form.useWatch("keepAliveEnabled", form);
const networkItems: Array<{
key: "ssl" | "ssh" | "proxy" | "httpTunnel";
title: string;
description: string;
enabled: boolean;
}> = [
...(isSSLType
? [
{
key: "ssl" as const,
title: t("connection.modal.network.ssl_tls"),
description: t(
"connection.modal.network.ssl.description",
),
enabled: effectiveUseSSL,
},
]
: []),
{
key: "ssh",
title: t("connection.modal.network.ssh.title"),
description: t("connection.modal.network.ssh.description"),
enabled: effectiveUseSSH,
},
{
key: "proxy",
title: t("connection.modal.network.proxy.title"),
description: t("connection.modal.network.proxy.description"),
enabled: effectiveUseProxy,
},
{
key: "httpTunnel",
title: t("connection.modal.network.httpTunnel.title"),
description: t(
"connection.modal.network.httpTunnel.description",
),
enabled: effectiveUseHttpTunnel,
},
];
const resolvedNetworkConfig =
activeNetworkConfig === "ssl" && !effectiveUseSSL
? networkItems.find((item) => item.enabled)?.key ||
(networkItems.some((item) => item.key === activeNetworkConfig)
? activeNetworkConfig
: networkItems[0]?.key || "ssh")
: networkItems.some((item) => item.key === activeNetworkConfig)
? activeNetworkConfig
: networkItems[0]?.key || "ssh";
const renderNetworkPanel = () => {
if (resolvedNetworkConfig === "ssl") {
return (
<div style={{ ...modalInnerSectionStyle, padding: 14 }}>
<div
style={{
marginBottom: 8,
color: darkMode ? "#f5f7ff" : "#162033",
fontSize: 14,
fontWeight: 700,
}}
>
{t("connection.modal.network.ssl_tls")}
</div>
<div style={{ ...modalMutedTextStyle, marginBottom: 14 }}>
{t("connection.modal.network.ssl.panelDescription")}
</div>
{!effectiveUseSSL ? (
<div
style={{
...modalMutedTextStyle,
padding: "10px 12px",
borderRadius: 12,
background: darkMode
? "rgba(255,255,255,0.03)"
: "rgba(16,24,40,0.04)",
}}
>
<div>{t("connection.modal.network.ssl.disabledHint")}</div>
<div style={{ marginTop: 8 }}>{sslHintText}</div>
</div>
) : (
<div style={tunnelSectionStyle}>
<div style={{ display: "grid", gap: 8, marginBottom: 14 }}>
<Text strong>
{t("connection.modal.network.ssl.mode")}
</Text>
{renderChoiceCards({
fieldName: "sslMode",
value: String(sslMode),
options: [
{
value: "preferred",
label: t(
"connection.modal.network.ssl_mode.preferred",
),
description: t(
"connection.modal.network.ssl.preferred.description",
),
},
{
value: "required",
label: t(
"connection.modal.network.ssl_mode.required",
),
description: t(
"connection.modal.network.ssl.required.description",
),
},
{
value: "skip-verify",
label: t(
"connection.modal.network.ssl_mode.skip_verify",
),
description: t(
"connection.modal.network.ssl.skipVerify.description",
),
},
],
})}
</div>
{(supportsSSLCAPath || supportsSSLClientCertificate) && (
<div style={{ display: "grid", gap: 8, marginBottom: 12 }}>
{supportsSSLCAPath && (
<Form.Item
label={
dbType === "sqlserver"
? t(
"connection.modal.network.ssl.serverCaPath",
)
: t(
"connection.modal.network.ssl.caPath",
)
}
style={{ marginBottom: 0 }}
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item name="sslCAPath" noStyle>
<Input
{...noAutoCapInputProps}
placeholder={t(
"connection.modal.example",
{ value: "C:\\certs\\ca.pem" },
)}
/>
</Form.Item>
<Button
onClick={() => handleSelectCertificateFile("sslCAPath", "ca")}
loading={selectingCertificateField === "sslCAPath"}
>
{t("connection.modal.action.browse")}
</Button>
</Space.Compact>
</Form.Item>
)}
{supportsSSLClientCertificate && (
<>
<Form.Item
label={
dbType === "dameng"
? t(
"connection.modal.network.ssl.damengCertPath",
)
: t(
"connection.modal.network.ssl.certPath",
)
}
rules={[
{
required: dbType === "dameng",
message: t(
"connection.modal.network.ssl.certRequired",
),
},
]}
style={{ marginBottom: 0 }}
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item name="sslCertPath" noStyle>
<Input
{...noAutoCapInputProps}
placeholder={t(
"connection.modal.example",
{
value:
"C:\\certs\\client-cert.pem",
},
)}
/>
</Form.Item>
<Button
onClick={() => handleSelectCertificateFile("sslCertPath", "client-cert")}
loading={selectingCertificateField === "sslCertPath"}
>
{t("connection.modal.action.browse")}
</Button>
</Space.Compact>
</Form.Item>
<Form.Item
label={
dbType === "dameng"
? t(
"connection.modal.network.ssl.damengKeyPath",
)
: t(
"connection.modal.network.ssl.keyPath",
)
}
rules={[
{
required: dbType === "dameng",
message: t(
"connection.modal.network.ssl.keyRequired",
),
},
]}
style={{ marginBottom: 0 }}
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item name="sslKeyPath" noStyle>
<Input
{...noAutoCapInputProps}
placeholder={t(
"connection.modal.example",
{
value:
"C:\\certs\\client-key.pem",
},
)}
/>
</Form.Item>
<Button
onClick={() => handleSelectCertificateFile("sslKeyPath", "client-key")}
loading={selectingCertificateField === "sslKeyPath"}
>
{t("connection.modal.action.browse")}
</Button>
</Space.Compact>
</Form.Item>
</>
)}
</div>
)}
<Text type="secondary" style={{ fontSize: 12 }}>
{sslHintText}
</Text>
</div>
)}
</div>
);
}
if (resolvedNetworkConfig === "ssh") {
return (
<div style={{ ...modalInnerSectionStyle, padding: 14 }}>
<div
style={{
marginBottom: 8,
color: darkMode ? "#f5f7ff" : "#162033",
fontSize: 14,
fontWeight: 700,
}}
>
{t("connection.modal.network.ssh.title")}
</div>
<div style={{ ...modalMutedTextStyle, marginBottom: 14 }}>
{t("connection.modal.network.ssh.panelDescription")}
</div>
{!effectiveUseSSH ? (
<div
style={{
...modalMutedTextStyle,
padding: "10px 12px",
borderRadius: 12,
background: darkMode
? "rgba(255,255,255,0.03)"
: "rgba(16,24,40,0.04)",
}}
>
{t("connection.modal.network.ssh.disabledHint")}
</div>
) : (
<div style={tunnelSectionStyle}>
<div
style={{
display: "grid",
gridTemplateColumns: "minmax(0, 1fr) 120px",
gap: 16,
}}
>
<Form.Item
name="sshHost"
label={t("connection.modal.network.ssh.host")}
rules={[
{
required: useSSH,
message: t(
"connection.modal.network.ssh.hostRequired",
),
},
]}
style={{ flex: 1 }}
>
<Input
{...noAutoCapInputProps}
placeholder={t("connection.modal.example.or", {
first: "ssh.example.com",
second: "192.168.1.100",
})}
/>
</Form.Item>
<Form.Item
name="sshPort"
label={t("connection.modal.field.port.label")}
rules={[
{
required: useSSH,
message: t(
"connection.modal.network.ssh.portRequired",
),
},
]}
style={{ width: 100 }}
>
<InputNumber style={{ width: "100%" }} />
</Form.Item>
</div>
<div
style={{
display: "grid",
gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
gap: 16,
}}
>
<Form.Item
name="sshUser"
label={t("connection.modal.network.ssh.user")}
rules={[
{
required: useSSH,
message: t(
"connection.modal.network.ssh.userRequired",
),
},
]}
style={{ flex: 1 }}
>
<Input
{...noAutoCapInputProps}
placeholder={t("connection.modal.example", {
value: "root",
})}
/>
</Form.Item>
<Form.Item
name="sshPassword"
label={t("connection.modal.network.ssh.password")}
style={{ flex: 1 }}
>
<Input.Password
{...noAutoCapInputProps}
placeholder={getStoredSecretPlaceholder({
hasStoredSecret: initialValues?.hasSSHPassword,
emptyPlaceholder: t(
"connection.modal.field.password.placeholder",
),
retainedLabel: t(
"connection.modal.network.ssh.retained",
),
})}
/>
</Form.Item>
</div>
<Form.Item
label={t("connection.modal.network.ssh.keyPath")}
help={t("connection.modal.example", {
value: "/Users/name/.ssh/id_rsa",
})}
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item name="sshKeyPath" noStyle>
<Input
{...noAutoCapInputProps}
placeholder={t(
"connection.modal.network.ssh.keyPathPlaceholder",
)}
/>
</Form.Item>
<Button
onClick={handleSelectSSHKeyFile}
loading={selectingSSHKey}
>
{t("connection.modal.action.browse")}
</Button>
</Space.Compact>
</Form.Item>
{renderStoredSecretControls({
fieldName: "sshPassword",
clearKey: "sshPassword",
hasStoredSecret: initialValues?.hasSSHPassword,
clearLabel: t(
"connection.modal.network.ssh.clearPassword",
),
description: t(
"connection.modal.network.ssh.savedDescription",
),
})}
</div>
)}
</div>
);
}
if (resolvedNetworkConfig === "proxy") {
return (
<div style={{ ...modalInnerSectionStyle, padding: 14 }}>
<div
style={{
marginBottom: 8,
color: darkMode ? "#f5f7ff" : "#162033",
fontSize: 14,
fontWeight: 700,
}}
>
{t("connection.modal.network.proxy.title")}
</div>
<div style={{ ...modalMutedTextStyle, marginBottom: 14 }}>
{t("connection.modal.network.proxy.panelDescription")}
</div>
{!effectiveUseProxy ? (
<div
style={{
...modalMutedTextStyle,
padding: "10px 12px",
borderRadius: 12,
background: darkMode
? "rgba(255,255,255,0.03)"
: "rgba(16,24,40,0.04)",
}}
>
{t("connection.modal.network.proxy.disabledHint")}
</div>
) : (
<div style={tunnelSectionStyle}>
<Form.Item
name="proxyHost"
label={t("connection.modal.network.proxy.host")}
rules={[
{
required: useProxy,
message: t(
"connection.modal.network.proxy.hostRequired",
),
},
]}
>
<Input
{...noAutoCapInputProps}
placeholder={t("connection.modal.example.or", {
first: "127.0.0.1",
second: "proxy.company.com",
})}
/>
</Form.Item>
<div
style={{
display: "grid",
gridTemplateColumns: "minmax(0, 1fr) 120px",
gap: 16,
}}
>
<div style={{ display: "grid", gap: 8 }}>
<Text strong>
{t("connection.modal.network.proxy.type")}
</Text>
{renderChoiceCards({
fieldName: "proxyType",
value: String(proxyType),
minWidth: 150,
options: [
{
value: "socks5",
label: "SOCKS5",
description: t(
"connection.modal.network.proxy.socks5.description",
),
},
{
value: "http",
label: "HTTP CONNECT",
description: t(
"connection.modal.network.proxy.http.description",
),
},
],
})}
</div>
<Form.Item
name="proxyPort"
label={t("connection.modal.field.port.label")}
rules={[
{
required: useProxy,
message: t(
"connection.modal.network.proxy.portRequired",
),
},
]}
style={{ marginBottom: 0 }}
>
<InputNumber
style={{ width: "100%" }}
min={1}
max={65535}
/>
</Form.Item>
</div>
<div
style={{
display: "grid",
gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
gap: 16,
}}
>
<Form.Item
name="proxyUser"
label={t("connection.modal.network.proxy.user")}
style={{ flex: 1 }}
>
<Input
{...noAutoCapInputProps}
placeholder={t(
"connection.modal.network.proxy.noAuth",
)}
/>
</Form.Item>
<Form.Item
name="proxyPassword"
label={t(
"connection.modal.network.proxy.password",
)}
style={{ flex: 1 }}
>
<Input.Password
{...noAutoCapInputProps}
placeholder={getStoredSecretPlaceholder({
hasStoredSecret:
initialValues?.hasProxyPassword,
emptyPlaceholder: t(
"connection.modal.network.proxy.noAuth",
),
retainedLabel: t(
"connection.modal.network.proxy.retained",
),
})}
/>
</Form.Item>
</div>
{renderStoredSecretControls({
fieldName: "proxyPassword",
clearKey: "proxyPassword",
hasStoredSecret: initialValues?.hasProxyPassword,
clearLabel: t(
"connection.modal.network.proxy.clearPassword",
),
description: t(
"connection.modal.network.proxy.savedDescription",
),
})}
</div>
)}
</div>
);
}
return (
<div style={{ ...modalInnerSectionStyle, padding: 14 }}>
<div
style={{
marginBottom: 8,
color: darkMode ? "#f5f7ff" : "#162033",
fontSize: 14,
fontWeight: 700,
}}
>
{t("connection.modal.network.httpTunnel.title")}
</div>
<div style={{ ...modalMutedTextStyle, marginBottom: 14 }}>
{t(
"connection.modal.network.httpTunnel.panelDescription",
)}
</div>
{!effectiveUseHttpTunnel ? (
<div
style={{
...modalMutedTextStyle,
padding: "10px 12px",
borderRadius: 12,
background: darkMode
? "rgba(255,255,255,0.03)"
: "rgba(16,24,40,0.04)",
}}
>
{t("connection.modal.network.httpTunnel.disabledHint")}
</div>
) : (
<div style={tunnelSectionStyle}>
<div
style={{
display: "grid",
gridTemplateColumns: "minmax(0, 1fr) 120px",
gap: 16,
}}
>
<Form.Item
name="httpTunnelHost"
label={t(
"connection.modal.network.httpTunnel.host",
)}
rules={[
{
required: useHttpTunnel,
message: t(
"connection.modal.network.httpTunnel.hostRequired",
),
},
]}
style={{ flex: 1 }}
>
<Input
{...noAutoCapInputProps}
placeholder={t("connection.modal.example.or", {
first: "tunnel.company.com",
second: "127.0.0.1",
})}
/>
</Form.Item>
<Form.Item
name="httpTunnelPort"
label={t("connection.modal.field.port.label")}
rules={[
{
required: useHttpTunnel,
message: t(
"connection.modal.network.httpTunnel.portRequired",
),
},
]}
style={{ width: 120 }}
>
<InputNumber
style={{ width: "100%" }}
min={1}
max={65535}
/>
</Form.Item>
</div>
<div
style={{
display: "grid",
gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
gap: 16,
}}
>
<Form.Item
name="httpTunnelUser"
label={t(
"connection.modal.network.httpTunnel.user",
)}
style={{ flex: 1 }}
>
<Input
{...noAutoCapInputProps}
placeholder={t(
"connection.modal.network.proxy.noAuth",
)}
/>
</Form.Item>
<Form.Item
name="httpTunnelPassword"
label={t(
"connection.modal.network.httpTunnel.password",
)}
style={{ flex: 1 }}
>
<Input.Password
{...noAutoCapInputProps}
placeholder={getStoredSecretPlaceholder({
hasStoredSecret:
initialValues?.hasHttpTunnelPassword,
emptyPlaceholder: t(
"connection.modal.network.proxy.noAuth",
),
retainedLabel: t(
"connection.modal.network.httpTunnel.retained",
),
})}
/>
</Form.Item>
</div>
{renderStoredSecretControls({
fieldName: "httpTunnelPassword",
clearKey: "httpTunnelPassword",
hasStoredSecret: initialValues?.hasHttpTunnelPassword,
clearLabel: t(
"connection.modal.network.httpTunnel.clearPassword",
),
description: t(
"connection.modal.network.httpTunnel.savedDescription",
),
})}
<Text type="secondary" style={{ fontSize: 12 }}>
{t(
"connection.modal.network.httpTunnel.exclusiveHint",
)}
</Text>
</div>
)}
</div>
);
};
return (
<div style={modalInnerSectionStyle}>
<div
style={{
marginBottom: 12,
color: darkMode ? "#f5f7ff" : "#162033",
fontSize: 14,
fontWeight: 700,
}}
>
{t("connection.modal.network.title")}
</div>
<div style={{ ...modalMutedTextStyle, marginBottom: 16 }}>
{t("connection.modal.network.description")}
</div>
<div
style={{
display: "grid",
gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
gap: 12,
marginBottom: 16,
}}
>
{networkItems.map((item) => {
const active = item.key === resolvedNetworkConfig;
const activeColor = darkMode ? "#ffd666" : "#1677ff";
return (
<div
key={item.key}
role="button"
tabIndex={0}
onClick={() => setActiveNetworkConfig(item.key)}
onKeyDown={(event) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
setActiveNetworkConfig(item.key);
}
}}
style={{
...getConnectionOptionCardStyle(item.enabled),
borderColor: active
? darkMode
? "rgba(255,214,102,0.46)"
: "rgba(24,144,255,0.36)"
: "transparent",
background: active
? darkMode
? "linear-gradient(180deg, rgba(255,214,102,0.14) 0%, rgba(255,214,102,0.08) 100%)"
: "linear-gradient(180deg, rgba(24,144,255,0.12) 0%, rgba(24,144,255,0.06) 100%)"
: getConnectionOptionCardStyle(item.enabled)
.background,
boxShadow: active
? darkMode
? "0 0 0 1px rgba(255,214,102,0.18) inset, 0 12px 26px rgba(0,0,0,0.16)"
: "0 0 0 1px rgba(24,144,255,0.14) inset, 0 12px 22px rgba(24,144,255,0.10)"
: "none",
cursor: "pointer",
outline: "none",
}}
>
<div
style={{
display: "flex",
alignItems: "flex-start",
gap: 10,
}}
>
<div
style={{
width: 8,
height: 8,
marginTop: 8,
borderRadius: 999,
background: active ? activeColor : "transparent",
border: active
? "none"
: darkMode
? "1px solid rgba(255,255,255,0.12)"
: "1px solid rgba(16,24,40,0.12)",
flexShrink: 0,
}}
/>
<div
style={{
display: "flex",
alignItems: "flex-start",
gap: 10,
minWidth: 0,
flex: 1,
}}
>
<Form.Item
name={
item.key === "ssl"
? "useSSL"
: item.key === "ssh"
? "useSSH"
: item.key === "proxy"
? "useProxy"
: "useHttpTunnel"
}
valuePropName="checked"
noStyle
>
<Checkbox />
</Form.Item>
<div style={{ minWidth: 0, flex: 1 }}>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
gap: 8,
}}
>
<span
style={{
fontSize: 14,
fontWeight: 700,
color: darkMode ? "#f5f7ff" : "#162033",
}}
>
{item.title}
</span>
<div
style={{
display: "flex",
alignItems: "center",
gap: 8,
}}
>
{active && (
<span
style={{
padding: "2px 8px",
borderRadius: 999,
fontSize: 11,
fontWeight: 700,
color: activeColor,
background: darkMode
? "rgba(255,214,102,0.16)"
: "rgba(24,144,255,0.12)",
}}
>
{t(
"connection.modal.network.currentEditing",
)}
</span>
)}
<span
style={{
fontSize: 11,
fontWeight: 700,
color: item.enabled
? activeColor
: darkMode
? "rgba(255,255,255,0.38)"
: "rgba(16,24,40,0.36)",
}}
>
{item.enabled
? t("connection.modal.network.enabled")
: t(
"connection.modal.network.notEnabled",
)}
</span>
</div>
</div>
<div
style={{
marginTop: 4,
...modalMutedTextStyle,
color: active
? darkMode
? "rgba(255,255,255,0.72)"
: "rgba(22,32,51,0.68)"
: modalMutedTextStyle.color,
}}
>
{item.description}
</div>
</div>
</div>
</div>
</div>
);
})}
</div>
<div style={{ marginBottom: 16 }}>{renderNetworkPanel()}</div>
<div style={{ ...modalInnerSectionStyle, padding: 12 }}>
<div
style={{
marginBottom: 10,
color: darkMode ? "#f5f7ff" : "#162033",
fontSize: 13,
fontWeight: 700,
}}
>
{t("connection.modal.network.advanced.title")}
</div>
<Form.Item
name="timeout"
label={t("connection.modal.network.timeout.label")}
help={t("connection.modal.network.timeout.help")}
rules={[
{
type: "number",
min: 1,
max: 300,
message: t("connection.modal.network.timeout.range"),
},
]}
style={{ marginBottom: 0 }}
>
<InputNumber
style={{ width: "100%" }}
min={1}
max={300}
placeholder={t("connection.modal.example", {
value: "30",
})}
/>
</Form.Item>
<Form.Item
name="keepAliveEnabled"
valuePropName="checked"
help={t("connection.modal.network.keepAliveEnabled.help")}
style={{ marginTop: 12, marginBottom: 12 }}
>
<Checkbox>
{t("connection.modal.network.keepAliveEnabled.checkbox")}
</Checkbox>
</Form.Item>
<Form.Item
name="keepAliveIntervalMinutes"
label={t("connection.modal.network.keepAliveInterval.label")}
help={t("connection.modal.network.keepAliveInterval.help")}
rules={[
{
type: "number",
min: MIN_KEEPALIVE_INTERVAL_MINUTES,
max: MAX_KEEPALIVE_INTERVAL_MINUTES,
message: t("connection.modal.network.keepAliveInterval.range"),
},
]}
style={{ marginBottom: 0 }}
>
<InputNumber
style={{ width: "100%" }}
min={MIN_KEEPALIVE_INTERVAL_MINUTES}
max={MAX_KEEPALIVE_INTERVAL_MINUTES}
disabled={!keepAliveEnabled}
placeholder={t("connection.modal.example", {
value: String(DEFAULT_KEEPALIVE_INTERVAL_MINUTES),
})}
/>
</Form.Item>
</div>
</div>
);
};
export default ConnectionModalNetworkSecuritySection;