Skip to content

Commit 07b6895

Browse files
authored
Sync SSH & RDP changes (#495)
1 parent 9e2e387 commit 07b6895

32 files changed

+1727
-273
lines changed

config.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@
1313
"dragQueryParams": "$NETBIRD_DRAG_QUERY_PARAMS",
1414
"hotjarTrackID": "$NETBIRD_HOTJAR_TRACK_ID",
1515
"googleAnalyticsID": "$NETBIRD_GOOGLE_ANALYTICS_ID",
16-
"googleTagManagerID": "$NETBIRD_GOOGLE_TAG_MANAGER_ID"
16+
"googleTagManagerID": "$NETBIRD_GOOGLE_TAG_MANAGER_ID",
17+
"wasmPath": "$NETBIRD_WASM_PATH"
1718
}

docker/init_react_envs.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,12 @@ export NETBIRD_GOOGLE_ANALYTICS_ID=${NETBIRD_GOOGLE_ANALYTICS_ID}
6161
export NETBIRD_GOOGLE_TAG_MANAGER_ID=${NETBIRD_GOOGLE_TAG_MANAGER_ID}
6262
export NETBIRD_TOKEN_SOURCE=${NETBIRD_TOKEN_SOURCE:-accessToken}
6363
export NETBIRD_DRAG_QUERY_PARAMS=${NETBIRD_DRAG_QUERY_PARAMS:-false}
64+
export NETBIRD_WASM_PATH=${NETBIRD_WASM_PATH:-https://pkgs.netbird.io/wasm/client}
6465

6566
echo "NetBird latest version: ${NETBIRD_LATEST_VERSION}"
6667

6768
# replace ENVs in the config
68-
ENV_STR="\$\$USE_AUTH0 \$\$AUTH_AUDIENCE \$\$AUTH_AUTHORITY \$\$AUTH_CLIENT_ID \$\$AUTH_CLIENT_SECRET \$\$AUTH_SUPPORTED_SCOPES \$\$NETBIRD_MGMT_API_ENDPOINT \$\$NETBIRD_MGMT_GRPC_API_ENDPOINT \$\$NETBIRD_HOTJAR_TRACK_ID \$\$NETBIRD_GOOGLE_ANALYTICS_ID \$\$NETBIRD_GOOGLE_TAG_MANAGER_ID \$\$AUTH_REDIRECT_URI \$\$AUTH_SILENT_REDIRECT_URI \$\$NETBIRD_TOKEN_SOURCE \$\$NETBIRD_DRAG_QUERY_PARAMS"
69+
ENV_STR="\$\$USE_AUTH0 \$\$AUTH_AUDIENCE \$\$AUTH_AUTHORITY \$\$AUTH_CLIENT_ID \$\$AUTH_CLIENT_SECRET \$\$AUTH_SUPPORTED_SCOPES \$\$NETBIRD_MGMT_API_ENDPOINT \$\$NETBIRD_MGMT_GRPC_API_ENDPOINT \$\$NETBIRD_HOTJAR_TRACK_ID \$\$NETBIRD_GOOGLE_ANALYTICS_ID \$\$NETBIRD_GOOGLE_TAG_MANAGER_ID \$\$AUTH_REDIRECT_URI \$\$AUTH_SILENT_REDIRECT_URI \$\$NETBIRD_TOKEN_SOURCE \$\$NETBIRD_DRAG_QUERY_PARAMS \$\$NETBIRD_WASM_PATH"
6970

7071
OIDC_TRUSTED_DOMAINS="/usr/share/nginx/html/OidcTrustedDomains.js"
7172
envsubst "$ENV_STR" < "$OIDC_TRUSTED_DOMAINS".tmpl > "$OIDC_TRUSTED_DOMAINS"

src/app/(dashboard)/network/page.tsx

Lines changed: 83 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
"use client";
22

33
import Breadcrumbs from "@components/Breadcrumbs";
4+
import Button from "@components/Button";
45
import Card from "@components/Card";
6+
import {
7+
DropdownMenu,
8+
DropdownMenuContent,
9+
DropdownMenuItem,
10+
DropdownMenuSeparator,
11+
DropdownMenuTrigger,
12+
} from "@components/DropdownMenu";
513
import FullTooltip from "@components/FullTooltip";
614
import InlineLink from "@components/InlineLink";
715
import Separator from "@components/Separator";
@@ -12,21 +20,25 @@ import { cn } from "@utils/helpers";
1220
import {
1321
ArrowUpRightIcon,
1422
HelpCircle,
23+
MoreVertical,
1524
PencilLineIcon,
1625
ServerIcon,
1726
ShieldCheckIcon,
1827
ShieldXIcon,
28+
Trash2,
1929
} from "lucide-react";
20-
import { useSearchParams } from "next/navigation";
30+
import { useRouter, useSearchParams } from "next/navigation";
2131
import React, { useMemo, useState } from "react";
2232
import { useSWRConfig } from "swr";
2333
import NetworkRoutesIcon from "@/assets/icons/NetworkRoutesIcon";
2434
import { usePermissions } from "@/contexts/PermissionsProvider";
2535
import { Network } from "@/interfaces/Network";
2636
import PageContainer from "@/layouts/PageContainer";
2737
import { NetworkInformationSquare } from "@/modules/networks/misc/NetworkInformationSquare";
28-
import NetworkModal from "@/modules/networks/NetworkModal";
29-
import { NetworkProvider } from "@/modules/networks/NetworkProvider";
38+
import {
39+
NetworkProvider,
40+
useNetworksContext,
41+
} from "@/modules/networks/NetworkProvider";
3042
import { ResourcesSection } from "@/modules/networks/resources/ResourcesSection";
3143
import { NetworkRoutingPeersSection } from "@/modules/networks/routing-peers/NetworkRoutingPeersSection";
3244

@@ -77,35 +89,24 @@ function NetworkOverview({ network }: Readonly<{ network: Network }>) {
7789

7890
<div className={"flex justify-between max-w-6xl"}>
7991
<div
80-
className={cn(
81-
"flex items-center",
82-
!network.description && "gap-2",
83-
)}
92+
className={"w-full lg:w-1/2 flex justify-between items-center"}
8493
>
85-
<NetworkInformationSquare
86-
name={network.name}
87-
active={isActive}
88-
size={"lg"}
89-
description={network.description}
90-
/>
91-
{permission.networks.update && (
92-
<button
93-
className={
94-
"flex items-center gap-2 dark:text-neutral-300 text-neutral-500 hover:text-neutral-100 transition-all hover:bg-nb-gray-800/60 py-2 px-3 rounded-md cursor-pointer"
95-
}
96-
onClick={() => setNetworkModal(true)}
97-
>
98-
<PencilLineIcon size={18} />
99-
</button>
100-
)}
101-
<NetworkModal
102-
open={networkModal}
103-
setOpen={setNetworkModal}
104-
onUpdated={() => {
105-
mutate(`/networks/${network.id}`);
106-
}}
107-
network={network}
108-
/>
94+
<div
95+
className={cn(
96+
"flex items-center w-full",
97+
!network.description && "gap-2",
98+
)}
99+
>
100+
<NetworkInformationSquare
101+
name={network.name}
102+
active={isActive}
103+
size={"lg"}
104+
description={network.description}
105+
/>
106+
</div>
107+
<NetworkProvider network={network}>
108+
<NetworkActions />
109+
</NetworkProvider>
109110
</div>
110111
</div>
111112

@@ -124,6 +125,56 @@ function NetworkOverview({ network }: Readonly<{ network: Network }>) {
124125
);
125126
}
126127

128+
function NetworkActions() {
129+
const { permission } = usePermissions();
130+
const { deleteNetwork, openEditNetworkModal, network } = useNetworksContext();
131+
const router = useRouter();
132+
133+
if (!network) return;
134+
135+
return (
136+
<DropdownMenu modal={false}>
137+
<DropdownMenuTrigger
138+
asChild={true}
139+
onClick={(e) => {
140+
e.stopPropagation();
141+
e.preventDefault();
142+
}}
143+
>
144+
<Button variant={"secondary"} className={"!px-3"}>
145+
<MoreVertical size={16} className={"shrink-0"} />
146+
</Button>
147+
</DropdownMenuTrigger>
148+
<DropdownMenuContent className="w-auto" align="end">
149+
<DropdownMenuItem
150+
onClick={() => openEditNetworkModal(network)}
151+
disabled={!permission.networks.update}
152+
>
153+
<div className={"flex gap-3 items-center"}>
154+
<PencilLineIcon size={14} className={"shrink-0"} />
155+
Rename
156+
</div>
157+
</DropdownMenuItem>
158+
159+
<DropdownMenuSeparator />
160+
161+
<DropdownMenuItem
162+
onClick={() =>
163+
deleteNetwork(network).then(() => router.push("/networks"))
164+
}
165+
variant={"danger"}
166+
disabled={!permission.networks.delete}
167+
>
168+
<div className={"flex gap-3 items-center"}>
169+
<Trash2 size={14} className={"shrink-0"} />
170+
Delete
171+
</div>
172+
</DropdownMenuItem>
173+
</DropdownMenuContent>
174+
</DropdownMenu>
175+
);
176+
}
177+
127178
function NetworkInformationCard({ network }: Readonly<{ network: Network }>) {
128179
const isHighlyAvailable = !!(
129180
network?.routing_peers_count && network?.routing_peers_count >= 2
@@ -154,7 +205,7 @@ function NetworkInformationCard({ network }: Readonly<{ network: Network }>) {
154205
const policyCount = network.policies?.length ?? 0;
155206

156207
return (
157-
<Card>
208+
<Card className={"w-full lg:w-1/2"}>
158209
<Card.List>
159210
<Card.ListItem
160211
tooltip={false}

src/app/(dashboard)/peer/page.tsx

Lines changed: 5 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import Breadcrumbs from "@components/Breadcrumbs";
44
import Button from "@components/Button";
55
import { Callout } from "@components/Callout";
66
import Card from "@components/Card";
7-
import FancyToggleSwitch from "@components/FancyToggleSwitch";
8-
import FullTooltip from "@components/FullTooltip";
97
import HelpText from "@components/HelpText";
108
import { Input } from "@components/Input";
119
import { Label } from "@components/Label";
@@ -38,12 +36,10 @@ import {
3836
FlagIcon,
3937
Globe,
4038
History,
41-
LockIcon,
4239
MapPin,
4340
MonitorSmartphoneIcon,
4441
NetworkIcon,
4542
PencilIcon,
46-
TerminalSquare,
4743
TimerResetIcon,
4844
} from "lucide-react";
4945
import { useRouter, useSearchParams } from "next/navigation";
@@ -66,6 +62,7 @@ import useGroupHelper from "@/modules/groups/useGroupHelper";
6662
import { AccessiblePeersSection } from "@/modules/peer/AccessiblePeersSection";
6763
import { PeerExpirationToggle } from "@/modules/peer/PeerExpirationToggle";
6864
import { PeerNetworkRoutesSection } from "@/modules/peer/PeerNetworkRoutesSection";
65+
import { PeerSSHToggle } from "@/modules/peer/PeerSSHToggle";
6966
import { RDPButton } from "@/modules/remote-access/rdp/RDPButton";
7067
import { SSHButton } from "@/modules/remote-access/ssh/SSHButton";
7168

@@ -83,9 +80,8 @@ export default function PeerPage() {
8380

8481
const peerKey = useMemo(() => {
8582
let id = peer?.id ?? "";
86-
let ssh = peer?.ssh_enabled ? "1" : "0";
8783
let expiration = peer?.login_expiration_enabled ? "1" : "0";
88-
return `${id}-${ssh}-${expiration}`;
84+
return `${id}-${expiration}`;
8985
}, [peer]);
9086

9187
if (isRestricted) {
@@ -107,7 +103,7 @@ export default function PeerPage() {
107103
);
108104

109105
return peer && !isLoading ? (
110-
<PeerProvider peer={peer} key={peerId}>
106+
<PeerProvider peer={peer} key={peerId} isPeerDetailPage={true}>
111107
<PeerOverview key={peerKey} />
112108
</PeerProvider>
113109
) : (
@@ -141,8 +137,7 @@ function PeerOverview() {
141137
const PeerGeneralInformation = () => {
142138
const router = useRouter();
143139
const { mutate } = useSWRConfig();
144-
const { peer, user, peerGroups, openSSHDialog, update } = usePeer();
145-
const [ssh, setSsh] = useState(peer.ssh_enabled);
140+
const { peer, user, peerGroups, update } = usePeer();
146141
const [name, setName] = useState(peer.name);
147142
const [showEditNameModal, setShowEditNameModal] = useState(false);
148143
const [loginExpiration, setLoginExpiration] = useState(
@@ -161,7 +156,6 @@ const PeerGeneralInformation = () => {
161156
* Detect if there are changes in the peer information, if there are changes, then enable the save button.
162157
*/
163158
const { hasChanges, updateRef: updateHasChangedRef } = useHasChanges([
164-
ssh,
165159
selectedGroups,
166160
loginExpiration,
167161
inactivityExpiration,
@@ -174,7 +168,6 @@ const PeerGeneralInformation = () => {
174168
if (permission.peers.update) {
175169
const updateRequest = update({
176170
name: newName ?? name,
177-
ssh,
178171
loginExpiration,
179172
inactivityExpiration,
180173
});
@@ -190,7 +183,6 @@ const PeerGeneralInformation = () => {
190183
mutate("/peers/" + peer.id);
191184
mutate("/groups");
192185
updateHasChangedRef([
193-
ssh,
194186
selectedGroups,
195187
loginExpiration,
196188
inactivityExpiration,
@@ -314,41 +306,7 @@ const PeerGeneralInformation = () => {
314306
)}
315307
</div>
316308

317-
<FullTooltip
318-
content={
319-
<div
320-
className={"flex gap-2 items-center !text-nb-gray-300 text-xs"}
321-
>
322-
<LockIcon size={14} />
323-
<span>
324-
{`You don't have the required permissions to update this
325-
setting.`}
326-
</span>
327-
</div>
328-
}
329-
interactive={false}
330-
className={"w-full block"}
331-
disabled={permission.peers.update}
332-
>
333-
<FancyToggleSwitch
334-
value={ssh}
335-
disabled={!permission.peers.update}
336-
onChange={(set) =>
337-
!set
338-
? setSsh(false)
339-
: openSSHDialog().then((confirm) => setSsh(confirm))
340-
}
341-
label={
342-
<>
343-
<TerminalSquare size={16} />
344-
SSH Access
345-
</>
346-
}
347-
helpText={
348-
"Enable the SSH server on this peer to access the machine via an secure shell."
349-
}
350-
/>
351-
</FullTooltip>
309+
<PeerSSHToggle />
352310

353311
{/* Remote Access Buttons */}
354312
<div>

src/app/(remote-access)/peer/rdp/page.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { notify } from "@components/Notification";
44
import FullScreenLoading from "@components/ui/FullScreenLoading";
55
import { IconCircleX } from "@tabler/icons-react";
66
import useFetchApi from "@utils/api";
7+
import { cn } from "@utils/helpers";
78
import { Loader2Icon } from "lucide-react";
89
import React, { useCallback, useEffect, useRef, useState } from "react";
910
import type { Peer } from "@/interfaces/Peer";
@@ -19,7 +20,6 @@ import {
1920
NetBirdStatus,
2021
useNetBirdClient,
2122
} from "@/modules/remote-access/useNetBirdClient";
22-
import { cn } from "@utils/helpers";
2323

2424
export default function RDPPage() {
2525
const { peerId } = useRDPQueryParams();
@@ -55,7 +55,7 @@ function RDPSession({ peer }: Props) {
5555

5656
useEffect(() => {
5757
document.title = `${peer.name} - ${peer.ip} - RDP`;
58-
}, []);
58+
}, [peer.ip, peer.name, connected, rdp]);
5959

6060
const sendErrorNotification = (title: string, message: string) => {
6161
notify({
@@ -104,6 +104,7 @@ function RDPSession({ peer }: Props) {
104104
port: credentials.port,
105105
username: credentials.username,
106106
password: credentials.password,
107+
domain: credentials.domain,
107108
width: window.innerWidth,
108109
height: window.innerHeight,
109110
});

src/app/(remote-access)/peer/ssh/page.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { PageNotFound } from "@components/ui/PageNotFound";
44
import useFetchApi, { ErrorResponse } from "@utils/api";
5+
import { isNativeSSHSupported } from "@utils/version";
56
import { CircleXIcon, InfoIcon, Loader2Icon } from "lucide-react";
67
import React, { useEffect, useRef } from "react";
78
import type { Peer } from "@/interfaces/Peer";
@@ -86,7 +87,8 @@ function SSHTerminal({ username, port, peer }: Props) {
8687
if (isSSHConnected || isSSHConnecting) return;
8788
connected.current = false;
8889
try {
89-
const rules = [`tcp/${port}`];
90+
const aclPort = isNativeSSHSupported(peer.version) ? "22022" : port;
91+
const rules = [`tcp/${aclPort}`];
9092
await client?.connectTemporary(peer.id, rules);
9193
await ssh({
9294
hostname: peer.ip,
@@ -107,7 +109,8 @@ function SSHTerminal({ username, port, peer }: Props) {
107109
if (connected.current) return;
108110
connected.current = true;
109111
try {
110-
const rules = [`tcp/${port}`];
112+
const aclPort = isNativeSSHSupported(peer.version) ? "22022" : port;
113+
const rules = [`tcp/${aclPort}`];
111114
await client?.connectTemporary(peer.id, rules);
112115
const res = await ssh({
113116
hostname: peer.ip,

src/assets/ssh/ssh-client.png

290 KB
Loading

src/components/PeerGroupSelector.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ export function PeerGroupSelector({
309309
"flex items-center gap-2 border-nb-gray-700 flex-wrap h-full"
310310
}
311311
>
312-
{resource && showResources && (
312+
{resource && (
313313
<ResourceBadge
314314
className={"py-[3px]"}
315315
resource={resources?.find((r) => r.id === resource.id)}

0 commit comments

Comments
 (0)