Skip to content

Commit 0199ea8

Browse files
Add support for peer approval (#299)
* add support for peer approval * use gold color for tag --------- Co-authored-by: Maycon Santos <[email protected]>
1 parent a208940 commit 0199ea8

File tree

5 files changed

+139
-6
lines changed

5 files changed

+139
-6
lines changed

src/store/account/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ export interface Account {
88
jwt_groups_enabled: boolean;
99
groups_propagation_enabled: boolean;
1010
jwt_groups_claim_name: string;
11+
extra: {
12+
peer_approval_enabled: boolean;
13+
}
1114
};
1215
}
1316

@@ -17,4 +20,5 @@ export interface FormAccount extends Account {
1720
groups_propagation_enabled: boolean;
1821
jwt_groups_claim_name: string;
1922
peer_login_expiration_formatted: ExpiresInValue;
23+
peer_approval_enabled: boolean;
2024
}

src/store/peer/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ export interface Peer {
1616
dns_label: string,
1717
last_login: string,
1818
login_expired: boolean,
19-
login_expiration_enabled: boolean
19+
login_expiration_enabled: boolean,
20+
approval_required: boolean
2021
}
2122

2223
export interface FormPeer extends Peer {

src/views/Activity.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,8 @@ export const Activity = () => {
338338
case "peer.login.expiration.enable":
339339
case "user.peer.login":
340340
case "peer.login.expire":
341+
case "peer.approve":
342+
case "peer.approval.revoke":
341343
return renderMultiRowSpan(event.meta.fqdn, event.meta.ip);
342344
case "route.add":
343345
case "route.delete":
@@ -387,6 +389,8 @@ export const Activity = () => {
387389
case "account.setting.peer.login.expiration.enable":
388390
case "account.setting.peer.login.expiration.disable":
389391
case "account.setting.peer.login.expiration.update":
392+
case "account.setting.peer.approval.enable":
393+
case "account.setting.peer.approval.disable":
390394
case "integration.create":
391395
case "integration.update":
392396
case "integration.delete":

src/views/Peers.tsx

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useEffect, useState } from "react";
2-
import { capitalize, formatOS, timeAgo } from "../utils/common";
2+
import {capitalize, formatOS, isLocalDev, isNetBirdHosted, timeAgo} from "../utils/common";
33
import { useDispatch, useSelector } from "react-redux";
44
import { RootState } from "typesafe-actions";
55
import { actions as peerActions } from "../store/peer";
@@ -79,6 +79,7 @@ export const Peers = () => {
7979
(state: RootState) => state.peer.updateGroupsVisible
8080
);
8181
const users = useSelector((state: RootState) => state.user.data);
82+
const account = useSelector((state: RootState) => state.account.data);
8283
const [addPeerModalOpen, setAddPeerModalOpen] = useState(false);
8384
const { oidcUser } = useOidcUser();
8485
const [isAdmin, setIsAdmin] = useState(false);
@@ -100,6 +101,7 @@ export const Peers = () => {
100101
const optionsOnOff = [
101102
{ label: "Online", value: "on" },
102103
{ label: "All", value: "all" },
104+
// ...((isNetBirdHosted() || isLocalDev()) && account[0].settings.extra.peer_approval_enabled ? [{ label: "Needs approval", value: "approval" }] : []),
103105
];
104106

105107
const transformDataTable = (d: Peer[]): PeerDataTable[] => {
@@ -291,6 +293,16 @@ export const Peers = () => {
291293
);
292294
}) as Peer[];
293295

296+
// switch (optionOnOff) {
297+
// case "on":
298+
// f = filter(f, (f: Peer) => f.connected);
299+
// break;
300+
// case "approval":
301+
// f = filter(f, (f: Peer) => f.approval_required);
302+
// break;
303+
// default:
304+
// break;
305+
// }
294306
if (optionOnOff === "on") {
295307
f = filter(f, (f: Peer) => f.connected);
296308
}
@@ -410,6 +422,36 @@ export const Peers = () => {
410422
});
411423
};
412424

