Compare commits

...
6 Commits
Author SHA1 Message Date
Misha Bragin 63ced3088a Add public installation page (#248) 2023-07-31 20:21:15 +02:00
Misha Bragin 42b7a15466 Drag custom query params to auth layer (e.g., utm_source) (#244) 2023-07-31 15:16:51 +02:00
Sarooj bukhari c88bfa6476 Add filter by groups in peer (#243) 2023-07-24 17:45:53 +02:00
Maycon Santos c4138a8c45 fix one-off key creation 2023-07-21 20:18:59 +02:00
Sarooj bukhari 3f5418bebc Bug/remove group duplication on select view (#241)
* remove duplicate group on select view to change the logic from name to id

* fix group bug and add grouping on DNS

* fix setup key issue
2023-07-21 19:46:22 +02:00
Maycon Santos f60605e5e3 Allow unset audience (#240)
by setting the AUTH_AUDIENCE=none we will unset the audience value,

not passing that to the requests

This is required for the jumpcloud support
2023-07-21 19:45:37 +02:00
22 changed files with 196 additions and 77 deletions

No files matched your search

+6 -1
View File
@@ -22,6 +22,10 @@ if [[ -z "${AUTH_AUDIENCE}" ]]; then
fi
fi
if [[ "${AUTH_AUDIENCE}" == "none" ]]; then
unset AUTH_AUDIENCE
fi
if [[ -z "${AUTH_SUPPORTED_SCOPES}" ]]; then
if [[ -z "${AUTH0_DOMAIN}" ]]; then
echo "AUTH_SUPPORTED_SCOPES environment variable must be set"
@@ -54,11 +58,12 @@ export NETBIRD_MGMT_API_ENDPOINT=$(echo $NETBIRD_MGMT_API_ENDPOINT | sed -E 's/(
export NETBIRD_MGMT_GRPC_API_ENDPOINT=${NETBIRD_MGMT_GRPC_API_ENDPOINT}
export NETBIRD_HOTJAR_TRACK_ID=${NETBIRD_HOTJAR_TRACK_ID}
export NETBIRD_TOKEN_SOURCE=${NETBIRD_TOKEN_SOURCE:-accessToken}
export NETBIRD_DRAG_QUERY_PARAMS=${NETBIRD_DRAG_QUERY_PARAMS:-false}
echo "NetBird latest version: ${NETBIRD_LATEST_VERSION}"
# replace ENVs in the config
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 \$\$AUTH_REDIRECT_URI \$\$AUTH_SILENT_REDIRECT_URI \$\$NETBIRD_TOKEN_SOURCE"
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 \$\$AUTH_REDIRECT_URI \$\$AUTH_SILENT_REDIRECT_URI \$\$NETBIRD_TOKEN_SOURCE \$\$NETBIRD_DRAG_QUERY_PARAMS"
MAIN_JS=$(find /usr/share/nginx/html/static/js/main.*js)
OIDC_TRUSTED_DOMAINS="/usr/share/nginx/html/OidcTrustedDomains.js"
+1 -12
View File
@@ -70,16 +70,7 @@ function App() {
return (
<>
<ConfigProvider
theme={{
token: {
borderRadius: 4,
colorPrimary: "#1890ff",
fontFamily: "Arial"
},
components: {Badge: {fontSizeSM: 20}},
}}
>
<Provider store={store}>
{!show && <SecureLoading padding="3em" width={50} height={50}/>}
{show &&
@@ -124,8 +115,6 @@ function App() {
</Layout>
}
</Provider>
</ConfigProvider>
</>
)
}
+2 -2
View File
@@ -630,7 +630,7 @@ const AccessControlEdit = () => {
value={m.id}
serchValue={m.name}
>
{optionRender(m.name)}
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
@@ -790,7 +790,7 @@ const AccessControlEdit = () => {
value={m.id}
serchValue={m.name}
>
{optionRender(m.name)}
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
+2 -2
View File
@@ -577,7 +577,7 @@ const AccessControlNew = () => {
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
@@ -733,7 +733,7 @@ const AccessControlNew = () => {
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
+1 -1
View File
@@ -751,7 +751,7 @@ const NameServerGroupAdd = () => {
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
+1 -1
View File
@@ -749,7 +749,7 @@ const NameServerGroupUpdate = () => {
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
+1 -1
View File
@@ -908,7 +908,7 @@ const PeerUpdate = () => {
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
+1 -1
View File
@@ -736,7 +736,7 @@ const RouteAddNew = (selectedPeer: any) => {
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
+1 -1
View File
@@ -481,7 +481,7 @@ const RoutePeerUpdate = () => {
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
+1 -1
View File
@@ -479,7 +479,7 @@ const RouteAddNew = () => {
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
+1 -1
View File
@@ -400,7 +400,7 @@ const SetupKeyNew = () => {
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
+16 -12
View File
@@ -70,13 +70,15 @@ const SetupKeyNew = () => {
const createSetupKeyToSave = (): SetupKeyToSave => {
let [existingGroups, groupsToCreate] = getExistingAndToCreateGroupsLists(
formSetupKey.autoGroupNames
formSetupKey.autoGroupNames || []
);
const expiresIn = formSetupKey.expires_in * 24 * 3600; // the api expects seconds we have days
const expiresIn = formSetupKey.expires_in
? formSetupKey.expires_in * 24 * 3600
: 7 * 24 * 3600; // the api expects seconds we have days
return {
id: formSetupKey.id,
name: formSetupKey.name,
type: formSetupKey.type,
type: formSetupKey.type ? formSetupKey.type : "one-off",
auto_groups: existingGroups,
revoked: formSetupKey.revoked,
groupsToCreate: groupsToCreate,
@@ -147,7 +149,7 @@ const SetupKeyNew = () => {
type: "one-off",
key: "",
last_used: "",
expires: "",
expires: "7",
state: "valid",
auto_groups: [] as string[],
usage_limit: 0,
@@ -218,25 +220,27 @@ const SetupKeyNew = () => {
);
const changesDetected = (): boolean => {
console.log("formSetupKey", formSetupKey);
return (
formSetupKey.name == null ||
formSetupKey.name !== setupKey.name ||
groupsChanged() ||
formSetupKey.usage_limit !== setupKey.usage_limit
formSetupKey?.usage_limit !== setupKey.usage_limit
);
};
const groupsChanged = (): boolean => {
console.log("groupsChanged", formSetupKey);
if (
setupKey &&
setupKey.auto_groups &&
formSetupKey.autoGroupNames.length !== setupKey.auto_groups.length
setupKey?.auto_groups &&
formSetupKey?.autoGroupNames &&
formSetupKey?.autoGroupNames.length !== setupKey?.auto_groups.length
) {
return true;
}
const formGroupIds =
groups
?.filter((g) => formSetupKey.autoGroupNames.includes(g.name))
?.filter((g) => formSetupKey?.autoGroupNames.includes(g.name))
.map((g) => g.id || "") || [];
return (
@@ -281,7 +285,7 @@ const SetupKeyNew = () => {
fontSize: "14px",
borderRadius: "2px",
}}
disabled={savedSetupKey.loading || !changesDetected()}
disabled={savedSetupKey.loading || !!!formSetupKey.name}
onClick={handleFormSubmit}
>
Create key
@@ -342,6 +346,7 @@ const SetupKeyNew = () => {
onValuesChange={onChange}
initialValues={{
usage_limit: 1,
expires_in: "7",
}}
>
<Row>
@@ -496,7 +501,6 @@ const SetupKeyNew = () => {
<Form.Item
style={{ marginTop: "5px", marginBottom: 0 }}
name="autoGroupNames"
rules={[{ validator: selectValidator }]}
>
<Select
mode="tags"
@@ -510,7 +514,7 @@ const SetupKeyNew = () => {
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
+1 -1
View File
@@ -425,7 +425,7 @@ const UserEdit = () => {
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
+1 -1
View File
@@ -336,7 +336,7 @@ const InviteUserPopup = () => {
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
+2 -1
View File
@@ -11,5 +11,6 @@
"hotjarTrackID": "$NETBIRD_HOTJAR_TRACK_ID",
"redirectURI": "$AUTH_REDIRECT_URI",
"silentRedirectURI": "$AUTH_SILENT_REDIRECT_URI",
"tokenSource": "$NETBIRD_TOKEN_SOURCE"
"tokenSource": "$NETBIRD_TOKEN_SOURCE",
"dragQueryParams": "$NETBIRD_DRAG_QUERY_PARAMS"
}
+2
View File
@@ -39,5 +39,7 @@ export function getConfig() {
redirectURI: redirectURI,
silentRedirectURI: silentRedirectURI,
tokenSource: tokenSource,
// drags all the query params to the auth layer specified in the URL when accessing dashboard.
dragQueryParams: configJson.dragQueryParams == "true"
};
}
+14 -2
View File
@@ -474,6 +474,18 @@ ul.ant-list-items {
min-height: 300px;
}
.route-form.edit-form-wrapper .ant-form-item{
margin-bottom: 39px;
.route-form.edit-form-wrapper .ant-form-item {
margin-bottom: 39px;
}
.groupsSelect {
max-width: 200px;
width: 100%;
}
@media (max-width: 1220px) {
.groupsSelect{
margin-left: 0;
margin-top: 15px;
}
}
+44 -4
View File
@@ -10,6 +10,8 @@ import {BrowserRouter} from "react-router-dom";
import Loading from "./components/Loading";
import LoginError from "./components/LoginError";
import {AuthorityConfiguration} from "@axa-fr/react-oidc/dist/vanilla/oidc";
import InstallPage from "./views/Install";
import {ConfigProvider} from "antd";
const config = getConfig();
@@ -17,12 +19,29 @@ const config = getConfig();
// is required for doing logout. Therefore, we need to hardcode the config for auth
const auth0AuthorityConfig: AuthorityConfiguration = {
authorization_endpoint: new URL("authorize", config.authority).href,
token_endpoint: new URL("oauth/token", config.authority).href,
token_endpoint: new URL("oauth/token", config.authority).href,
revocation_endpoint: new URL("oauth/revoke", config.authority).href,
end_session_endpoint: new URL("v2/logout", config.authority).href,
userinfo_endpoint: new URL("userinfo", config.authority).href,
} as AuthorityConfiguration
const buildExtras = (config: any) => {
type Extras = { [key: string]: string }
let extras: Extras = {};
if (config.dragQueryParams) {
const searchParams = new URLSearchParams(window.location.search);
searchParams.forEach((value, key) => {
extras[key] = value
});
}
if (config.audience) {
extras.audience = config.audience
}
return extras
}
const providerConfig = {
authority: config.authority,
client_id: config.clientId,
@@ -34,7 +53,7 @@ const providerConfig = {
// service_worker_relative_url:'/OidcServiceWorker.js',
service_worker_only: false,
authority_configuration: config.auth0Auth ? auth0AuthorityConfig : undefined,
...(config.audience ? {extras: {audience: config.audience}} : null),
extras: buildExtras(config),
...(config.clientSecret ? {token_request_extras: {client_secret: config.clientSecret}} : null)
};
@@ -44,8 +63,14 @@ const root = ReactDOM.createRoot(
const loadingComponent = () => <Loading padding="3em" width={50} height={50}/>
root.render(
<OidcProvider
const showApp = () => {
if (window.location.pathname === "/install") {
// We bypass authentication for pages that do not require auth.
// E.g., when we just want to show installation steps for public.
return <InstallPage/>
}
return <OidcProvider
configuration={providerConfig}
callbackSuccessComponent={loadingComponent}
authenticatingErrorComponent={LoginError}
@@ -60,6 +85,21 @@ root.render(
<App/>
</BrowserRouter>
</OidcProvider>
}
root.render(
<ConfigProvider
theme={{
token: {
borderRadius: 4,
colorPrimary: "#1890ff",
fontFamily: "Arial"
},
components: {Badge: {fontSizeSM: 20}},
}}
>
{showApp()}
</ConfigProvider>
);
// If you want to start measuring performance in your app, pass a function
+4 -4
View File
@@ -18,7 +18,7 @@ export const useGetGroupTagHelpers = () => {
return tagRender(props, "");
};
const tagRender = (props: CustomTagProps, color: string) => {
const tagRender = (props: CustomTagProps, color: string) => {
const { value, closable, onClose } = props;
const onPreventMouseDown = (event: React.MouseEvent<HTMLSpanElement>) => {
event.preventDefault();
@@ -77,9 +77,9 @@ export const useGetGroupTagHelpers = () => {
</>
);
const optionRender = (label: string) => {
const optionRender = (label: string, id: any) => {
let peersCount = "";
const g = groups.find((_g) => _g.name === label);
const g = groups.find((_g) => _g.id === id);
if (g)
peersCount = ` - ${g.peers_count || 0} ${
!g.peers_count || parseInt(g.peers_count) !== 1 ? "peers" : "peer"
@@ -110,7 +110,7 @@ export const useGetGroupTagHelpers = () => {
return [groupIDList, groupNameListToCreate];
};
const getGroupNamesFromIDs = (groupIDList: string[]): string[] => {
const getGroupNamesFromIDs = (groupIDList: string[]): string[] => {
if (!groupIDList) {
return [];
}
+8 -6
View File
@@ -11,6 +11,7 @@ import {
Select,
Space,
Typography,
SelectProps,
} from "antd";
import { useGetTokenSilently } from "../utils/token";
import { useGetGroupTagHelpers } from "../utils/groups";
@@ -20,7 +21,7 @@ import { actions as nsGroupActions } from "../store/nameservers";
const { Paragraph } = Typography;
const styleNotification = { marginTop: 85 };
const { Option } = Select;
export const DNSSettingsForm = () => {
const { getTokenSilently } = useGetTokenSilently();
const dispatch = useDispatch();
@@ -62,9 +63,7 @@ export const DNSSettingsForm = () => {
if (!dnsSettingsData) return;
dispatch(
dnsSettingsActions.setDNSSettings({
disabled_management_groups: getGroupNamesFromIDs(
dnsSettingsData.disabled_management_groups
),
disabled_management_groups: dnsSettingsData.disabled_management_groups,
})
);
}, [dnsSettingsData]);
@@ -217,9 +216,12 @@ export const DNSSettingsForm = () => {
tagRender={blueTagRender}
onChange={handleChangeTags}
dropdownRender={dropDownRender}
optionFilterProp="serchValue"
>
{tagGroups.map((m) => (
<Select.Option key={m}>{optionRender(m)}</Select.Option>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
</Form.Item>
Loaded 20 of 22 files, more files were not shown because too many files have changed in this diff. Show more