Compare commits

..
111 Commits
Author SHA1 Message Date
Misha Bragin ec40730cb2 Fix setup key layout (#172) 2023-05-08 17:49:27 +02:00
Misha Bragin 7f3648861b Fix popups layout (#171) 2023-05-08 12:30:53 +02:00
Crusadero b50464db43 Setup keys screen (#167) 2023-05-07 18:39:28 +02:00
pascal-fischer 1eb5ccc131 displaying proper groups and name on route peer update (#169) 2023-05-05 15:50:39 +02:00
pascal-fischer ac42a17b11 remove unnecessary oidc user check from users page (#166) 2023-04-27 13:28:50 +02:00
pascal-fischer 77ca3c6fde Adding service user support and new user overview (#164)
Changes:
user tab was split in service users and regular users
user edit view was reworked:
shows PAT box for service users and self (hides for rest)
hides email and groups for service users as no usage
reverted settings tab to only contain account settings + hide for normal users
Use navbar avatar dropdown to link to users list and open user edit page for self
extend api-client to handle requests with query parameters
use popup form for PAT creation, user invite and service user creation
validate all form fields before trying to send API call and show faulty fields

Additional fixes:
groups popup was only visible after 2nd hover after tab switch on every view, fixed to also show on first hover
fix setup keys page throwing errors from time to time and not loading
peers view was sending getRoute requests that are only allowed for admins which was throwing errors (only console) for normal users -> disabled requests for non-admin users
2023-04-22 12:57:17 +02:00
pascal-fischer 20e24b4ede Fix Routes view when updating routes (#165)
* fix filter

* filter also for android

* fix masquerade Traffic button

* remove log
2023-04-21 13:07:54 +02:00
Misha Bragin 7a29dac01c Add single line installer command for Mac and Linux (#162) 2023-04-04 14:20:02 +02:00
pascal-fischer 444e9ec44a fetch userID from user list and not oidc by default (#161) 2023-04-03 16:52:42 +02:00
pascal-fischer dff0313f82 Feature/pat support (#157)
* Add working UI + API calls [missing token popup]

* use popup view to add new token

* show userID if user name not available

* switch from description to name

* show "Me" instead of own name

* removed created_by column

* update add token explanation

* use object instead of plain text for token create response

* some style changes

* disable information button for tokens

* last_used can contain nil

* fix delete popups

* lower case letters for dates

* add activity and fix visibility

* show settings tab for non admins

* remove spaces on top of setting tabs

* fix copy button size and position

* fix list footers

* continue merge changes to new files
2023-04-03 12:29:40 +02:00
Maycon Santos 11fbfb336a Clean last estimated name (#160) 2023-04-03 12:16:12 +02:00
Maycon Santos 4a0ae8f27d Add missing config change (#159) 2023-04-01 21:58:46 +02:00
Maycon Santos 9a72d8b0c4 Allow defining API token source (#158)
On many IDP providers, the access token
 is used to access the IDP's own API

 With these changes, we allow users to define the proper token to be used for
 management API calls
2023-04-01 19:44:28 +02:00
Misha Bragin 8e038cf242 Make table headers font-weight normal (#156) 2023-03-27 15:59:18 +02:00
Misha Bragin 5bd94eff56 Fix add peer popup tab layout on mobile (#154) 2023-03-23 12:10:27 +01:00
Misha Bragin 77f065b093 Update theme border radius (#152) 2023-03-22 16:56:36 +01:00
Misha Bragin a4d55cfb90 Fix settings modal styles (#151) 2023-03-22 16:14:49 +01:00
Misha Bragin cfd4c9075b Add onboarding steps (#150) 2023-03-22 15:21:52 +01:00
braginini 962180030a Fix activity docs link 2023-03-15 14:20:48 +01:00
Misha Bragin 485e1e8d79 Add more references to docs (#149) 2023-03-15 14:18:22 +01:00
Givi Khojanashvili b11007b29f Add policy add activities (#147)
Related changes for netbirdio/netbird#700
2023-03-13 10:58:34 +01:00
Maycon Santos bce75c1ca9 Disable banner (#146) 2023-03-02 15:55:31 +01:00
Maycon Santos 0c09992b38 Use user.is_current (#145)
prevent update for own user

use the is_current for label

removed unused imports
2023-03-01 22:50:26 +01:00
Maycon Santos 86b12f30d2 Use new windows release URL (#144)
removed latestVersion logic and environment support
2023-03-01 15:00:36 +01:00
Maycon Santos d3e34d8448 Use single page size helper with new larger values (#143)
Reduce duplicated code with single helper for pagination

On larger deployments we should allow for larger pages

fix popover key issue and vertical spacing

update deprecated keys
2023-02-28 16:32:12 +01:00
Misha Bragin 76083168f6 Log error when activity event is not handled (#142) 2023-02-28 11:22:40 +01:00
Misha Bragin a54b3687ae Display user in the user role update event (#141)
Handling of the "User role updated" event (user.role.update) 
was missing in the Activity tab.
2023-02-27 15:27:00 +01:00
Zoltan Papp 25f154dc83 Capitalize first letter of OS (#140) 2023-02-27 14:54:39 +01:00
pascal-fischer f3c7d877f8 Add additional step in the Mac installation instructions to start the daemon (#138) 2023-02-22 20:55:36 +01:00
Misha Bragin 7cea7e7f54 Format individual peer login expiration event (#139)
Events peer.login.expiration.disable and peer.login.expiration.enable
are handled in the Activity tab now and properly displayed.
2023-02-22 20:54:56 +01:00
Misha Bragin aaa351635f Add peer expiration setting confirmation modal (#137)
Add a confirmation dialog to notify a user of possible
consequences of the peer login expiration enabling/disabling.
2023-02-21 08:47:14 +01:00
Misha Bragin 379ff5486e Account settings view (#136)
New Settings tab added to the dashboard.
It is possible to enable or disable peer login expiration globally for an account.
As well as defining the expiration time period.
2023-02-20 08:57:24 +01:00
Misha Bragin 8bcd9918e2 Fix expires in input filed of the setup key (#135) 2023-02-17 14:30:22 +01:00
Misha Bragin 044ccd0ce6 Display login expiration activities (#134) 2023-02-16 15:36:45 +01:00
braginini ab09ca3697 Display API error in peers view 2023-02-16 13:03:39 +01:00
Misha Bragin 1644ed5dce Add peer login expiration tooltip (#133) 2023-02-16 12:47:35 +01:00
Misha Bragin cea459792f Add peer login expiration (#132)
Display if peer login has expired in the Peers table
Enable/Disable peer login expiration
2023-02-16 12:18:15 +01:00
Maycon Santos a402680816 Disallow all crawlers and dashboard indexing (#131) 2023-02-10 18:45:11 +01:00
Givi Khojanashvili e57e5b726d Feat add custom id claim (#129)
* Fix management API endpoint ENV var. Format README.

* Add and use id_current user flag

* Use mix of the new and old methods to detect current user.
2023-02-03 21:48:03 +01:00
Misha Bragin 2c4ada0ad8 Use peerID in the Routes view (#130)
Relates to the netbirdio/netbird PR
Use Peer.ID instead of Peer.Key as peer identifier (#664)
2023-02-03 10:34:43 +01:00
Misha Bragin 8195587c85 Handle additional activity events (#128) 2023-01-31 13:56:46 +01:00
Maycon Santos adf6e1e71f Use ID token payload when oidcUser is nil (#127)
With some IDPs like MS Azure the
oidcUser is not being set, so we can fallback to id token
to validate UI and current user
2023-01-24 09:10:14 +01:00
Maycon Santos b733a186ae Remove console.log in peers page (#125) 2023-01-19 14:55:42 +01:00
Maycon Santos 5d901470c2 Feature/dns settings (#126)
Add DNS settings view to the DNS tab.

Split the page into sub-tabs for Nameservers and DNS settings

Added API calls to the new DNS settings API
2023-01-18 18:12:29 +01:00
Misha Bragin 29ab28847d Add Events view (#119) 2023-01-02 17:29:11 +01:00
Maycon Santos 0361825e04 Add peer's last seem time on popover (#122) 2022-12-16 19:37:10 +01:00
Moath Qasim 2fa33ec06a Fix MacOS custom netbird up command (#121) 2022-12-11 18:54:48 +01:00
Maycon Santos c677eeaae4 Add distribution groups to Network routes (#118)
Users can add distribution groups to network routes

Groups can be added to individual network routes or to all routes in the group

Adding a new group in the modal is restricted to individual network route operations
2022-12-08 17:24:34 +01:00
Maycon Santos 7fb4b0b145 Update actions versions (#120) 2022-12-08 13:22:07 +01:00
dependabot[bot] 57f60a2fbf Bump loader-utils from 2.0.2 to 2.0.4 (#109)
Bumps [loader-utils](https://github.com/webpack/loader-utils) from 2.0.2 to 2.0.4.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v2.0.4/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v2.0.2...v2.0.4)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-08 12:06:54 +01:00
dependabot[bot] ec949da416 Bump minimatch and recursive-readdir (#106)
Bumps [minimatch](https://github.com/isaacs/minimatch) and [recursive-readdir](https://github.com/jergason/recursive-readdir). These dependencies needed to be updated together.

Updates `minimatch` from 3.0.4 to 3.1.2
- [Release notes](https://github.com/isaacs/minimatch/releases)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.0.4...v3.1.2)

Updates `recursive-readdir` from 2.2.2 to 2.2.3
- [Release notes](https://github.com/jergason/recursive-readdir/releases)
- [Changelog](https://github.com/jergason/recursive-readdir/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jergason/recursive-readdir/commits/v2.2.3)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-type: indirect
- dependency-name: recursive-readdir
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-08 12:06:28 +01:00
Misha Bragin 43710b8ada Add SetupKey usage limit (#117) 2022-12-05 13:10:21 +01:00
Maycon Santos 247665a846 Call users API on empty state (#116)
Validate if the users state is empty and issue a GET call to /api/users

We check if the call was issued and if not on tabs that already does such a call
2022-11-27 16:33:27 +01:00
Maycon Santos 010657c594 Fix DNS validations (#115)
Check if domains is not empty when primary is false

Validate domain and primary fields before submit

Display validation errors as message too

Reload groups on failure too

Display API call error

Added call to action message when nameserver is empty
2022-11-27 13:15:55 +01:00
Misha Bragin 2d911af97f Add DNS feature announcement (#114) 2022-11-25 18:37:55 +01:00
Misha Bragin afdfed0160 Filter peers by groups (#113) 2022-11-25 18:26:00 +01:00
Misha Bragin 6b86da3716 Copy IP or DNS on the peers tab (#112)
Copy Peer IP or DNS in the Address column in Peers table
2022-11-25 17:23:35 +01:00
Maycon Santos 425fac8e9c DNS (#101)
Added DNS tab for managing Nameservers.
Users will be able to add multiple nameservers 
and set distribution groups that dictate to which peers the settings will be applied.
With this PR we also got a set of group handlers that can be reused.
2022-11-25 15:55:26 +01:00
Misha Bragin fa2413f937 Add FQDN of a peer to the peers table (#111) 2022-11-21 11:27:13 +01:00
Misha Bragin feec057933 Don't show admin content to users with a "user" role (#108) 2022-11-15 17:58:06 +01:00
Enrico Renna 9127686df7 fix: apt-key deprecation warning/errors (#107) 2022-11-15 09:12:13 +01:00
Maycon Santos 479911ded8 Check for change in any field (#104)
* Check for change in any field

Name should not be required, specially for self-hosted

* proper email change validation
2022-11-12 15:29:16 +01:00
Misha Bragin 69dcd6fadd Handle Management API errors (#103) 2022-11-10 16:30:16 +01:00
Misha Bragin 0b7b34b490 Handle Forbidden Errors coming from management (#100) 2022-11-05 08:41:55 +01:00
braginini fff93a3820 Improve spacing on email verification screen. 2022-10-27 09:50:58 +02:00
braginini da21784c73 Improve email verification window messaging 2022-10-27 09:40:57 +02:00
braginini 2e03a39b3e Add user invites banner 2022-10-20 12:01:52 +02:00
Maycon Santos 8e626cdd96 Revert "bump @axa-fr/react-oidc to 6.9 to fix atob padding bug (#97)" (#99)
This reverts commit 957ff98cec.
2022-10-18 17:48:30 +02:00
braginini 472704ad59 Merge remote-tracking branch 'origin/main' 2022-10-18 11:49:53 +02:00
braginini 94c7288016 Enable invite logic 2022-10-18 11:49:43 +02:00
Jens L 957ff98cec bump @axa-fr/react-oidc to 6.9 to fix atob padding bug (#97)
* bump @axa-fr/react-oidc to 6.9 to fix atob padding bug

* add issuer to auth0AuthorityConfig
2022-10-17 23:54:21 +02:00
Jens L 80178f66c3 correctly handle JWTs without base64-padding (#96) 2022-10-15 17:34:40 +02:00
braginini 37324cbcfc Hide user invites feature 2022-10-14 11:42:21 +02:00
braginini 9dd362a8a4 Add wiretrustee.com domain to "hosted" variants 2022-10-13 18:27:52 +02:00
braginini 90605a2067 Enable invites only for the local or hosted version 2022-10-13 18:11:30 +02:00
Misha Bragin 18cfddbbe7 Support User Invites (#86)
This PR brings an "Invite User" button to the Users view
and a view to creating (inviting) a new user to the account.
This function calls the Management API POST /users
endpoint that creates a new user.
2022-10-13 18:01:32 +02:00
Maycon Santos 17e671200e Don't display announcement after user close it (#95)
We store the banner text as md5
and the state if user closed already
2022-10-13 17:45:51 +02:00
Maycon Santos bb94342cc8 Support custom redirect callback URIS (#92) 2022-10-12 12:25:55 +02:00
Misha Bragin b86cf8b99f Add setup key expiration property when creating new key (#90) 2022-10-06 17:03:09 +02:00
Maycon Santos f472c06cbf skip analytics on monitoring 2022-10-03 12:27:51 +05:00
Maycon Santos c58834309b Add hotjar integration (#89)
hotjar is only enabled if NETBIRD_HOTJAR_TRACK_ID is passed
2022-10-02 18:01:06 +05:00
Maycon Santos 75fdd3e17f Add new peer button and user message (#87) 2022-09-30 19:59:55 +02:00
braginini 568c5eccda Change tables key fields styling 2022-09-29 11:00:56 +02:00
braginini 363f226a1c Add me tag to the user view to identify the current user 2022-09-29 10:37:04 +02:00
braginini bf447b1ada Fix user role display when clicking view 2022-09-29 10:26:02 +02:00
Maycon Santos 90cb05bd2d Parse access token for validation and use latestToke global (#85) 2022-09-27 12:33:55 +02:00
Misha Bragin a98d6d9ce1 Display additional peer info (#84) 2022-09-26 18:40:06 +02:00
braginini f83e39d734 Fix deprecated fields warning 2022-09-23 15:05:34 +02:00
braginini 52c1909229 Fix package json 2022-09-23 15:02:23 +02:00
Misha Bragin f0d893c689 Support user role update (#82) 2022-09-23 14:21:59 +02:00
Misha Bragin c8339c4be1 Peers auto-tagging with users and predefined groups (#77) 2022-09-22 10:19:53 +02:00
Misha Bragin 954d697b5f Add Access Token hook to return valid token (#81) 2022-09-19 13:11:07 +02:00
Maycon Santos ace2bb61ef Fix popover for groups (#78)
* Fix popover for groups

Fixed all popover overlay when opening
update modal

also fixed group input size problem
 with peers update

* remove style display flex from form tittle
2022-09-15 22:24:20 +05:00
Misha Bragin f389862931 Support Auto Groups when updating setup keys (#75) 2022-09-13 17:51:05 +02:00
braginini 521df658ad Shorten the banner text 2022-09-13 11:01:19 +02:00
Maycon Santos 4db17c119a enable new route update 2022-09-08 10:51:36 +02:00
Maycon Santos 230a4cb05e Group network routes by identifier and range (#73)
* fix missing peer when disabling route

and passing peer to modal view

* group rows by HA routes

* Adjust high availability and show fields disabled

* add groupedRoutes to GroupedDataTable

* remove unused fields

* filter by grouped routes

* group routes by network id and network

* use better check for save button
2022-09-08 09:26:38 +02:00
braginini 06316239de Fix routes docs link 2022-09-05 19:45:14 +02:00
braginini 59eff85339 Fix routes docs link 2022-09-05 19:44:49 +02:00
braginini ffabdf8a1a Add new release banner 2022-09-05 19:09:43 +02:00
Maycon Santos 0fe5aa13b1 Rename Network range and enable masquerade by default (#72) 2022-09-05 16:13:01 +02:00
Maycon Santos 7166eb6e2f Network Routes page (#71)
Add Network routes page to interact with the routes API endpoint of our management
2022-09-05 09:08:51 +02:00
Misha Bragin c9f1955d6a Fix ACL modal groups input fields width (#69) 2022-08-22 15:27:52 +02:00
Misha Bragin c3236d05a1 Fix Auth0 OIDC integration 2022-08-17 20:38:52 +02:00
Misha Bragin 25e8a52465 Refactor to generic OIDC config (#66)
Cleans up config.json providing generic OIDC properties.
This allows for using other IDP providers besides Auth0.
The change is backward compatible with the previous versions.
2022-08-15 19:32:01 +02:00
Maycon Santos 2b26198741 As user to refresh page on 401 (#65)
* As user to refresh page on 401

* replace status code string
2022-08-04 20:42:16 +02:00
Maycon Santos 2b359b2140 Update dependencies to resolve issue with mobile (#64)
* Update dependencies to resolve issue with mobile

* ensure min rc-overflow fixes the issue with mobile
2022-08-03 16:48:24 +02:00
Maycon Santos d71d8214e7 Disable service worker (#63)
Service has caused some bugs where
the trust domains were ignored
and api calls were done without proper credentials
2022-08-03 09:44:46 +02:00
braginini 321e4d8311 Remove banner 2022-08-01 13:32:28 +02:00
Maycon Santos 224a889de3 Parse API URL when using default 443 and 80 ports (#62)
Init scripts will remove ports for replacement when the user
provided default HTTP and HTTPS ports.

This was causing issues with trusted domain logic from the OIDC library.
2022-07-27 11:09:45 +02:00
Maycon Santos b59865ae05 Replace Auth0 SDK with axa-fr/react-oidc (#60)
Replacing Auth0's SDK with a more generic implementation of an OIDC client.
This will allow us to use other IDP providers that follow the OIDC standards.
2022-07-26 16:13:08 +02:00
121 changed files with 30776 additions and 5244 deletions

No files matched your search

+8 -7
View File
@@ -5,15 +5,16 @@ on:
- main
tags:
- "**"
pull_request:
jobs:
build_n_push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: setup-node
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: '16'
cache: 'npm'
@@ -26,26 +27,26 @@ jobs:
run: CI=false npm run build
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
-
name: Docker meta
id: meta
uses: docker/metadata-action@v3
uses: docker/metadata-action@v4
with:
images: wiretrustee/dashboard
-
name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_TOKEN }}
-
name: Docker build and push
uses: docker/build-push-action@v2
uses: docker/build-push-action@v3
with:
context: .
file: docker/Dockerfile
+3
View File
@@ -2,6 +2,7 @@
# dependencies
/node_modules
/node_modules.bkp
/.pnp
.pnp.js
@@ -26,3 +27,5 @@ src/auth_config.json
.idea
.eslintcache
src/.local-config.json
/public/OidcServiceWorker.js
/public/OidcTrustedDomains.js
+28 -9
View File
@@ -36,24 +36,43 @@ Disclaimer. We believe that proper user management system is not a trivial task
use Auth0 service that covers all our needs (user management, social login, JTW for the management API).
Auth0 so far is the only 3rd party dependency that can't be really self-hosted.
1. install [Docker](https://docs.docker.com/get-docker/)
2. register [Auth0](https://auth0.com/) account
3. running Wiretrustee UI Dashboard requires the following Auth0 environmental variables to be set (see docker command below):
1. Install [Docker](https://docs.docker.com/get-docker/)
2. Register [Auth0](https://auth0.com/) account
3. Running Wiretrustee UI Dashboard requires the following Auth0 environmental variables to be set (see docker command below):
```AUTH0_DOMAIN``` ```AUTH0_CLIENT_ID``` ```AUTH0_AUDIENCE```
`AUTH0_DOMAIN` `AUTH0_CLIENT_ID` `AUTH0_AUDIENCE`
To obtain these, please use [Auth0 React SDK Guide](https://auth0.com/docs/quickstart/spa/react/01-login#configure-auth0) up until "Configure Allowed Web Origins"
4. Wiretrustee UI Dashboard uses Wiretrustee Management Service HTTP API, so setting ```WIRETRUSTEE_MGMT_API_ENDPOINT``` is required. Most likely it will be ```http://localhost:33071``` if you are hosting Management API on the same server.
4. Wiretrustee UI Dashboard uses Wiretrustee Management Service HTTP API, so setting `NETBIRD_MGMT_API_ENDPOINT` is required. Most likely it will be `http://localhost:33071` if you are hosting Management API on the same server.
5. Run docker container without SSL (Let's Encrypt):
```docker run -d --name wiretrustee-dashboard --rm -p 80:80 -p 443:443 -e AUTH0_DOMAIN=<SET YOUR AUTH DOMAIN> -e AUTH0_CLIENT_ID=<SET YOUR CLIENT ID> -e AUTH0_AUDIENCE=<SET YOUR AUDIENCE> -e WIRETRUSTEE_MGMT_API_ENDPOINT=<SET YOUR MANAGEMETN API URL> wiretrustee/dashboard:main```
```shell
docker run -d --name wiretrustee-dashboard \
--rm -p 80:80 -p 443:443 \
-e AUTH0_DOMAIN=<SET YOUR AUTH DOMAIN> \
-e AUTH0_CLIENT_ID=<SET YOUR CLIENT ID> \
-e AUTH0_AUDIENCE=<SET YOUR AUDIENCE> \
-e NETBIRD_MGMT_API_ENDPOINT=<SET YOUR MANAGEMETN API URL> \
wiretrustee/dashboard:main
```
6. Run docker container with SSL (Let's Encrypt):
```docker run -d --name wiretrustee-dashboard --rm -p 80:80 -p 443:443 -e NGINX_SSL_PORT=443 -e LETSENCRYPT_DOMAIN=<YOUR PUBLIC DOMAIN> -e LETSENCRYPT_EMAIL=<YOUR EMAIL> -e AUTH0_DOMAIN=<SET YOUR AUTH DOMAIN> -e AUTH0_CLIENT_ID=<SET YOUR CLEITN ID> -e AUTH0_AUDIENCE=<SET YOUR AUDIENCE> -e WIRETRUSTEE_MGMT_API_ENDPOINT=<SET YOUR MANAGEMETN API URL> wiretrustee/dashboard:main```
```shell
docker run -d --name wiretrustee-dashboard \
--rm -p 80:80 -p 443:443 \
-e NGINX_SSL_PORT=443 \
-e LETSENCRYPT_DOMAIN=<YOUR PUBLIC DOMAIN> \
-e LETSENCRYPT_EMAIL=<YOUR EMAIL> \
-e AUTH0_DOMAIN=<SET YOUR AUTH DOMAIN> \
-e AUTH0_CLIENT_ID=<SET YOUR CLEITN ID> \
-e AUTH0_AUDIENCE=<SET YOUR AUDIENCE> \
-e NETBIRD_MGMT_API_ENDPOINT=<SET YOUR MANAGEMETN API URL> \
wiretrustee/dashboard:main
```
## How to run local development
1. Install node 16
2. create and update the src/.local-config.json file. This file should contain values to be replaced from src/config.json
2. create and update the `src/.local-config.json` file. This file should contain values to be replaced from `src/config.json`
3. run `npm install`
4. run `npm run start dev`
4. run `npm run start dev`
+46 -22
View File
@@ -1,19 +1,39 @@
#!/bin/bash
set -e
if [[ -z "${AUTH0_DOMAIN}" ]]; then
echo "AUTH0_DOMAIN environment variable must be set"
exit 1
if [[ -z "${AUTH_AUTHORITY}" ]]; then
if [[ -z "${AUTH0_DOMAIN}" ]]; then
echo "AUTH_AUTHORITY or AUTH0_DOMAIN environment variable must be set"
exit 1
fi
fi
if [[ -z "${AUTH0_CLIENT_ID}" ]]; then
echo "AUTH0_CLIENT_ID environment variable must be set"
exit 1
if [[ -z "${AUTH_CLIENT_ID}" ]]; then
if [[ -z "${AUTH0_CLIENT_ID}" ]]; then
echo "AUTH_CLIENT_ID or AUTH0_CLIENT_ID environment variable must be set"
exit 1
fi
fi
if [[ -z "${AUTH0_AUDIENCE}" ]]; then
echo "AUTH0_AUDIENCE environment variable must be set"
exit 1
if [[ -z "${AUTH_AUDIENCE}" ]]; then
if [[ -z "${AUTH0_AUDIENCE}" ]]; then
echo "AUTH_AUDIENCE or AUTH0_AUDIENCE environment variable must be set"
exit 1
fi
fi
if [[ -z "${AUTH_SUPPORTED_SCOPES}" ]]; then
if [[ -z "${AUTH0_DOMAIN}" ]]; then
echo "AUTH_SUPPORTED_SCOPES environment variable must be set"
exit 1
fi
fi
if [[ -z "${USE_AUTH0}" ]]; then
if [[ -z "${AUTH0_DOMAIN}" ]]; then
echo "USE_AUTH0 environment variable must be set"
exit 1
fi
fi
if [[ -z "${NETBIRD_MGMT_API_ENDPOINT}" ]]; then
@@ -21,23 +41,27 @@ if [[ -z "${NETBIRD_MGMT_API_ENDPOINT}" ]]; then
exit 1
fi
AUTH0_DOMAIN=${AUTH0_DOMAIN}
AUTH0_CLIENT_ID=${AUTH0_CLIENT_ID}
AUTH0_AUDIENCE=${AUTH0_AUDIENCE}
NETBIRD_MGMT_API_ENDPOINT=${NETBIRD_MGMT_API_ENDPOINT}
NETBIRD_MGMT_GRPC_API_ENDPOINT=${NETBIRD_MGMT_GRPC_API_ENDPOINT}
export AUTH_AUTHORITY=${AUTH_AUTHORITY:-https://$AUTH0_DOMAIN}
export AUTH_CLIENT_ID=${AUTH_CLIENT_ID:-$AUTH0_CLIENT_ID}
export AUTH_AUDIENCE=${AUTH_AUDIENCE:-$AUTH0_AUDIENCE}
export AUTH_REDIRECT_URI=${AUTH_REDIRECT_URI}
export AUTH_SILENT_REDIRECT_URI=${AUTH_SILENT_REDIRECT_URI}
export USE_AUTH0=${USE_AUTH0:-true}
export AUTH_SUPPORTED_SCOPES=${AUTH_SUPPORTED_SCOPES:-openid profile email api offline_access email_verified}
export NETBIRD_MGMT_API_ENDPOINT=$(echo $NETBIRD_MGMT_API_ENDPOINT | sed -E 's/(:80|:443)$//')
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}
REPO="https://github.com/netbirdio/netbird/"
# this command will fetch the latest release e.g. v0.6.3
export NETBIRD_LATEST_VERSION=$(basename $(curl -fs -o/dev/null -w %{redirect_url} ${REPO}releases/latest))
echo "NetBird latest version: ${NETBIRD_LATEST_VERSION}"
# replace ENVs in the config
ENV_STR="\$\$AUTH0_DOMAIN \$\$AUTH0_CLIENT_ID \$\$AUTH0_AUDIENCE \$\$NETBIRD_MGMT_API_ENDPOINT \$\$NETBIRD_MGMT_GRPC_API_ENDPOINT \$\$NETBIRD_LATEST_VERSION"
ENV_STR="\$\$USE_AUTH0 \$\$AUTH_AUDIENCE \$\$AUTH_AUTHORITY \$\$AUTH_CLIENT_ID \$\$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"
MAIN_JS=$(find /usr/share/nginx/html/static/js/main.*js)
OIDC_TRUSTED_DOMAINS="/usr/share/nginx/html/OidcTrustedDomains.js"
cp "$MAIN_JS" "$MAIN_JS".copy
envsubst "$ENV_STR" < "$MAIN_JS".copy > "$MAIN_JS"
rm "$MAIN_JS".copy
envsubst "$ENV_STR" < "$OIDC_TRUSTED_DOMAINS".tmpl > "$OIDC_TRUSTED_DOMAINS"
rm "$MAIN_JS".copy
+20292 -3765
View File
File diff suppressed because it is too large. Load diff
+17 -7
View File
@@ -3,8 +3,8 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@ant-design/icons": "^4.7.0",
"@auth0/auth0-react": "^1.6.0",
"@ant-design/icons": "^4.8.0",
"@axa-fr/react-oidc": "^5.14.0",
"@headlessui/react": "^1.5.0",
"@heroicons/react": "^1.0.4",
"@testing-library/jest-dom": "^5.11.4",
@@ -18,32 +18,42 @@
"@types/react-redux": "^7.1.24",
"@types/react-router-dom": "^5.3.3",
"@types/styled-components": "^5.1.25",
"antd": "^4.20.6",
"antd": "^5.3.1",
"autoprefixer": "^10.4.4",
"axios": "^0.27.2",
"cidr-regex": "^3.1.1",
"copyfiles": "^2.4.1",
"heroicons": "^1.0.6",
"highlight.js": "^11.2.0",
"history": "^5.0.1",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"postcss": "^8.4.12",
"prop-types": "^15.7.2",
"react": "^18.1.0",
"punycode": "^2.1.1",
"rc-overflow": "^1.2.8",
"react": "^18.2.0",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^18.1.0",
"react-highlight": "^0.14.0",
"react-hotjar": "^5.1.0",
"react-redux": "^8.0.2",
"react-router-dom": "^5.2.0",
"react-router-dom": "^5.3.3",
"react-scripts": "^5.0.1",
"react-syntax-highlighter": "^15.5.0",
"react-table": "^7.7.0",
"redux": "^4.2.0",
"redux-devtools-extension": "^2.13.9",
"redux-saga": "^1.1.3",
"styled-components": "^5.3.5",
"tailwindcss": "^3.0.23",
"ts-md5": "^1.3.1",
"typesafe-actions": "^5.1.0",
"typescript": "^4.6.4",
"web-vitals": "^2.1.4"
},
"scripts": {
"copy": "copyfiles -f ./node_modules/@axa-fr/react-oidc/dist/OidcServiceWorker.js ./public",
"copytrusted": "copyfiles -f ./public/local/OidcTrustedDomains.js ./public",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
@@ -68,6 +78,6 @@
]
},
"devDependencies": {
"@types/react-highlight": "^0.12.5"
"@types/react-syntax-highlighter": "^15.5.3"
}
}
+6
View File
@@ -0,0 +1,6 @@
// Add here trusted domains, access tokens will be send to
const trustedDomains = {
default:["$NETBIRD_MGMT_API_ENDPOINT"],
auth0:[]
};
+1
View File
@@ -5,6 +5,7 @@
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="robots" content="noindex">
<meta
name="description"
content="NetBird Management Dashboard"
+6
View File
@@ -0,0 +1,6 @@
// Add here trusted domains, access tokens will be send to
const trustedDomains = {
default:["http://localhost:3001","http://127.0.0.1:3001", "http://0.0.0.0:33071"],
auth0:[]
};
+1 -1
View File
@@ -1,3 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
Disallow: /
+18
View File
@@ -0,0 +1,18 @@
#!/bin/bash
MGMT_PORT=$1
npm run build
docker build -f docker/Dockerfile -t netbird/dashboard-local:latest .
docker rm -f netbird-dashboard
docker run -d --name netbird-dashboard \
-p 3000:80 -p 443:443 \
-e AUTH_AUDIENCE=netbird-client \
-e AUTH_AUTHORITY=http://localhost:8080/realms/netbird \
-e AUTH_CLIENT_ID=netbird-client \
-e USE_AUTH0=false \
-e AUTH_SUPPORTED_SCOPES='openid profile email api offline_access' \
-e NETBIRD_MGMT_API_ENDPOINT=http://localhost:$MGMT_PORT \
-e NETBIRD_MGMT_GRPC_API_ENDPOINT=http://localhost:$MGMT_PORT \
netbird/dashboard-local:latest
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
MGMT_PORT=$1
npm run build
docker build -f docker/Dockerfile -t netbird/dashboard-local:latest .
docker rm -f netbird-dashboard
docker run -d --name netbird-dashboard \
-p 3000:80 -p 443:443 \
-e AUTH0_AUDIENCE=http://localhost:3000/ \
-e AUTH0_DOMAIN=netbird-localdev.eu.auth0.com \
-e AUTH0_CLIENT_ID=kBRMAOqIZ7hvpVCaypQLCJvTzkYYIXVt \
-e NETBIRD_MGMT_API_ENDPOINT=http://localhost:$MGMT_PORT \
-e NETBIRD_MGMT_GRPC_API_ENDPOINT=http://localhost:$MGMT_PORT \
netbird/dashboard-local:latest
Executable
+18
View File
@@ -0,0 +1,18 @@
#!/bin/bash
MGMT_PORT=$1
npm run build
docker build -f docker/Dockerfile -t netbird/dashboard-local:latest .
docker rm -f netbird-dashboard
docker run -d --name netbird-dashboard \
-p 3000:80 -p 443:443 \
-e AUTH_AUDIENCE=http://localhost:3000/ \
-e AUTH_AUTHORITY=https://netbird-localdev.eu.auth0.com \
-e AUTH_CLIENT_ID=kBRMAOqIZ7hvpVCaypQLCJvTzkYYIXVt \
-e USE_AUTH0=true \
-e AUTH_SUPPORTED_SCOPES='openid profile email api offline_access email_verified' \
-e NETBIRD_MGMT_API_ENDPOINT=http://localhost:$MGMT_PORT \
-e NETBIRD_MGMT_GRPC_API_ENDPOINT=http://localhost:$MGMT_PORT \
netbird/dashboard-local:latest
+104 -99
View File
@@ -1,45 +1,48 @@
import React, {useEffect, useState} from 'react';
import React, {useEffect, useRef, useState} from 'react';
import {Provider} from "react-redux";
import {Link, Redirect, Route, Switch} from 'react-router-dom';
import {useAuth0} from "@auth0/auth0-react";
import Navbar from './components/Navbar';
import Peers from './views/Peers';
import FooterComponent from './components/FooterComponent';
import Loading from "./components/Loading";
import SetupKeys from "./views/SetupKeys";
import AddPeer from "./views/AddPeer";
import Users from './views/Users';
import AccessControl from './views/AccessControl';
// import Activity from './views/Activity';
import {apiClient, store} from "./store";
import {hotjar} from 'react-hotjar';
import {getConfig} from "./config";
import Banner from "./components/Banner";
import {store} from "./store";
import {Button, Col, Layout, Result, Row} from 'antd';
import {Col, ConfigProvider, Layout, Row} from "antd";
import {Container} from "./components/Container";
import Navbar from "./components/Navbar";
import {Redirect, Route, Switch} from "react-router-dom";
import {withOidcSecure} from "@axa-fr/react-oidc";
import Peers from "./views/Peers";
import Routes from "./views/Routes";
import AddPeer from "./views/AddPeer";
import SetupKeys from "./views/SetupKeys";
import AccessControl from "./views/AccessControl";
import Users from "./views/Users";
import FooterComponent from "./components/FooterComponent";
import {useGetTokenSilently, useTokenSource} from "./utils/token";
import {User} from "./store/user/types";
import {SecureLoading} from "./components/Loading";
import DNS from "./views/DNS";
import Activity from "./views/Activity";
import Settings from "./views/Settings";
const {Header, Content} = Layout;
function App() {
const {
isLoading,
isAuthenticated,
loginWithRedirect,
logout,
error
} = useAuth0();
const run = useRef(false)
const [show, setShow] = useState(false)
const {hotjarTrackID,tokenSource} = getConfig();
useTokenSource(tokenSource)
const {getTokenSilently} = useGetTokenSilently();
// @ts-ignore
if (hotjarTrackID && window._DATADOG_SYNTHETICS_BROWSER === undefined) {
hotjar.initialize(hotjarTrackID, 6);
}
const [isOpen, setIsOpen] = useState(false);
const toggle = () => {
setIsOpen(!isOpen);
};
useEffect(() => {
const hideMenu = () => {
if (window.innerWidth > 768 && isOpen) {
setIsOpen(false);
console.log('i resized');
}
};
@@ -48,81 +51,83 @@ function App() {
return () => {
window.removeEventListener('resize', hideMenu);
};
});
}, []);
if (error) {
return <Result
status="warning"
title={error.message}
extra={<>
<a href={window.location.origin}>
<Button type="primary">
Try again
</Button>
</a>
<Button type="primary" onClick={function () {
logout({
returnTo: window.location.origin,
})
}}>
Log out
</Button>
</>
}
/>
}
useEffect(() => {
if (!run.current) {
run.current = true
apiClient.request<User[]>('GET', `/api/users`, {getAccessTokenSilently: getTokenSilently})
.then(() => {
setShow(true)
})
.catch(e => {
setShow(true)
console.log(e)
})
}
if (isLoading) {
return <Loading padding="3em" width="50px" height="50px"/>;
}
if (!isAuthenticated) {
loginWithRedirect({})
}
}, [getTokenSilently])
return (
<Provider store={store}>
{isAuthenticated &&
<Layout>
<Banner/>
<Header className="header" style={{
display: "flex",
flexDirection: "column",
justifyContent: "space-around",
alignContent: "center"
}}>
<Row justify="space-around" align="middle">
<Col span={24}>
<Container>
<Navbar/>
</Container>
</Col>
</Row>
</Header>
<Content style={{ minHeight: "100vh"}}>
<Switch>
<Route
exact
path="/"
render={() => {
return (
<Redirect to="/peers"/>
)
}}
/>
<Route path='/peers' exact component={Peers}/>
<Route path="/add-peer" component={AddPeer}/>
<Route path="/setup-keys" component={SetupKeys}/>
<Route path="/acls" component={AccessControl}/>
{/*<Route path="/activity" component={Activity}/>*/}
<Route path="/users" component={Users}/>
</Switch>
</Content>
<FooterComponent/>
</Layout>
}
</Provider>
);
<>
<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 &&
<Layout>
<Banner/>
<Header className="header" style={{
display: "flex",
flexDirection: "column",
justifyContent: "space-around",
alignContent: "center"
}}>
<Row justify="space-around" align="middle">
<Col span={24}>
<Container>
<Navbar/>
</Container>
</Col>
</Row>
</Header>
<Content style={{minHeight: "100vh"}}>
<Switch>
<Route
exact
path="/"
render={() => {
return (
<Redirect to="/peers"/>
)
}}
/>
<Route path='/peers' exact component={withOidcSecure(Peers)}/>
<Route path="/setup-keys" component={withOidcSecure(SetupKeys)}/>
<Route path="/acls" component={withOidcSecure(AccessControl)}/>
<Route path="/routes" component={withOidcSecure(Routes)}/>
<Route path="/users" component={withOidcSecure(Users)}/>
<Route path="/dns" component={withOidcSecure(DNS)}/>
<Route path="/activity" component={withOidcSecure(Activity)}/>
<Route path="/settings" component={withOidcSecure(Settings)}/>
</Switch>
</Content>
<FooterComponent/>
</Layout>
}
</Provider>
</ConfigProvider>
</>
)
}
export default App;
+1 -5
View File
@@ -1,8 +1,4 @@
import React, {useEffect, useState} from 'react';
import {useDispatch, useSelector} from "react-redux";
import {RootState} from "typesafe-actions";
import { actions as ruleActions } from '../store/rule';
import {string} from "prop-types";
import {Avatar, List, Modal} from "antd";
import {Group} from "../store/group/types";
@@ -20,7 +16,7 @@ const AccessControlModalGroups:React.FC<Props> = ({data, title, visible, onCance
return (
<>
<Modal title={title} visible={isModalVisible} onCancel={() => onCancel()} footer={null}>
<Modal title={title} open={isModalVisible} onCancel={() => onCancel()} footer={null}>
<List
itemLayout="horizontal"
dataSource={data as Group[] | undefined}
+76 -56
View File
@@ -1,26 +1,32 @@
import React, {useEffect, useRef, useState} from 'react';
import {useDispatch, useSelector} from "react-redux";
import {RootState} from "typesafe-actions";
import { actions as ruleActions } from '../store/rule';
import {actions as ruleActions} from '../store/rule';
import {
Button,
Col,
Row,
Typography,
Divider,
Drawer,
Form,
Input,
Radio,
RadioChangeEvent,
Row,
Select,
Space,
Switch,
Button, Drawer, Form, Divider, Select, Tag, Radio, RadioChangeEvent
Tag,
Typography
} from "antd";
import {ArrowRightOutlined, CheckOutlined, CloseOutlined, FlagFilled, QuestionCircleFilled} from "@ant-design/icons";
import type { CustomTagProps } from 'rc-select/lib/BaseSelect'
import {CloseOutlined, FlagFilled, QuestionCircleFilled} from "@ant-design/icons";
import type {CustomTagProps} from 'rc-select/lib/BaseSelect'
import {Rule, RuleToSave} from "../store/rule/types";
import {useAuth0} from "@auth0/auth0-react";
import { uniq } from "lodash"
import {uniq} from "lodash"
import {Header} from "antd/es/layout/layout";
import {RuleObject} from "antd/lib/form";
import {useGetTokenSilently} from "../utils/token";
const { Paragraph } = Typography;
const { Option } = Select;
const {Paragraph} = Typography;
const {Option} = Select;
interface FormRule extends Rule {
tagSourceGroups: string[]
@@ -28,11 +34,11 @@ interface FormRule extends Rule {
}
const AccessControlNew = () => {
const { getAccessTokenSilently } = useAuth0()
const {getTokenSilently} = useGetTokenSilently()
const dispatch = useDispatch()
const setupNewRuleVisible = useSelector((state: RootState) => state.rule.setupNewRuleVisible)
const groups = useSelector((state: RootState) => state.group.data)
const rule = useSelector((state: RootState) => state.rule.rule)
const groups = useSelector((state: RootState) => state.group.data)
const rule = useSelector((state: RootState) => state.rule.rule)
const savedRule = useSelector((state: RootState) => state.rule.savedRule)
const [editName, setEditName] = useState(false)
@@ -72,7 +78,7 @@ const AccessControlNew = () => {
setTagGroups(groups?.map(g => g.name) || [])
}, [groups])
const createRuleToSave = ():RuleToSave => {
const createRuleToSave = (): RuleToSave => {
const sources = groups?.filter(g => formRule.tagSourceGroups.includes(g.name)).map(g => g.id || '') || []
const destinations = groups?.filter(g => formRule.tagDestinationGroups.includes(g.name)).map(g => g.id || '') || []
const sourcesNoId = formRule.tagSourceGroups.filter(s => !tagGroups.includes(s))
@@ -96,14 +102,17 @@ const AccessControlNew = () => {
form.validateFields()
.then((values) => {
const ruleToSave = createRuleToSave()
dispatch(ruleActions.saveRule.request({getAccessTokenSilently, payload: ruleToSave}))
dispatch(ruleActions.saveRule.request({
getAccessTokenSilently: getTokenSilently,
payload: ruleToSave
}))
})
.catch((errorInfo) => {
console.log('errorInfo', errorInfo)
});
};
const setVisibleNewRule = (status:boolean) => {
const setVisibleNewRule = (status: boolean) => {
dispatch(ruleActions.setSetupNewRuleVisible(status));
}
@@ -121,7 +130,7 @@ const AccessControlNew = () => {
setVisibleNewRule(false)
}
const onChange = (data:any) => {
const onChange = (data: any) => {
setFormRule({...formRule, ...data})
}
@@ -139,7 +148,7 @@ const AccessControlNew = () => {
})
};
const handleChangeDisabled = ({ target: { value } }: RadioChangeEvent) => {
const handleChangeDisabled = ({target: {value}}: RadioChangeEvent) => {
setFormRule({
...formRule,
disabled: value
@@ -147,7 +156,7 @@ const AccessControlNew = () => {
};
const tagRender = (props: CustomTagProps) => {
const { label, value, closable, onClose } = props;
const {label, value, closable, onClose} = props;
const onPreventMouseDown = (event: React.MouseEvent<HTMLSpanElement>) => {
event.preventDefault();
event.stopPropagation();
@@ -159,7 +168,7 @@ const AccessControlNew = () => {
onMouseDown={onPreventMouseDown}
closable={closable}
onClose={onClose}
style={{ marginRight: 3 }}
style={{marginRight: 3}}
>
<strong>{value}</strong>
</Tag>
@@ -169,12 +178,12 @@ const AccessControlNew = () => {
const optionRender = (label: string) => {
let peersCount = ''
const g = groups.find(_g => _g.name === label)
if (g) peersCount = ` - ${g.peers_count || 0} ${(!g.peers_count || parseInt(g.peers_count) !== 1) ? 'peers' : 'peer'} `
if (g) peersCount = ` - ${g.peers_count || 0} ${(!g.peers_count || parseInt(g.peers_count) !== 1) ? 'peers' : 'peer'} `
return (
<>
<Tag
color="blue"
style={{ marginRight: 3 }}
style={{marginRight: 3}}
>
<strong>{label}</strong>
</Tag>
@@ -186,25 +195,27 @@ const AccessControlNew = () => {
const dropDownRender = (menu: React.ReactElement) => (
<>
{menu}
<Divider style={{ margin: '8px 0' }} />
<Divider style={{margin: '8px 0'}}/>
<Row style={{padding: '0 8px 4px'}}>
<Col flex="auto">
<span style={{color: "#9CA3AF"}}>Add new group by pressing "Enter"</span>
</Col>
<Col flex="none">
<svg width="14" height="12" viewBox="0 0 14 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.70455 7.19176V5.89915H10.3949C10.7727 5.89915 11.1174 5.80634 11.429 5.62074C11.7405 5.43513 11.9875 5.18655 12.1697 4.875C12.3554 4.56345 12.4482 4.21875 12.4482 3.84091C12.4482 3.46307 12.3554 3.12003 12.1697 2.81179C11.9841 2.50024 11.7356 2.25166 11.424 2.06605C11.1158 1.88044 10.7727 1.78764 10.3949 1.78764H9.83807V0.5H10.3949C11.0114 0.5 11.5715 0.650805 12.0753 0.952414C12.5791 1.25402 12.9818 1.65672 13.2834 2.16051C13.585 2.6643 13.7358 3.22443 13.7358 3.84091C13.7358 4.30161 13.648 4.73414 13.4723 5.13849C13.3 5.54285 13.0613 5.89915 12.7564 6.20739C12.4515 6.51562 12.0968 6.75758 11.6925 6.93324C11.2881 7.10559 10.8556 7.19176 10.3949 7.19176H1.70455ZM4.90128 11.0646L0.382102 6.54545L4.90128 2.02628L5.79119 2.91619L2.15696 6.54545L5.79119 10.1747L4.90128 11.0646Z" fill="#9CA3AF"/>
<path
d="M1.70455 7.19176V5.89915H10.3949C10.7727 5.89915 11.1174 5.80634 11.429 5.62074C11.7405 5.43513 11.9875 5.18655 12.1697 4.875C12.3554 4.56345 12.4482 4.21875 12.4482 3.84091C12.4482 3.46307 12.3554 3.12003 12.1697 2.81179C11.9841 2.50024 11.7356 2.25166 11.424 2.06605C11.1158 1.88044 10.7727 1.78764 10.3949 1.78764H9.83807V0.5H10.3949C11.0114 0.5 11.5715 0.650805 12.0753 0.952414C12.5791 1.25402 12.9818 1.65672 13.2834 2.16051C13.585 2.6643 13.7358 3.22443 13.7358 3.84091C13.7358 4.30161 13.648 4.73414 13.4723 5.13849C13.3 5.54285 13.0613 5.89915 12.7564 6.20739C12.4515 6.51562 12.0968 6.75758 11.6925 6.93324C11.2881 7.10559 10.8556 7.19176 10.3949 7.19176H1.70455ZM4.90128 11.0646L0.382102 6.54545L4.90128 2.02628L5.79119 2.91619L2.15696 6.54545L5.79119 10.1747L4.90128 11.0646Z"
fill="#9CA3AF"/>
</svg>
</Col>
</Row>
</>
)
const toggleEditName = (status:boolean) => {
const toggleEditName = (status: boolean) => {
setEditName(status);
}
const toggleEditDescription = (status:boolean) => {
const toggleEditDescription = (status: boolean) => {
setEditDescription(status);
}
@@ -217,10 +228,10 @@ const AccessControlNew = () => {
const selectValidator = (_: RuleObject, value: string[]) => {
let hasSpaceNamed = []
if (!value.length) {
return Promise.reject(new Error("Please enter ate least one group"))
return Promise.reject(new Error("Please enter at least one group"))
}
value.forEach(function(v: string) {
value.forEach(function (v: string) {
if (!v.trim().length) {
hasSpaceNamed.push(v)
}
@@ -248,7 +259,8 @@ const AccessControlNew = () => {
footer={
<Space style={{display: 'flex', justifyContent: 'end'}}>
<Button onClick={onCancel} disabled={savedRule.loading}>Cancel</Button>
<Button type="primary" disabled={savedRule.loading} onClick={handleFormSubmit}>{`${formRule.id ? 'Save' : 'Create'}`}</Button>
<Button type="primary" disabled={savedRule.loading}
onClick={handleFormSubmit}>{`${formRule.id ? 'Save' : 'Create'}`}</Button>
</Space>
}
>
@@ -258,37 +270,51 @@ const AccessControlNew = () => {
<Header style={{margin: "-32px -24px 20px -24px", padding: "24px 24px 0 24px"}}>
<Row align="top">
<Col flex="none" style={{display: "flex"}}>
{!editName && !editDescription && formRule.id &&
{!editName && !editDescription && formRule.id &&
<button type="button" aria-label="Close" className="ant-drawer-close"
style={{paddingTop: 3}}
onClick={onCancel}>
<span role="img" aria-label="close" className="anticon anticon-close">
<span role="img" aria-label="close"
className="anticon anticon-close">
<CloseOutlined size={16}/>
</span>
</button>
}
</Col>
<Col flex="auto">
{ !editName && formRule.id ? (
<div className={"access-control input-text ant-drawer-title"} onClick={() => toggleEditName(true)}>{formRule.id ? formRule.name : 'New Rule'}</div>
{!editName && formRule.id ? (
<div className={"access-control input-text ant-drawer-title"}
onClick={() => toggleEditName(true)}>{formRule.id ? formRule.name : 'New Rule'}</div>
) : (
<Form.Item
name="name"
label="Name"
rules={[{required: true, message: 'Please add a name for this access rule', whitespace: true}]}
rules={[{
required: true,
message: 'Please add a name for this access rule',
whitespace: true
}]}
>
<Input placeholder="Add rule name..." ref={inputNameRef} onPressEnter={() => toggleEditName(false)} onBlur={() => toggleEditName(false)} autoComplete="off"/>
<Input placeholder="Add rule name..." ref={inputNameRef}
onPressEnter={() => toggleEditName(false)}
onBlur={() => toggleEditName(false)} autoComplete="off"/>
</Form.Item>
)}
{ !editDescription ? (
<div className={"access-control input-text ant-drawer-subtitle"} onClick={() => toggleEditDescription(true)}>{formRule.description && formRule.description.trim() !== "" ? formRule.description : 'Add description...'}</div>
{!editDescription ? (
<div className={"access-control input-text ant-drawer-subtitle"}
onClick={() => toggleEditDescription(true)}>
{formRule.description && formRule.description.trim() !== "" ? formRule.description : 'Add description...'}
</div>
) : (
<Form.Item
name="description"
label="Description"
style={{marginTop: 24}}
>
<Input placeholder="Add description..." ref={inputDescriptionRef} onPressEnter={() => toggleEditDescription(false)} onBlur={() => toggleEditDescription(false)} autoComplete="off"/>
<Input placeholder="Add description..." ref={inputDescriptionRef}
onPressEnter={() => toggleEditDescription(false)}
onBlur={() => toggleEditDescription(false)}
autoComplete="off"/>
</Form.Item>
)}
</Col>
@@ -308,14 +334,7 @@ const AccessControlNew = () => {
<Form.Item
name="disabled"
label="Status"
//valuePropName="checked"
>
{/*<Switch
checkedChildren={<CheckOutlined />}
unCheckedChildren={<CloseOutlined />}
onChange={handleChangeDisabled}
/>*/}
<Radio.Group
options={optionsDisabledEnabled}
@@ -329,11 +348,10 @@ const AccessControlNew = () => {
<Form.Item
name="tagSourceGroups"
label="Source groups"
rules={[{ validator: selectValidator }]}
style={{display: 'flex'}}
rules={[{validator: selectValidator}]}
>
<Select mode="tags"
style={{ width: '100%' }}
style={{width: '100%'}}
placeholder="Tags Mode"
tagRender={tagRender}
onChange={handleChangeSource}
@@ -351,11 +369,10 @@ const AccessControlNew = () => {
<Form.Item
name="tagDestinationGroups"
label="Destination groups"
rules={[{ validator: selectValidator }]}
style={{display: 'flex'}}
rules={[{validator: selectValidator}]}
>
<Select
mode="tags" style={{ width: '100%' }}
mode="tags" style={{width: '100%'}}
placeholder="Tags Mode"
tagRender={tagRender}
onChange={handleChangeDestination}
@@ -376,10 +393,14 @@ const AccessControlNew = () => {
</Col>
<Col flex="auto">
<Paragraph>
At the moment access rules are bi-directional by default, this means both source and destination can talk to each-other in both directions. However destination peers will not be able to communicate with each other, nor will the source peers.
At the moment access rules are bi-directional by default, this means both
source and destination can talk to each-other in both directions. However
destination peers will not be able to communicate with each other, nor will
the source peers.
</Paragraph>
<Paragraph>
If you want to enable all peers of the same group to talk to each other - you can add that group both as a receiver and as a destination.
If you want to enable all peers of the same group to talk to each other -
you can add that group both as a receiver and as a destination.
</Paragraph>
</Col>
</Row>
@@ -387,8 +408,7 @@ const AccessControlNew = () => {
<Col span={24}>
<Divider></Divider>
<Button icon={<QuestionCircleFilled/>} type="link" target="_blank"
href="https://docs.netbird.io/docs/overview/acls" style={{color: 'rgb(07, 114, 128)'}}>Learn
more about access controls</Button>
href="https://docs.netbird.io/docs/overview/acls">Learn more about access controls</Button>
</Col>
</Row>
</Form>
+25 -5
View File
@@ -1,20 +1,28 @@
import { useState } from "react";
import {useEffect, useState} from "react";
import {Button, Col, Row, Space, Typography} from "antd";
import { CloseOutlined } from '@ant-design/icons';
import {Md5} from "ts-md5";
const { Text } = Typography
const Banner = () => {
const [show, setShow] = useState(true);
const [show, setShow] = useState(false);
const banner_md5_key = 'banner_md5'
const banner_closed_key = 'banner_closed'
const dismiss = () => {
setShow(false);
localStorage.setItem(banner_closed_key,'true');
};
const announcement = "New Release! Manage DNS with NetBird."
const announcement_md5 = Md5.hashStr(announcement)
const linkLearnMore = () => {
return (
<a
href="https://netbird.io/blog/introducing-access-control"
href="https://netbird.io/docs/how-to-guides/nameservers"
className="font-bold underline"
target="_blank"
rel="noreferrer"
@@ -22,12 +30,24 @@ const Banner = () => {
)
}
useEffect(()=>{
let store_banner_md5 = localStorage.getItem(banner_md5_key);
let stored_banner_closed = localStorage.getItem(banner_closed_key);
if((!stored_banner_closed || stored_banner_closed !== 'true') ||
(!store_banner_md5 || store_banner_md5 !== announcement_md5)) {
//setShow(true);
localStorage.setItem(banner_md5_key,announcement_md5);
localStorage.setItem(banner_closed_key,'false');
}
},[])
return show ? (
<div className="relative bg-indigo-600 white" color="white" style={{position: "relative", padding: "0.3rem"}} >
<Row>
<Col xs={24} sm={0} lg={0}>
<Text className="ant-col-md-0" style={{color: "#ffffff"}}>
Big news! Introducing NetBird Access Control.
{announcement}
</Text>
</Col>
<Col xs={24} sm={0} lg={0}>
@@ -38,7 +58,7 @@ const Banner = () => {
<Col xs={0} sm={24}>
<Space align="center" style={{display: "flex", justifyContent: "center"}}>
<Text style={{color: "#ffffff"}}>
Big news! Introducing NetBird Access Control.
{announcement}
</Text>
<span>
{linkLearnMore()}
+21 -9
View File
@@ -1,24 +1,36 @@
import {copyToClipboard} from "../utils/common";
import {Button, message} from "antd";
import {StepCommand} from "./addpeer/types";
import React from "react";
import {Button, message, Typography} from "antd";
import React, {ReactNode} from "react";
const {Text} = Typography;
type Props = {
keyMessage: string;
text: string;
toCopy: string;
body: ReactNode;
messageText: string;
styleNotification?: any;
style?: any;
className?:any;
className?: any;
};
const ButtonCopyMessage:React.FC<Props> = ({ keyMessage, text, messageText, styleNotification, style, className}) => {
const ButtonCopyMessage: React.FC<Props> = ({
keyMessage,
toCopy,
body,
messageText,
styleNotification,
style,
className
}) => {
const copyTextMessage = () => {
copyToClipboard(text)
message.success({ content: `${messageText}`, key: keyMessage, duration: 1, style: (styleNotification || {}) });
copyToClipboard(toCopy)
message.success({content: `${messageText}`, key: keyMessage, duration: 1, style: (styleNotification || {})});
}
return (
<Button type="text" onClick={copyTextMessage} style={style || {}} className={className}>{text}</Button>
<Button type="text" onClick={copyTextMessage} style={style || {}} className={className}>
{body}
</Button>
)
}
+21 -6
View File
@@ -1,17 +1,32 @@
import React from "react";
import loading from "../assets/bars.svg";
import {Space} from "antd";
import {OidcSecure} from "@axa-fr/react-oidc";
type Props = {
type LoadingProps = {
padding?: string;
width?: string;
height?: string;
width?: number;
height?: number;
};
const Loading:React.FC<Props> = ({padding, width, height}) => (
<Space direction="vertical" align="center" style={{display: 'flex', padding: `${padding || `.25em`}`}}>
<img src={loading} alt="Loading" style={{width: `${width || '25px'}`, height: `${height || '25px'}`}}/>
const Loading: React.FC<LoadingProps> = ({padding, width, height}) => (
<Space direction="vertical" align="center" style={{
marginTop: `-${height ? (height / 2) + "px" : '-25px'}`,
marginLeft: `-${width ? (width / 2) + "px" : '-25px'}`,
position: "absolute",
top: "50%",
left: "50%",
display: 'flex'
}}>
<img src={loading} alt="Loading"
style={{width: `${width ? width + "px" : '25px'}`, height: `${height ? height + "px" : '25px'}`}}/>
</Space>
);
export default Loading;
// Wrapper of Loading to handle cases when it is shown within the authenticated layout and has to trigger authentication when token expires.
export const SecureLoading = (props: LoadingProps) => (
<OidcSecure>
<Loading {...props} />
</OidcSecure>
);
+57
View File
@@ -0,0 +1,57 @@
import {useOidc, useOidcUser} from "@axa-fr/react-oidc";
import {Anchor, Button, Col, Result, Row, Space} from "antd";
import React from "react";
import {getConfig} from "../config";
import {ResultStatusType} from "antd/lib/result";
const {Link} = Anchor;
function LoginError() {
const {logout} = useOidc();
const config = getConfig();
const {oidcUserLoadingState} = useOidcUser();
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
if (urlParams.get("error") === "access_denied") {
let title = urlParams.get("error_description")
let status: ResultStatusType = "warning"
// this comes from the auth0 rule that links accounts
if (title === "account linked successfully") {
status = "success"
title = "Your account has been linked successfully. Please log in again to complete the setup."
}
return <Result
status={status}
title={title}
extra={<>
<Space style={{
display: "flex-inline",
flexDirection: "column",
justifyContent: "space-around",
alignContent: "center"
}}>
<h4>Already verified your email address?</h4>
<a href={window.location.origin}>
<Button type="primary">
Continue
</Button>
</a>
<Button type="link" onClick={function () {
logout("", {client_id: config.clientId})
}}>
Trouble logging in? Try again.
</Button>
</Space>
</>
}
/>
}
return <div>{"Login Error: User state: " + oidcUserLoadingState}</div>
}
export default LoginError;
Loaded 20 of 121 files, more files were not shown because too many files have changed in this diff. Show more