425+
const showConfirmApprove = (record: PeerDataTable) => {
426+
setPeerToAction(record);
427+
428+
let content = (
429+
<Paragraph>
430+
Are you sure you want to approve this peer?
431+
</Paragraph>
432+
);
433+
434+
let name = record ? record.name : "";
435+
confirmModal.confirm({
436+
icon: <ExclamationCircleOutlined />,
437+
title: <span className="font-500">Approve peer {name}</span>,
438+
width: 600,
439+
content: content,
440+
onOk() {
441+
record.approval_required = false
442+
dispatch(
443+
peerActions.updatePeer.request({
444+
getAccessTokenSilently: getTokenSilently,
445+
payload: record,
446+
})
447+
);
448+
},
449+
onCancel() {
450+
setPeerToAction(null);
451+
},
452+
});
453+
};
454+
413455
const showConfirmEnableSSH = (record: PeerDataTable) => {
414456
confirmModal.confirm({
415457
icon: <ExclamationCircleOutlined />,
@@ -601,6 +643,19 @@ export const Peers = () => {
601643
""
602644
);
603645

646+
let approval = peer.approval_required ? (
647+
<Tooltip title="The peer needs to be approved by an administrator before it can connect to other peers">
648+
<Tag color="gold">
649+
<Text
650+
style={{ fontSize: "10px", color: "rgba(212, 136, 6, 1)" }}
651+
type={"secondary"}
652+
>needs approval</Text>
653+
</Tag>
654+
</Tooltip>
655+
) : (
656+
""
657+
);
658+
604659
const userEmail = users?.find((u) => u.id === peer.user_id)?.email;
605660
let expiry = !peer.login_expiration_enabled ? (
606661
<Tag>
@@ -622,9 +677,9 @@ export const Peers = () => {
622677
<Row>
623678
<Text className="font-500"> {status}</Text>
624679
</Row>
625-
<Row>{loginExpire}</Row>
626680
</span>
627681
</Button>
682+
<Row>{loginExpire}</Row>
628683
</>
629684
);
630685
}
@@ -643,11 +698,18 @@ export const Peers = () => {
643698
<Row>
644699
<Text type="secondary">{userEmail}</Text>
645700
</Row>
646-
<Row style={{ minWidth: "195px" }}>
647-
{expiry} {loginExpire}
648-
</Row>
649701
</span>
650702
</Button>
703+
<Row style={{ minWidth: "195px", paddingLeft: "15px" }}>
704+
{expiry} {loginExpire} <Button
705+
type="text"
706+
style={{ height: "auto", whiteSpace: "normal", textAlign: "center", padding: "0px", margin: "0px" }}
707+
onClick={() => showConfirmApprove(peer)}
708+
className={!isAdmin ? "nohover" : ""}
709+
>
710+
{approval}
711+
</Button>
712+
</Row>
651713
</div>
652714
);
653715
};

src/views/Settings.tsx

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ export const Settings = () => {
127127

128128
const [formPeerExpirationEnabled, setFormPeerExpirationEnabled] =
129129
useState(true);
130+
const [formPeerApprovalEnabled, setFormPeerApprovalEnabled] =
131+
useState(false);
130132
const [jwtGroupsEnabled, setJwtGroupsEnabled] = useState(true);
131133
const [groupsPropagationEnabled, setGroupsPropagationEnabled] =
132134
useState(true);
@@ -221,9 +223,11 @@ export const Settings = () => {
221223
jwt_groups_enabled: account.settings.jwt_groups_enabled,
222224
jwt_groups_claim_name: account.settings.jwt_groups_claim_name,
223225
groups_propagation_enabled: account.settings.groups_propagation_enabled,
226+
peer_approval_enabled: account.settings.extra ? account.settings.extra.peer_approval_enabled : false,
224227
} as FormAccount;
225228
setFormAccount(fAccount);
226229
setFormPeerExpirationEnabled(fAccount.peer_login_expiration_enabled);
230+
setFormPeerApprovalEnabled(fAccount.peer_approval_enabled);
227231
setJwtGroupsEnabled(fAccount.jwt_groups_enabled);
228232
setGroupsPropagationEnabled(fAccount.groups_propagation_enabled);
229233
setJwtGroupsClaimName(fAccount.jwt_groups_claim_name);
@@ -394,6 +398,7 @@ export const Settings = () => {
394398
updatedAccount.data.settings.jwt_groups_claim_name,
395399
groups_propagation_enabled:
396400
updatedAccount.data.settings.groups_propagation_enabled,
401+
peer_approval_enabled: updatedAccount.data.settings.extra.peer_approval_enabled
397402
} as FormAccount;
398403
setFormAccount(fAccount);
399404
} else if (updatedAccount.error) {
@@ -428,6 +433,7 @@ export const Settings = () => {
428433
jwt_groups_enabled: jwtGroupsEnabled,
429434
jwt_groups_claim_name: jwtGroupsClaimName,
430435
groups_propagation_enabled: groupsPropagationEnabled,
436+
peer_approval_enabled: formPeerApprovalEnabled,
431437
});
432438
})
433439
.catch((errorInfo) => {
@@ -453,6 +459,9 @@ export const Settings = () => {
453459
jwt_groups_enabled: jwtGroupsEnabled,
454460
jwt_groups_claim_name: jwtGroupsClaimName,
455461
groups_propagation_enabled: groupsPropagationEnabled,
462+
extra: {
463+
peer_approval_enabled: values.peer_approval_enabled
464+
}
456465
},
457466
} as Account;
458467
};
@@ -624,6 +633,59 @@ export const Settings = () => {
624633
<div className={groupsClicked ? "d-none" : ""}>
625634
<Row>
626635
<Col span={12}>
636+
{(isNetBirdHosted() || isLocalDev()) && <Form.Item name="peer_approval_enabled" label="">
637+
<div
638+
style={{
639+
display: "flex",
640+
gap: "15px",
641+
}}
642+
>
643+
<Switch
644+
onChange={(checked) => {
645+
setFormPeerApprovalEnabled(checked);
646+
}}
647+
size="small"
648+
checked={formPeerApprovalEnabled}
649+
/>
650+
<div>
651+
<label
652+
style={{
653+
color: "rgba(0, 0, 0, 0.88)",
654+
fontSize: "14px",
655+
fontWeight: "500",
656+
}}
657+
>
658+
Peer approval{" "}
659+
<Tooltip
660+
title="Peer approval requires that every newly added peer
661+
will require approval by an administrator before it can connect to other peers.
662+
You can approve peers in the peers tab."
663+
>
664+
<Text
665+
style={{
666+
marginLeft: "5px",
667+
fontSize: "14px",
668+
color: "#bdbdbe",
669+
}}
670+
type={"secondary"}
671+
>
672+
<QuestionCircleFilled />
673+
</Text>
674+
</Tooltip>
675+
</label>
676+
<Paragraph
677+
type={"secondary"}
678+
style={{
679+
marginTop: "-2",
680+
fontWeight: "400",
681+
marginBottom: "0",
682+
}}
683+
>
684+
Require peers to be approved by an administrator
685+
</Paragraph>
686+
</div>
687+
</div>
688+
</Form.Item>}
627689
<Form.Item name="peer_login_expiration_enabled" label="">
628690
<div
629691
style={{

0 commit comments

Comments
 (0)