Compare commits

...

11 Commits

Author SHA1 Message Date
braginini
5018f8dad3 Add User-Agent to CLI 2022-05-23 09:52:44 +02:00
braginini
a4fc3fca23 Add User-Agent to CLI and Ui and pass to Management 2022-05-23 09:48:04 +02:00
Maycon Santos
5cbfa4bb9e Rebrand client cli (#320) 2022-05-22 18:53:47 +02:00
Misha Bragin
32611e1131 FIx external docs location in README 2022-05-22 14:03:43 +02:00
Maycon Santos
e334e8db53 Renaming project builds and including new Icons (#318)
Added MacOS icons, plist, and cask template file

Adjusted goreleaser with the new name for all builds

Added Icon and update windows-ui build to include it and avoid console

migrated Docker builds to new namespace netbirdio
2022-05-21 18:42:56 +02:00
Misha Bragin
3eb230e1a0 Fix Peer Deletion & HTTP endpoints (#319) 2022-05-21 17:27:04 +02:00
Givi Khojanashvili
3ce3ccc39a Add rules for ACL (#306)
Add rules HTTP endpoint for frontend - CRUD operations.
Add Default rule - allow all.
Send network map to peers based on rules.
2022-05-21 15:21:39 +02:00
Maycon Santos
11a3863c28 update docker hub namespace (#316) 2022-05-20 11:00:15 +02:00
Maycon Santos
3992fe4743 remove extra sign (#315) 2022-05-20 10:53:56 +02:00
Misha Bragin
6ce8a13ffa Update links to docs and blog 2022-05-18 10:33:37 +02:00
Maycon Santos
001cf98dce Update daemon server adminURL and managementURL fields (#314)
Removed the UP call in the login function

Attempt login on change to get status
2022-05-18 00:22:47 +02:00
67 changed files with 2152 additions and 703 deletions

View File

@@ -8,6 +8,9 @@ on:
- main
pull_request:
env:
SIGN_PIPE_VER: main
jobs:
release:
runs-on: ubuntu-latest
@@ -48,10 +51,18 @@ jobs:
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USER }}
username: netbirdio
password: ${{ secrets.DOCKER_TOKEN }}
- name: Install dependencies
run: sudo apt update && sudo apt install -y -q libgtk-3-dev libappindicator3-dev libayatana-appindicator3-dev libgl1-mesa-dev xorg-dev gcc-mingw-w64-x86-64
- name: Install rsrc
run: go install github.com/akavel/rsrc@v0.10.2
- name: Generate windows rsrc
run: rsrc -arch amd64 -ico client/ui/netbird.ico -manifest client/ui/manifest.xml -o client/ui/resources_windows_amd64.syso
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
@@ -63,18 +74,17 @@ jobs:
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
UPLOAD_DEBIAN_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
UPLOAD_YUM_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
-
name: Trigger Windows binaries sign pipeline
uses: benc-uk/workflow-dispatch@v1
if: startsWith(github.ref, 'refs/tags/')
with:
workflow: Sign windows bin and installer
repo: wiretrustee/windows-sign-pipeline
ref: v0.0.2
repo: netbirdio/sign-pipelines
ref: ${{ env.SIGN_PIPE_VER }}
token: ${{ secrets.SIGN_GITHUB_TOKEN }}
inputs: '{ "tag": "${{ github.ref }}" }'
-
-
name: upload non tags for debug purposes
uses: actions/upload-artifact@v2
with:
@@ -108,19 +118,29 @@ jobs:
run: go mod tidy
-
name: Run GoReleaser
id: goreleaser
uses: goreleaser/goreleaser-action@v2
with:
version: v1.6.3
args: release --config .goreleaser_ui_darwin.yaml --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
UPLOAD_DEBIAN_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
UPLOAD_YUM_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
-
-
name: Trigger Darwin App binaries sign pipeline
uses: benc-uk/workflow-dispatch@v1
if: startsWith(github.ref, 'refs/tags/')
with:
workflow: Sign darwin ui app
repo: netbirdio/sign-pipelines
ref: ${{ env.SIGN_PIPE_VER }}
token: ${{ secrets.SIGN_GITHUB_TOKEN }}
inputs: '{ "tag": "${{ github.ref }}" }'
-
name: upload non tags for debug purposes
uses: actions/upload-artifact@v2
with:
name: build-ui-darwin
path: dist/
retention-days: 3
retention-days: 3

View File

@@ -1,8 +1,8 @@
project_name: wiretrustee
project_name: netbird
builds:
- id: wiretrustee
- id: netbird
dir: client
binary: wiretrustee
binary: netbird
env: [CGO_ENABLED=0]
goos:
- linux
@@ -55,9 +55,9 @@ builds:
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
mod_timestamp: '{{ .CommitTimestamp }}'
- id: wiretrustee-ui
- id: netbird-ui
dir: client/ui
binary: wiretrustee-ui
binary: netbird-ui
env:
- CGO_ENABLED=1
goos:
@@ -68,9 +68,9 @@ builds:
- -s -w -X github.com/netbirdio/netbird/client/ui/system.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
mod_timestamp: '{{ .CommitTimestamp }}'
- id: wiretrustee-ui-windows
- id: netbird-ui-windows
dir: client/ui
binary: wiretrustee-ui-windows
binary: netbird-ui
env:
- CGO_ENABLED=1
- CC=x86_64-w64-mingw32-gcc
@@ -80,23 +80,50 @@ builds:
- amd64
ldflags:
- -s -w -X github.com/netbirdio/netbird/client/ui/system.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
- -H windowsgui
mod_timestamp: '{{ .CommitTimestamp }}'
archives:
- builds:
- wiretrustee
- netbird
- id: linux-arch
name_template: "{{ .ProjectName }}-ui-linux_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
builds:
- netbird-ui
- id: windows-arch
name_template: "{{ .ProjectName }}-ui-windows_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
builds:
- netbird-ui-windows
nfpms:
- maintainer: Wiretrustee <dev@wiretrustee.com>
description: Wiretrustee client UI.
homepage: https://wiretrustee.com/
id: wiretrustee-ui-deb
package_name: wiretrustee-ui
- maintainer: Netbird <dev@netbird.io>
description: Netbird client UI.
homepage: https://netbird.io/
id: netbird-ui-deb
package_name: netbird-ui
builds:
- wiretrustee-ui
- netbird-ui
formats:
- deb
contents:
- src: client/ui/netbird.desktop
dst: /usr/share/applications/netbird.desktop
- src: client/ui/disconnected.png
dst: /usr/share/pixmaps/netbird.png
dependencies:
- libayatana-appindicator3-1
- libgtk-3-dev
- libappindicator3-dev
- maintainer: Netbird <dev@netbird.io>
description: Netbird client UI.
homepage: https://netbird.io/
id: netbird-ui-rpm
package_name: netbird-ui
builds:
- netbird-ui
formats:
- rpm
contents:
- src: client/ui/netbird.desktop
@@ -108,38 +135,44 @@ nfpms:
- libgtk-3-dev
- libappindicator3-dev
- maintainer: Wiretrustee <dev@wiretrustee.com>
description: Wiretrustee client.
homepage: https://wiretrustee.com/
id: wiretrustee-deb
- maintainer: Netbird <dev@netbird.io>
description: Netbird client.
homepage: https://netbird.io/
id: netbird-deb
bindir: /usr/bin
builds:
- wiretrustee
- netbird
formats:
- deb
replaces:
- wiretrustee
scripts:
postinstall: "release_files/post_install.sh"
preremove: "release_files/pre_remove.sh"
- maintainer: Wiretrustee <dev@wiretrustee.com>
description: Wiretrustee client.
homepage: https://wiretrustee.com/
id: wiretrustee-rpm
- maintainer: Netbird <dev@netbird.io>
description: Netbird client.
homepage: https://netbird.io/
id: netbird-rpm
bindir: /usr/bin
builds:
- wiretrustee
- netbird
formats:
- rpm
replaces:
- wiretrustee
scripts:
postinstall: "release_files/post_install.sh"
preremove: "release_files/pre_remove.sh"
dockers:
- image_templates:
- wiretrustee/wiretrustee:{{ .Version }}-amd64
- netbirdio/netbird:{{ .Version }}-amd64
ids:
- wiretrustee
- netbird
goarch: amd64
use: buildx
dockerfile: client/Dockerfile
@@ -150,11 +183,11 @@ dockers:
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=maintainer=wiretrustee@wiretrustee.com"
- "--label=maintainer=dev@netbird.io"
- image_templates:
- wiretrustee/wiretrustee:{{ .Version }}-arm64v8
- netbirdio/netbird:{{ .Version }}-arm64v8
ids:
- wiretrustee
- netbird
goarch: arm64
use: buildx
dockerfile: client/Dockerfile
@@ -165,11 +198,11 @@ dockers:
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=maintainer=wiretrustee@wiretrustee.com"
- "--label=maintainer=dev@netbird.io"
- image_templates:
- wiretrustee/wiretrustee:{{ .Version }}-arm
- netbirdio/netbird:{{ .Version }}-arm
ids:
- wiretrustee
- netbird
goarch: arm
goarm: 6
use: buildx
@@ -181,7 +214,7 @@ dockers:
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=maintainer=wiretrustee@wiretrustee.com"
- "--label=maintainer=dev@netbird.io"
- image_templates:
- netbirdio/signal:{{ .Version }}-amd64
ids:
@@ -198,7 +231,7 @@ dockers:
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=maintainer=dev@netbird.io"
- image_templates:
- netbird/signal:{{ .Version }}-arm64v8
- netbirdio/signal:{{ .Version }}-arm64v8
ids:
- netbird-signal
goarch: arm64
@@ -213,7 +246,7 @@ dockers:
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=maintainer=dev@netbird.io"
- image_templates:
- netbird/signal:{{ .Version }}-arm
- netbirdio/signal:{{ .Version }}-arm
ids:
- netbird-signal
goarch: arm
@@ -229,7 +262,7 @@ dockers:
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=maintainer=dev@netbird.io"
- image_templates:
- netbird/management:{{ .Version }}-amd64
- netbirdio/management:{{ .Version }}-amd64
ids:
- netbird-mgmt
goarch: amd64
@@ -244,7 +277,7 @@ dockers:
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=maintainer=dev@netbird.io"
- image_templates:
- netbird/management:{{ .Version }}-arm64v8
- netbirdio/management:{{ .Version }}-arm64v8
ids:
- netbird-mgmt
goarch: arm64
@@ -259,7 +292,7 @@ dockers:
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=maintainer=dev@netbird.io"
- image_templates:
- netbird/management:{{ .Version }}-arm
- netbirdio/management:{{ .Version }}-arm
ids:
- netbird-mgmt
goarch: arm
@@ -275,7 +308,7 @@ dockers:
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=maintainer=dev@netbird.io"
- image_templates:
- netbird/management:{{ .Version }}-debug-amd64
- netbirdio/management:{{ .Version }}-debug-amd64
ids:
- netbird-mgmt
goarch: amd64
@@ -290,7 +323,7 @@ dockers:
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=maintainer=dev@netbird.io"
- image_templates:
- netbird/management:{{ .Version }}-debug-arm64v8
- netbirdio/management:{{ .Version }}-debug-arm64v8
ids:
- netbird-mgmt
goarch: arm64
@@ -306,7 +339,7 @@ dockers:
- "--label=maintainer=dev@netbird.io"
- image_templates:
- netbird/management:{{ .Version }}-debug-arm
- netbirdio/management:{{ .Version }}-debug-arm
ids:
- netbird-mgmt
goarch: arm
@@ -322,60 +355,62 @@ dockers:
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=maintainer=dev@netbird.io"
docker_manifests:
- name_template: wiretrustee/wiretrustee:{{ .Version }}
- name_template: netbirdio/netbird:{{ .Version }}
image_templates:
- wiretrustee/wiretrustee:{{ .Version }}-arm64v8
- wiretrustee/wiretrustee:{{ .Version }}-arm
- wiretrustee/wiretrustee:{{ .Version }}-amd64
- netbirdio/netbird:{{ .Version }}-arm64v8
- netbirdio/netbird:{{ .Version }}-arm
- netbirdio/netbird:{{ .Version }}-amd64
- name_template: wiretrustee/wiretrustee:latest
- name_template: netbirdio/netbird:latest
image_templates:
- wiretrustee/wiretrustee:{{ .Version }}-arm64v8
- wiretrustee/wiretrustee:{{ .Version }}-arm
- wiretrustee/wiretrustee:{{ .Version }}-amd64
- netbirdio/netbird:{{ .Version }}-arm64v8
- netbirdio/netbird:{{ .Version }}-arm
- netbirdio/netbird:{{ .Version }}-amd64
- name_template: netbird/signal:{{ .Version }}
- name_template: netbirdio/signal:{{ .Version }}
image_templates:
- netbird/signal:{{ .Version }}-arm64v8
- netbird/signal:{{ .Version }}-arm
- netbird/signal:{{ .Version }}-amd64
- netbirdio/signal:{{ .Version }}-arm64v8
- netbirdio/signal:{{ .Version }}-arm
- netbirdio/signal:{{ .Version }}-amd64
- name_template: netbird/signal:latest
- name_template: netbirdio/signal:latest
image_templates:
- netbird/signal:{{ .Version }}-arm64v8
- netbird/signal:{{ .Version }}-arm
- netbird/signal:{{ .Version }}-amd64
- netbirdio/signal:{{ .Version }}-arm64v8
- netbirdio/signal:{{ .Version }}-arm
- netbirdio/signal:{{ .Version }}-amd64
- name_template: netbird/management:{{ .Version }}
- name_template: netbirdio/management:{{ .Version }}
image_templates:
- netbird/management:{{ .Version }}-arm64v8
- netbird/management:{{ .Version }}-arm
- netbird/management:{{ .Version }}-amd64
- netbirdio/management:{{ .Version }}-arm64v8
- netbirdio/management:{{ .Version }}-arm
- netbirdio/management:{{ .Version }}-amd64
- name_template: netbird/management:latest
- name_template: netbirdio/management:latest
image_templates:
- netbird/management:{{ .Version }}-arm64v8
- netbird/management:{{ .Version }}-arm
- netbird/management:{{ .Version }}-amd64
- netbirdio/management:{{ .Version }}-arm64v8
- netbirdio/management:{{ .Version }}-arm
- netbirdio/management:{{ .Version }}-amd64
- name_template: netbird/management:debug-latest
- name_template: netbirdio/management:debug-latest
image_templates:
- netbird/management:{{ .Version }}-debug-arm64v8
- netbird/management:{{ .Version }}-debug-arm
- netbird/management:{{ .Version }}-debug-amd64
- netbirdio/management:{{ .Version }}-debug-arm64v8
- netbirdio/management:{{ .Version }}-debug-arm
- netbirdio/management:{{ .Version }}-debug-amd64
brews:
-
ids:
- default
tap:
owner: wiretrustee
name: homebrew-client
owner: netbirdio
name: homebrew-tap
token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
commit_author:
name: Wiretrustee
email: wiretrustee@wiretrustee.com
description: Wiretrustee project.
name: Netbird
email: dev@netbird.io
description: Netbird project.
download_strategy: CurlDownloadStrategy
homepage: https://wiretrustee.com/
homepage: https://netbird.io/
license: "BSD3"
test: |
system "#{bin}/{{ .ProjectName }} -h"
@@ -384,6 +419,7 @@ uploads:
- name: debian
ids:
- deb
- netbird-ui-deb
mode: archive
target: https://pkgs.wiretrustee.com/debian/pool/{{ .ArtifactName }};deb.distribution=stable;deb.component=main;deb.architecture={{ if .Arm }}armhf{{ else }}{{ .Arch }}{{ end }};deb.package=
username: dev@wiretrustee.com
@@ -391,6 +427,7 @@ uploads:
- name: yum
ids:
- rpm
- netbird-ui-rpm
mode: archive
target: https://pkgs.wiretrustee.com/yum/{{ .Arch }}{{ if .Arm }}{{ .Arm }}{{ end }}
username: dev@wiretrustee.com

View File

@@ -1,8 +1,8 @@
project_name: wiretrustee-ui
project_name: netbird-ui
builds:
- id: wiretrustee-ui-darwin
- id: netbird-ui-darwin
dir: client/ui
binary: wiretrustee-ui
binary: netbird-ui
env: [CGO_ENABLED=1]
goos:
@@ -21,18 +21,7 @@ builds:
archives:
- builds:
- wiretrustee-ui-darwin
- netbird-ui-darwin
brews:
-
tap:
owner: wiretrustee
name: homebrew-client
token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
commit_author:
name: Wiretrustee
email: wiretrustee@wiretrustee.com
description: Wiretrustee project.
download_strategy: CurlDownloadStrategy
homepage: https://wiretrustee.com/
license: "BSD3"
changelog:
skip: true

103
README.md
View File

@@ -1,6 +1,6 @@
<p align="center">
<strong>Big News! Wiretrustee becomes Netbird</strong>.
<a href="https://blog.netbird.io/wiretrustee-becomes-netbird">
<a href="https://netbird.io/blog/wiretrustee-becomes-netbird">
Learn more
</a>
</p>
@@ -37,7 +37,7 @@
<strong>
Start using Netbird at <a href="https://app.netbird.io/">app.netbird.io</a>
<br/>
See <a href="https://docs.netbird.io">Documentation</a>
See <a href="https://netbird.io/docs/">Documentation</a>
<br/>
Join our <a href="https://join.slack.com/t/wiretrustee/shared_invite/zt-vrahf41g-ik1v7fV8du6t0RwxSrJ96A">Slack channel</a>
<br/>
@@ -86,7 +86,7 @@ Hosted version:
* Occasionally, the NAT traversal is unsuccessful due to strict NATs (e.g. mobile carrier-grade NAT). When this occurs the system falls back to the relay server (TURN), and a secure Wireguard tunnel is established via the TURN server. [Coturn](https://github.com/coturn/coturn) is the one that has been successfully used for STUN and TURN in Netbird setups.
<p float="left" align="middle">
<img src="https://docs.netbird.io/img/architecture/high-level-dia.png" width="700"/>
<img src="https://netbird.io/docs/img/architecture/high-level-dia.png" width="700"/>
</p>
@@ -105,11 +105,17 @@ Hosted version:
curl -L https://pkgs.wiretrustee.com/debian/public.key | sudo apt-key add -
echo 'deb https://pkgs.wiretrustee.com/debian stable main' | sudo tee /etc/apt/sources.list.d/wiretrustee.list
```
2. Install the package
2. Update APT's cache
```shell
sudo apt-get update
sudo apt-get install wiretrustee
```
3. Install the package
```shell
# for CLI only
sudo apt-get install netbird
# for GUI package
sudo apt-get install netbird-ui
```
**RPM/Red hat**
1. Add the repository:
```shell
@@ -125,26 +131,37 @@ Hosted version:
```
2. Install the package
```shell
sudo yum install wiretrustee
# for CLI only
sudo yum install netbird
# for GUI package
sudo yum install netbird-ui
```
#### MACOS
**Brew install**
1. Download and install Brew at https://brew.sh/
2. Install the client
```shell
brew install wiretrustee/client/wiretrustee
# for CLI only
brew install netbirdio/tap/netbird
# for GUI package
brew install --cask netbirdio/tap/netbird-ui
```
**Installation from binary**
3. As homebrew doesn't allow sudo exec, we need to install and start the client daemon:
```shell
sudo netbird service install
sudo netbird service start
```
**Installation from binary (CLI only)**
1. Checkout Netbird [releases](https://github.com/netbirdio/netbird/releases/latest)
2. Download the latest release (**Switch VERSION to the latest**):
```shell
curl -o ./wiretrustee_<VERSION>_darwin_amd64.tar.gz https://github.com/netbirdio/netbird/releases/download/v<VERSION>/wiretrustee_<VERSION>_darwin_amd64.tar.gz
curl -o ./netbird_<VERSION>_darwin_amd64.tar.gz https://github.com/netbirdio/netbird/releases/download/v<VERSION>/wiretrustee_<VERSION>_darwin_amd64.tar.gz
```
3. Decompress
```shell
tar xcf ./wiretrustee_<VERSION>_darwin_amd64.tar.gz
sudo mv wiretrusee /usr/bin/wiretrustee
chmod +x /usr/bin/wiretrustee
tar xcf ./netbird_<VERSION>_darwin_amd64.tar.gz
sudo mv netbird /usr/bin/netbird
chmod +x /usr/bin/netbird
```
After that you may need to add /usr/bin in your PATH environment variable:
````shell
@@ -152,47 +169,64 @@ Hosted version:
````
4. Install and run the service
```shell
sudo wiretrustee service install
sudo wiretrustee service start
sudo netbird service install
sudo netbird service start
```
#### Windows
1. Checkout Netbird [releases](https://github.com/netbirdio/netbird/releases/latest)
2. Download the latest Windows release installer ```wiretrustee_installer_<VERSION>_windows_amd64.exe``` (**Switch VERSION to the latest**):
2. Download the latest Windows release installer ```netbird_installer_<VERSION>_windows_amd64.exe``` (**Switch VERSION to the latest**):
3. Proceed with installation steps
4. This will install the client in the C:\\Program Files\\Wiretrustee and add the client service
4. This will install the client in the C:\\Program Files\\Netbird and add the client service
5. After installing, you can follow the [Client Configuration](#Client-Configuration) steps.
> To uninstall the client and service, you can use Add/Remove programs
### Client Configuration
If you installed the UI client, you can launch it and click on Connect
> It will open your browser, and you will be prompt for email and password
Simply run:
```shell
netbird up
```
> It will open your browser, and you will be prompt for email and password
Check connection status:
```shell
netbird status
```
In case you are activating a server peer, you can use a setup-key as described in the steps below:
1. Login to the Management Service. You need to have a `setup key` in hand (see ).
For **Unix** systems:
For all systems:
```shell
sudo wiretrustee up --setup-key <SETUP KEY>
netbird up --setup-key <SETUP KEY>
```
For **Windows** systems, start powershell as administrator and:
```shell
wiretrustee up --setup-key <SETUP KEY>
```
For **Docker**, you can run with the following command:
```shell
docker run --network host --privileged --rm -d -e WT_SETUP_KEY=<SETUP KEY> -v wiretrustee-client:/etc/wiretrustee wiretrustee/wiretrustee:<TAG>
docker run --network host --privileged --rm -d -e NB_SETUP_KEY=<SETUP KEY> -v netbird-client:/etc/netbird netbirdio/netbird:<TAG>
```
> TAG > 0.3.0 version
> TAG > 0.6.0 version
Alternatively, if you are hosting your own Management Service provide `--management-url` property pointing to your Management Service:
```shell
sudo wiretrustee up --setup-key <SETUP KEY> --management-url https://localhost:33073
sudo netbird up --setup-key <SETUP KEY> --management-url http://localhost:33073
```
> You could also omit the `--setup-key` property. In this case, the tool will prompt for the key.
2. Check connection status:
```shell
netbird status
```
2. Check your IP:
3. Check your IP:
For **MACOS** you will just start the service:
````shell
sudo ipconfig getifaddr utun100
sudo ifconfig utun100
````
For **Linux** systems:
```shell
@@ -203,25 +237,24 @@ For **Windows** systems:
netsh interface ip show config name="wt0"
```
3. Repeat on other machines.
4. Repeat on other machines.
### Troubleshooting
1. If you are using self-hosted version and haven't specified `--management-url`, the client app will use the default URL
which is ```https://api.wiretrustee.com:33073```.
1. If you have specified a wrong `--management-url` (e.g., just by mistake when self-hosting)
2. If you have specified a wrong `--management-url` (e.g., just by mistake when self-hosting)
to override it you can do the following:
```shell
sudo wiretrustee down
sudo wiretrustee up --management-url https://<CORRECT HOST:PORT>/
netbird down
netbird up --management-url https://<CORRECT HOST:PORT>/
```
2. If you are using self-hosted version and haven't specified `--management-url`, the client app will use the default URL
which is ```https://api.wiretrustee.com:33073```.
To override it see solution #1 above.
### Running Dashboard, Management, Signal and Coturn
See [Self-Hosting Guide](https://docs.netbird.io/getting-started/self-hosting)
See [Self-Hosting Guide](https://netbird.io/docs/getting-started/self-hosting)
### Legal

View File

@@ -1,4 +1,4 @@
FROM gcr.io/distroless/base:debug
ENV WT_LOG_FILE=console
ENTRYPOINT [ "/go/bin/wiretrustee","up"]
COPY wiretrustee /go/bin/wiretrustee
ENTRYPOINT [ "/go/bin/netbird","up"]
COPY netbird /go/bin/netbird

View File

@@ -13,11 +13,16 @@ import (
var downCmd = &cobra.Command{
Use: "down",
Short: "down wiretrustee connections",
Short: "down netbird connections",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
err := util.InitLog(logLevel, "console")
err := handleRebrand(cmd)
if err != nil {
return err
}
err = util.InitLog(logLevel, "console")
if err != nil {
log.Errorf("failed initializing log %v", err)
return err

View File

@@ -3,6 +3,7 @@ package cmd
import (
"context"
"fmt"
"github.com/netbirdio/netbird/client/system"
"github.com/skratchdot/open-golang/open"
"google.golang.org/grpc/codes"
gstatus "google.golang.org/grpc/status"
@@ -18,11 +19,16 @@ import (
var loginCmd = &cobra.Command{
Use: "login",
Short: "login to the Wiretrustee Management Service (first run)",
Short: "login to the Netbird Management Service (first run)",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
err := util.InitLog(logLevel, "console")
err := handleRebrand(cmd)
if err != nil {
return err
}
err = util.InitLog(logLevel, "console")
if err != nil {
return fmt.Errorf("failed initializing log %v", err)
}
@@ -102,8 +108,11 @@ var loginCmd = &cobra.Command{
func foregroundLogin(ctx context.Context, cmd *cobra.Command, config *internal.Config, setupKey string) error {
needsLogin := false
sysInfo := system.GetInfo()
sysInfo.Caller = system.NetBirdCLIUserAgent()
err := WithBackOff(func() error {
err := internal.Login(ctx, config, "", "")
err := internal.Login(ctx, config, "", "", sysInfo)
if s, ok := gstatus.FromError(err); ok && (s.Code() == codes.InvalidArgument || s.Code() == codes.PermissionDenied) {
needsLogin = true
return nil
@@ -124,7 +133,7 @@ func foregroundLogin(ctx context.Context, cmd *cobra.Command, config *internal.C
}
err = WithBackOff(func() error {
err := internal.Login(ctx, config, setupKey, jwtToken)
err := internal.Login(ctx, config, setupKey, jwtToken, sysInfo)
if s, ok := gstatus.FromError(err); ok && (s.Code() == codes.InvalidArgument || s.Code() == codes.PermissionDenied) {
return nil
}

View File

@@ -2,9 +2,15 @@ package cmd
import (
"context"
"errors"
"fmt"
"github.com/netbirdio/netbird/client/system"
"io"
"io/fs"
"io/ioutil"
"os"
"os/signal"
"path"
"runtime"
"strings"
"syscall"
@@ -21,18 +27,24 @@ import (
)
var (
configPath string
defaultConfigPath string
logLevel string
defaultLogFile string
logFile string
daemonAddr string
managementURL string
adminURL string
setupKey string
preSharedKey string
rootCmd = &cobra.Command{
Use: "wiretrustee",
configPath string
defaultConfigPathDir string
defaultConfigPath string
oldDefaultConfigPathDir string
oldDefaultConfigPath string
logLevel string
defaultLogFileDir string
defaultLogFile string
oldDefaultLogFileDir string
oldDefaultLogFile string
logFile string
daemonAddr string
managementURL string
adminURL string
setupKey string
preSharedKey string
rootCmd = &cobra.Command{
Use: "netbird",
Short: "",
Long: "",
SilenceUsage: true,
@@ -45,23 +57,36 @@ func Execute() error {
}
func init() {
defaultConfigPath = "/etc/wiretrustee/config.json"
defaultLogFile = "/var/log/wiretrustee/client.log"
defaultConfigPathDir = "/etc/netbird/"
defaultLogFileDir = "/var/log/netbird/"
oldDefaultConfigPathDir = "/etc/wiretrustee/"
oldDefaultLogFileDir = "/var/log/wiretrustee/"
if runtime.GOOS == "windows" {
defaultConfigPath = os.Getenv("PROGRAMDATA") + "\\Wiretrustee\\" + "config.json"
defaultLogFile = os.Getenv("PROGRAMDATA") + "\\Wiretrustee\\" + "client.log"
defaultConfigPathDir = os.Getenv("PROGRAMDATA") + "\\Netbird\\"
defaultLogFileDir = os.Getenv("PROGRAMDATA") + "\\Netbird\\"
oldDefaultConfigPathDir = os.Getenv("PROGRAMDATA") + "\\Wiretrustee\\"
oldDefaultLogFileDir = os.Getenv("PROGRAMDATA") + "\\Wiretrustee\\"
}
defaultDaemonAddr := "unix:///var/run/wiretrustee.sock"
defaultConfigPath = defaultConfigPathDir + "config.json"
defaultLogFile = defaultLogFileDir + "client.log"
oldDefaultConfigPath = oldDefaultConfigPathDir + "config.json"
oldDefaultLogFile = oldDefaultLogFileDir + "client.log"
defaultDaemonAddr := "unix:///var/run/netbird.sock"
if runtime.GOOS == "windows" {
defaultDaemonAddr = "tcp://127.0.0.1:41731"
}
rootCmd.PersistentFlags().StringVar(&daemonAddr, "daemon-addr", defaultDaemonAddr, "Daemon service address to serve CLI requests [unix|tcp]://[path|host:port]")
rootCmd.PersistentFlags().StringVar(&managementURL, "management-url", "", fmt.Sprintf("Management Service URL [http|https]://[host]:[port] (default \"%s\")", internal.ManagementURLDefault().String()))
rootCmd.PersistentFlags().StringVar(&adminURL, "admin-url", "https://app.netbird.io", "Admin Panel URL [http|https]://[host]:[port]")
rootCmd.PersistentFlags().StringVar(&configPath, "config", defaultConfigPath, "Wiretrustee config file location")
rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "sets Wiretrustee log level")
rootCmd.PersistentFlags().StringVar(&logFile, "log-file", defaultLogFile, "sets Wiretrustee log path. If console is specified the the log will be output to stdout")
rootCmd.PersistentFlags().StringVar(&configPath, "config", defaultConfigPath, "Netbird config file location")
rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "sets Netbird log level")
rootCmd.PersistentFlags().StringVar(&logFile, "log-file", defaultLogFile, "sets Netbird log path. If console is specified the the log will be output to stdout")
rootCmd.PersistentFlags().StringVar(&setupKey, "setup-key", "", "Setup key obtained from the Management Service Dashboard (used to register peer)")
rootCmd.PersistentFlags().StringVar(&preSharedKey, "preshared-key", "", "Sets Wireguard PreSharedKey property. If set, then only peers that have the same key can communicate.")
rootCmd.AddCommand(serviceCmd)
@@ -94,22 +119,30 @@ func SetupCloseHandler(ctx context.Context, cancel context.CancelFunc) {
func SetFlagsFromEnvVars() {
flags := rootCmd.PersistentFlags()
flags.VisitAll(func(f *pflag.Flag) {
envVar := FlagNameToEnvVar(f.Name)
oldEnvVar := FlagNameToEnvVar(f.Name, "WT_")
if value, present := os.LookupEnv(envVar); present {
if value, present := os.LookupEnv(oldEnvVar); present {
err := flags.Set(f.Name, value)
if err != nil {
log.Infof("unable to configure flag %s using variable %s, err: %v", f.Name, envVar, err)
log.Infof("unable to configure flag %s using variable %s, err: %v", f.Name, oldEnvVar, err)
}
}
newEnvVar := FlagNameToEnvVar(f.Name, "NB_")
if value, present := os.LookupEnv(newEnvVar); present {
err := flags.Set(f.Name, value)
if err != nil {
log.Infof("unable to configure flag %s using variable %s, err: %v", f.Name, newEnvVar, err)
}
}
})
}
// FlagNameToEnvVar converts flag name to environment var name adding a prefix,
// replacing dashes and making all uppercase (e.g. setup-keys is converted to WT_SETUP_KEYS)
func FlagNameToEnvVar(f string) string {
prefix := "WT_"
parsed := strings.ReplaceAll(f, "-", "_")
// replacing dashes and making all uppercase (e.g. setup-keys is converted to NB_SETUP_KEYS according to the input prefix)
func FlagNameToEnvVar(cmdFlag string, prefix string) string {
parsed := strings.ReplaceAll(cmdFlag, "-", "_")
upper := strings.ToUpper(parsed)
return prefix + upper
}
@@ -124,6 +157,7 @@ func DialClientGRPCServer(ctx context.Context, addr string) (*grpc.ClientConn, e
strings.TrimPrefix(addr, "tcp://"),
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithBlock(),
grpc.WithUserAgent(system.NetBirdCLIUserAgent()),
)
}
@@ -144,3 +178,113 @@ var CLIBackOffSettings = &backoff.ExponentialBackOff{
Stop: backoff.Stop,
Clock: backoff.SystemClock,
}
func handleRebrand(cmd *cobra.Command) error {
var err error
if logFile == defaultLogFile {
if migrateToNetbird(oldDefaultLogFile, defaultLogFile) {
cmd.Printf("will copy Log dir %s and its content to %s\n", oldDefaultLogFileDir, defaultLogFileDir)
err = cpDir(oldDefaultLogFileDir, defaultLogFileDir)
if err != nil {
return err
}
}
}
if configPath == defaultConfigPath {
if migrateToNetbird(oldDefaultConfigPath, defaultConfigPath) {
cmd.Printf("will copy Config dir %s and its content to %s\n", oldDefaultConfigPathDir, defaultConfigPathDir)
err = cpDir(oldDefaultConfigPathDir, defaultConfigPathDir)
if err != nil {
return err
}
}
}
return nil
}
func cpFile(src, dst string) error {
var err error
var srcfd *os.File
var dstfd *os.File
var srcinfo os.FileInfo
if srcfd, err = os.Open(src); err != nil {
return err
}
defer srcfd.Close()
if dstfd, err = os.Create(dst); err != nil {
return err
}
defer dstfd.Close()
if _, err = io.Copy(dstfd, srcfd); err != nil {
return err
}
if srcinfo, err = os.Stat(src); err != nil {
return err
}
return os.Chmod(dst, srcinfo.Mode())
}
func copySymLink(source, dest string) error {
link, err := os.Readlink(source)
if err != nil {
return err
}
return os.Symlink(link, dest)
}
func cpDir(src string, dst string) error {
var err error
var fds []os.FileInfo
var srcinfo os.FileInfo
if srcinfo, err = os.Stat(src); err != nil {
return err
}
if err = os.MkdirAll(dst, srcinfo.Mode()); err != nil {
return err
}
if fds, err = ioutil.ReadDir(src); err != nil {
return err
}
for _, fd := range fds {
srcfp := path.Join(src, fd.Name())
dstfp := path.Join(dst, fd.Name())
fileInfo, err := os.Stat(srcfp)
if err != nil {
return fmt.Errorf("fouldn't get fileInfo; %v", err)
}
switch fileInfo.Mode() & os.ModeType {
case os.ModeSymlink:
if err = copySymLink(srcfp, dstfp); err != nil {
return fmt.Errorf("failed to copy from %s to %s; %v", srcfp, dstfp, err)
}
case os.ModeDir:
if err = cpDir(srcfp, dstfp); err != nil {
return fmt.Errorf("failed to copy from %s to %s; %v", srcfp, dstfp, err)
}
default:
if err = cpFile(srcfp, dstfp); err != nil {
return fmt.Errorf("failed to copy from %s to %s; %v", srcfp, dstfp, err)
}
}
}
return nil
}
func migrateToNetbird(oldPath, newPath string) bool {
_, errOld := os.Stat(oldPath)
_, errNew := os.Stat(newPath)
if errors.Is(errOld, fs.ErrNotExist) || errNew == nil {
return false
}
return true
}

View File

@@ -24,8 +24,8 @@ func newProgram(ctx context.Context, cancel context.CancelFunc) *program {
func newSVCConfig() *service.Config {
return &service.Config{
Name: "wiretrustee",
DisplayName: "Wiretrustee",
Name: "netbird",
DisplayName: "Netbird",
Description: "A WireGuard-based mesh network that connects your devices into a single private network.",
}
}
@@ -41,5 +41,5 @@ func newSVC(prg *program, conf *service.Config) (service.Service, error) {
var serviceCmd = &cobra.Command{
Use: "service",
Short: "manages wiretrustee service",
Short: "manages Netbird service",
}

View File

@@ -76,20 +76,24 @@ func (p *program) Stop(srv service.Service) error {
}
time.Sleep(time.Second * 2)
log.Info("stopped Wiretrustee service") //nolint
log.Info("stopped Netbird service") //nolint
return nil
}
var runCmd = &cobra.Command{
Use: "run",
Short: "runs wiretrustee as service",
Run: func(cmd *cobra.Command, args []string) {
Short: "runs Netbird as service",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
err := util.InitLog(logLevel, logFile)
err := handleRebrand(cmd)
if err != nil {
log.Errorf("failed initializing log %v", err)
return
return err
}
err = util.InitLog(logLevel, logFile)
if err != nil {
return fmt.Errorf("failed initializing log %v", err)
}
ctx, cancel := context.WithCancel(cmd.Context())
@@ -97,27 +101,30 @@ var runCmd = &cobra.Command{
s, err := newSVC(newProgram(ctx, cancel), newSVCConfig())
if err != nil {
cmd.PrintErrln(err)
return
return err
}
err = s.Run()
if err != nil {
cmd.PrintErrln(err)
return
return err
}
cmd.Printf("Wiretrustee service is running")
cmd.Printf("Netbird service is running")
return nil
},
}
var startCmd = &cobra.Command{
Use: "start",
Short: "starts wiretrustee service",
Short: "starts Netbird service",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
err := util.InitLog(logLevel, logFile)
err := handleRebrand(cmd)
if err != nil {
return err
}
err = util.InitLog(logLevel, logFile)
if err != nil {
log.Errorf("failed initializing log %v", err)
return err
}
@@ -133,61 +140,69 @@ var startCmd = &cobra.Command{
cmd.PrintErrln(err)
return err
}
cmd.Println("Wiretrustee service has been started")
cmd.Println("Netbird service has been started")
return nil
},
}
var stopCmd = &cobra.Command{
Use: "stop",
Short: "stops wiretrustee service",
Run: func(cmd *cobra.Command, args []string) {
Short: "stops Netbird service",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
err := util.InitLog(logLevel, logFile)
err := handleRebrand(cmd)
if err != nil {
log.Errorf("failed initializing log %v", err)
return err
}
err = util.InitLog(logLevel, logFile)
if err != nil {
return fmt.Errorf("failed initializing log %v", err)
}
ctx, cancel := context.WithCancel(cmd.Context())
s, err := newSVC(newProgram(ctx, cancel), newSVCConfig())
if err != nil {
cmd.PrintErrln(err)
return
return err
}
err = s.Stop()
if err != nil {
cmd.PrintErrln(err)
return
return err
}
cmd.Println("Wiretrustee service has been stopped")
cmd.Println("Netbird service has been stopped")
return nil
},
}
var restartCmd = &cobra.Command{
Use: "restart",
Short: "restarts wiretrustee service",
Run: func(cmd *cobra.Command, args []string) {
Short: "restarts Netbird service",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
err := util.InitLog(logLevel, logFile)
err := handleRebrand(cmd)
if err != nil {
log.Errorf("failed initializing log %v", err)
return err
}
err = util.InitLog(logLevel, logFile)
if err != nil {
return fmt.Errorf("failed initializing log %v", err)
}
ctx, cancel := context.WithCancel(cmd.Context())
s, err := newSVC(newProgram(ctx, cancel), newSVCConfig())
if err != nil {
cmd.PrintErrln(err)
return
return err
}
err = s.Restart()
if err != nil {
cmd.PrintErrln(err)
return
return err
}
cmd.Println("Wiretrustee service has been restarted")
cmd.Println("Netbird service has been restarted")
return nil
},
}

View File

@@ -9,10 +9,15 @@ import (
var installCmd = &cobra.Command{
Use: "install",
Short: "installs wiretrustee service",
Short: "installs Netbird service",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
err := handleRebrand(cmd)
if err != nil {
return err
}
svcConfig := newSVCConfig()
svcConfig.Arguments = []string{
@@ -47,30 +52,34 @@ var installCmd = &cobra.Command{
cmd.PrintErrln(err)
return err
}
cmd.Println("Wiretrustee service has been installed")
cmd.Println("Netbird service has been installed")
return nil
},
}
var uninstallCmd = &cobra.Command{
Use: "uninstall",
Short: "uninstalls wiretrustee service from system",
Run: func(cmd *cobra.Command, args []string) {
Short: "uninstalls Netbird service from system",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
err := handleRebrand(cmd)
if err != nil {
return err
}
ctx, cancel := context.WithCancel(cmd.Context())
s, err := newSVC(newProgram(ctx, cancel), newSVCConfig())
if err != nil {
cmd.PrintErrln(err)
return
return err
}
err = s.Uninstall()
if err != nil {
cmd.PrintErrln(err)
return
return err
}
cmd.Println("Wiretrustee has been uninstalled")
cmd.Println("Netbird has been uninstalled")
return nil
},
}

View File

@@ -14,11 +14,16 @@ import (
var statusCmd = &cobra.Command{
Use: "status",
Short: "status of the Wiretrustee Service",
Short: "status of the Netbird Service",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
err := util.InitLog(logLevel, "console")
err := handleRebrand(cmd)
if err != nil {
return err
}
err = util.InitLog(logLevel, "console")
if err != nil {
return fmt.Errorf("failed initializing log %v", err)
}

View File

@@ -68,7 +68,10 @@ func startManagement(t *testing.T, config *mgmt.Config) (*grpc.Server, net.Liste
}
peersUpdateManager := mgmt.NewPeersUpdateManager()
accountManager := mgmt.NewManager(store, peersUpdateManager, nil)
accountManager, err := mgmt.BuildManager(store, peersUpdateManager, nil)
if err != nil {
t.Fatal(err)
}
turnManager := mgmt.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig)
mgmtServer, err := mgmt.NewServer(config, accountManager, peersUpdateManager, turnManager)
if err != nil {

View File

@@ -13,11 +13,16 @@ import (
var upCmd = &cobra.Command{
Use: "up",
Short: "install, login and start wiretrustee client",
Short: "install, login and start Netbird client",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
err := util.InitLog(logLevel, "console")
err := handleRebrand(cmd)
if err != nil {
return err
}
err = util.InitLog(logLevel, "console")
if err != nil {
return fmt.Errorf("failed initializing log %v", err)
}

View File

@@ -8,7 +8,7 @@ import (
var (
versionCmd = &cobra.Command{
Use: "version",
Short: "prints wiretrustee version",
Short: "prints Netbird version",
Run: func(cmd *cobra.Command, args []string) {
cmd.Println(system.WiretrusteeVersion())
},

View File

@@ -1,12 +1,12 @@
!define APP_NAME "Wiretrustee"
!define COMP_NAME "Wiretrustee"
!define WEB_SITE "wiretrustee.com"
!define APP_NAME "Netbird"
!define COMP_NAME "Netbird"
!define WEB_SITE "Netbird.io"
!define VERSION $%APPVER%
!define COPYRIGHT "Wiretrustee Authors, 2021"
!define COPYRIGHT "Netbird Authors, 2021"
!define DESCRIPTION "A WireGuard®-based mesh network that connects your devices into a single private network"
!define INSTALLER_NAME "wiretrustee-installer.exe"
!define MAIN_APP_EXE "Wiretrustee"
!define ICON "ui\\wiretrustee.ico"
!define INSTALLER_NAME "netbird-installer.exe"
!define MAIN_APP_EXE "Netbird"
!define ICON "ui\\netbird.ico"
!define BANNER "ui\\banner.bmp"
!define LICENSE_DATA "..\\LICENSE"
@@ -16,8 +16,8 @@
!define REG_APP_PATH "Software\Microsoft\Windows\CurrentVersion\App Paths\${MAIN_APP_EXE}"
!define UNINSTALL_PATH "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}"
!define UI_APP_NAME "Wiretrustee UI"
!define UI_APP_EXE "Wiretrustee-ui"
!define UI_APP_NAME "Netbird UI"
!define UI_APP_EXE "Netbird-ui"
!define UI_REG_APP_PATH "Software\Microsoft\Windows\CurrentVersion\App Paths\${UI_APP_EXE}"
!define UI_UNINSTALL_PATH "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UI_APP_NAME}"
@@ -83,8 +83,7 @@ Section -MainProgram
${INSTALL_TYPE}
SetOverwrite ifnewer
SetOutPath "$INSTDIR"
File /r "..\\dist\\wiretrustee_windows_amd64\\"
File /r "..\\dist\\wiretrustee-ui_windows_amd64\\"
File /r "..\\dist\\netbird_windows_amd64\\"
SectionEnd
@@ -92,18 +91,18 @@ SectionEnd
Section -Icons_Reg
SetOutPath "$INSTDIR"
WriteUninstaller "$INSTDIR\wiretrustee_uninstall.exe"
WriteUninstaller "$INSTDIR\netbird_uninstall.exe"
WriteRegStr ${REG_ROOT} "${REG_APP_PATH}" "" "$INSTDIR\${MAIN_APP_EXE}"
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayName" "${APP_NAME}"
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "UninstallString" "$INSTDIR\wiretrustee_uninstall.exe"
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "UninstallString" "$INSTDIR\netbird_uninstall.exe"
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayIcon" "$INSTDIR\${MAIN_APP_EXE}"
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayVersion" "${VERSION}"
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "Publisher" "${COMP_NAME}"
WriteRegStr ${REG_ROOT} "${UI_REG_APP_PATH}" "" "$INSTDIR\${UI_APP_EXE}"
WriteRegStr ${REG_ROOT} "${UI_UNINSTALL_PATH}" "DisplayName" "${UI_APP_NAME}"
WriteRegStr ${REG_ROOT} "${UI_UNINSTALL_PATH}" "UninstallString" "$INSTDIR\wiretrustee_uninstall.exe"
WriteRegStr ${REG_ROOT} "${UI_UNINSTALL_PATH}" "UninstallString" "$INSTDIR\netbird_uninstall.exe"
WriteRegStr ${REG_ROOT} "${UI_UNINSTALL_PATH}" "DisplayIcon" "$INSTDIR\${UI_APP_EXE}"
WriteRegStr ${REG_ROOT} "${UI_UNINSTALL_PATH}" "DisplayVersion" "${VERSION}"
WriteRegStr ${REG_ROOT} "${UI_UNINSTALL_PATH}" "Publisher" "${COMP_NAME}"
@@ -111,6 +110,9 @@ WriteRegStr ${REG_ROOT} "${UI_UNINSTALL_PATH}" "Publisher" "${COMP_NAME}"
EnVar::SetHKLM
EnVar::AddValueEx "path" "$INSTDIR"
CreateShortCut "${SMPROGRAMS}\${UI_APP_NAME}.lnk" "$INSTDIR\${UI_APP_EXE}"
CreateShortCut "${DESKTOP}\${UI_APP_NAME}.lnk" "$INSTDIR\${UI_APP_EXE}"
Exec '"$INSTDIR\${MAIN_APP_EXE}" service install'
Exec '"$INSTDIR\${MAIN_APP_EXE}" service start'
# sleep a bit for visibility

View File

@@ -2,6 +2,7 @@ package internal
import (
"context"
"github.com/netbirdio/netbird/client/system"
"time"
"github.com/netbirdio/netbird/iface"
@@ -193,7 +194,7 @@ func connectToManagement(ctx context.Context, managementAddr string, ourPrivateK
return nil, nil, status.Errorf(codes.FailedPrecondition, "failed while getting Management Service public key: %s", err)
}
loginResp, err := client.Login(*serverPublicKey)
loginResp, err := client.Login(*serverPublicKey, system.GetInfo())
if err != nil {
if s, ok := status.FromError(err); ok && s.Code() == codes.PermissionDenied {
log.Error("peer registration required. Please run wiretrustee login command first")

View File

@@ -455,7 +455,10 @@ func startManagement(port int, dataDir string) (*grpc.Server, error) {
log.Fatalf("failed creating a store: %s: %v", config.Datadir, err)
}
peersUpdateManager := server.NewPeersUpdateManager()
accountManager := server.NewManager(store, peersUpdateManager, nil)
accountManager, err := server.BuildManager(store, peersUpdateManager, nil)
if err != nil {
return nil, err
}
turnManager := server.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig)
mgmtServer, err := server.NewServer(config, accountManager, peersUpdateManager, turnManager)
if err != nil {

View File

@@ -12,7 +12,7 @@ import (
"google.golang.org/grpc/status"
)
func Login(ctx context.Context, config *Config, setupKey string, jwtToken string) error {
func Login(ctx context.Context, config *Config, setupKey string, jwtToken string, sysInfo *system.Info) error {
// validate our peer's Wireguard PRIVATE key
myPrivateKey, err := wgtypes.ParseKey(config.PrivateKey)
if err != nil {
@@ -39,7 +39,7 @@ func Login(ctx context.Context, config *Config, setupKey string, jwtToken string
return err
}
_, err = loginPeer(*serverKey, mgmClient, setupKey, jwtToken)
_, err = loginPeer(*serverKey, mgmClient, setupKey, jwtToken, sysInfo)
if err != nil {
log.Errorf("failed logging-in peer on Management Service : %v", err)
return err
@@ -55,8 +55,8 @@ func Login(ctx context.Context, config *Config, setupKey string, jwtToken string
}
// loginPeer attempts to login to Management Service. If peer wasn't registered, tries the registration flow.
func loginPeer(serverPublicKey wgtypes.Key, client *mgm.GrpcClient, setupKey string, jwtToken string) (*mgmProto.LoginResponse, error) {
loginResp, err := client.Login(serverPublicKey)
func loginPeer(serverPublicKey wgtypes.Key, client *mgm.GrpcClient, setupKey string, jwtToken string, sysInfo *system.Info) (*mgmProto.LoginResponse, error) {
loginResp, err := client.Login(serverPublicKey, sysInfo)
if err != nil {
if s, ok := status.FromError(err); ok && s.Code() == codes.PermissionDenied {
log.Debugf("peer registration required")

View File

@@ -3,10 +3,10 @@
<assemblyIdentity
version="0.0.0.1"
processorArchitecture="*"
name="wiretrustee.exe"
name="netbird.exe"
type="win32"
/>
<description>Wiretrustee application</description>
<description>Netbird application</description>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>

View File

@@ -5,5 +5,5 @@
#define STRINGIZE(x) #x
#define EXPAND(x) STRINGIZE(x)
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST manifest.xml
7 ICON ui/wiretrustee.ico
7 ICON ui/netbird.ico
wireguard.dll RCDATA wireguard.dll

View File

@@ -3,7 +3,9 @@ package server
import (
"context"
"fmt"
"github.com/netbirdio/netbird/client/system"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
gstatus "google.golang.org/grpc/status"
"sync"
"time"
@@ -90,6 +92,23 @@ func (s *Server) Start() error {
return nil
}
// loginAttempt attempts to login using the provided information. it returns a status in case something fails
func (s *Server) loginAttempt(ctx context.Context, setupKey, jwtToken string, sysInfo *system.Info) (internal.StatusType, error) {
var status internal.StatusType
err := internal.Login(ctx, s.config, setupKey, jwtToken, sysInfo)
if err != nil {
if s, ok := gstatus.FromError(err); ok && (s.Code() == codes.InvalidArgument || s.Code() == codes.PermissionDenied) {
log.Warnf("failed login: %v", err)
status = internal.StatusNeedsLogin
} else {
log.Errorf("failed login: %v", err)
status = internal.StatusLoginFailed
}
return status, err
}
return "", nil
}
// Login uses setup key to prepare configuration for the daemon.
func (s *Server) Login(_ context.Context, msg *proto.LoginRequest) (*proto.LoginResponse, error) {
s.mutex.Lock()
@@ -102,23 +121,23 @@ func (s *Server) Login(_ context.Context, msg *proto.LoginRequest) (*proto.Login
state := internal.CtxGetState(ctx)
defer func() {
s, err := state.Status()
if err != nil || (s != internal.StatusNeedsLogin && s != internal.StatusLoginFailed) {
status, err := state.Status()
if err != nil || (status != internal.StatusNeedsLogin && status != internal.StatusLoginFailed) {
state.Set(internal.StatusIdle)
}
}()
state.Set(internal.StatusConnecting)
s.mutex.Lock()
managementURL := s.managementURL
if msg.ManagementUrl != "" {
managementURL = msg.ManagementUrl
s.managementURL = msg.ManagementUrl
}
adminURL := s.adminURL
if msg.AdminURL != "" {
adminURL = msg.AdminURL
s.adminURL = msg.AdminURL
}
s.mutex.Unlock()
@@ -131,6 +150,19 @@ func (s *Server) Login(_ context.Context, msg *proto.LoginRequest) (*proto.Login
s.config = config
s.mutex.Unlock()
sysInfo := system.GetInfo()
agent := extractUserAgent(ctx)
if agent != "" {
sysInfo.Caller = agent
}
if _, err := s.loginAttempt(ctx, "", "", sysInfo); err == nil {
state.Set(internal.StatusIdle)
return &proto.LoginResponse{}, nil
}
state.Set(internal.StatusConnecting)
if msg.SetupKey == "" {
providerConfig, err := internal.GetDeviceAuthorizationFlowInfo(ctx, config)
if err != nil {
@@ -176,14 +208,8 @@ func (s *Server) Login(_ context.Context, msg *proto.LoginRequest) (*proto.Login
}, nil
}
if err := internal.Login(ctx, s.config, msg.SetupKey, ""); err != nil {
if s, ok := gstatus.FromError(err); ok && (s.Code() == codes.InvalidArgument || s.Code() == codes.PermissionDenied) {
log.Warnf("failed login with known status: %v", err)
state.Set(internal.StatusNeedsLogin)
} else {
log.Errorf("failed login: %v", err)
state.Set(internal.StatusLoginFailed)
}
if loginStatus, err := s.loginAttempt(ctx, msg.SetupKey, "", sysInfo); err != nil {
state.Set(loginStatus)
return nil, err
}
@@ -235,14 +261,14 @@ func (s *Server) WaitSSOLogin(_ context.Context, msg *proto.WaitSSOLoginRequest)
return nil, err
}
if err := internal.Login(ctx, s.config, "", tokenInfo.AccessToken); err != nil {
if s, ok := gstatus.FromError(err); ok && (s.Code() == codes.InvalidArgument || s.Code() == codes.PermissionDenied) {
log.Warnf("failed login: %v", err)
state.Set(internal.StatusNeedsLogin)
} else {
log.Errorf("failed login: %v", err)
state.Set(internal.StatusLoginFailed)
}
sysInfo := system.GetInfo()
agent := extractUserAgent(ctx)
if agent != "" {
sysInfo.Caller = agent
}
if loginStatus, err := s.loginAttempt(ctx, "", tokenInfo.AccessToken, sysInfo); err != nil {
state.Set(loginStatus)
return nil, err
}
@@ -350,3 +376,14 @@ func (s *Server) GetConfig(ctx context.Context, msg *proto.GetConfigRequest) (*p
PreSharedKey: preSharedKey,
}, nil
}
func extractUserAgent(ctx context.Context) string {
mD, ok := metadata.FromIncomingContext(ctx)
if ok {
agent, ok := mD["user-agent"]
if ok {
return agent[0]
}
}
return ""
}

View File

@@ -16,8 +16,18 @@ type Info struct {
Hostname string
CPUs int
WiretrusteeVersion string
Caller string
CallerVersion string
}
func WiretrusteeVersion() string {
return version
}
func NetBirdDesktopUIUserAgent() string {
return "netbird-desktop-ui/" + WiretrusteeVersion()
}
func NetBirdCLIUserAgent() string {
return "netbird-cli/" + WiretrusteeVersion()
}

12
client/ui/Info.plist Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>netbird-ui</string>
<key>CFBundleIconFile</key>
<string>Netbird</string>
<key>LSUIElement</key>
<string>1</string>
</dict>
</plist>

BIN
client/ui/Netbird.icns Normal file

Binary file not shown.

View File

@@ -5,6 +5,7 @@ import (
"flag"
"fmt"
"github.com/cenkalti/backoff/v4"
"github.com/netbirdio/netbird/client/system"
"io/ioutil"
"os"
"os/exec"
@@ -40,7 +41,7 @@ const (
func main() {
var daemonAddr string
defaultDaemonAddr := "unix:///var/run/wiretrustee.sock"
defaultDaemonAddr := "unix:///var/run/netbird.sock"
if runtime.GOOS == "windows" {
defaultDaemonAddr = "tcp://127.0.0.1:41731"
}
@@ -175,7 +176,7 @@ func (s *serviceClient) getSettingsForm() *widget.Form {
if s.iPreSharedKey.Text != "" && s.iPreSharedKey.Text != "**********" {
// validate preSharedKey if it added
if _, err := wgtypes.ParseKey(s.iPreSharedKey.Text); err != nil {
dialog.ShowError(fmt.Errorf("Invalid Pre-shared Key Value"), s.wSettings)
dialog.ShowError(fmt.Errorf("invalid Pre-shared Key Value"), s.wSettings)
return
}
}
@@ -247,11 +248,6 @@ func (s *serviceClient) login() error {
}
}
if _, err := s.conn.Up(s.ctx, &proto.UpRequest{}); err != nil {
log.Errorf("up service: %v", err)
return err
}
return nil
}
@@ -276,6 +272,12 @@ func (s *serviceClient) menuUpClick() error {
}
}
status, err = conn.Status(s.ctx, &proto.StatusRequest{})
if err != nil {
log.Errorf("get service status: %v", err)
return err
}
if status.Status != string(internal.StatusIdle) {
log.Warnf("already connected")
return nil
@@ -449,6 +451,7 @@ func (s *serviceClient) getSrvClient(timeout time.Duration) (proto.DaemonService
strings.TrimPrefix(s.addr, "tcp://"),
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithBlock(),
grpc.WithUserAgent(system.NetBirdDesktopUIUserAgent()),
)
if err != nil {
return nil, fmt.Errorf("dial service: %w", err)

17
client/ui/manifest.xml Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="0.0.0.1"
processorArchitecture="*"
name="netbird-ui.exe"
type="win32"
/>
<description>Netbird UI application</description>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View File

@@ -0,0 +1,23 @@
{{ $projectName := env.Getenv "PROJECT" }}{{ $amdFilePath := env.Getenv "AMD" }}{{ $armFilePath := env.Getenv "ARM" }}
{{ $amdURL := env.Getenv "AMD_URL" }}{{ $armURL := env.Getenv "ARM_URL" }}
{{ $amdFile := filepath.Base $amdFilePath }}{{ $armFile := filepath.Base $armFilePath }}{{ $amdFileBytes := file.Read $amdFilePath }}
{{ $armFileBytes := file.Read $armFilePath }}# Netbird's UI Client Cask Formula
cask "{{ $projectName }}" do
version "{{ env.Getenv "VERSION" }}"
if Hardware::CPU.intel?
url "{{ $amdURL }}"
sha256 "{{ crypto.SHA256 $amdFileBytes }}"
app "netbird_ui_darwin_amd64", target: "Netbird UI.app"
else
url "{{ $armURL }}"
sha256 "{{ crypto.SHA256 $armFileBytes }}"
app "netbird_ui_darwin_arm64", target: "Netbird UI.app"
end
depends_on formula: "netbird"
name "Netbird UI"
desc "Netbird UI Client"
homepage "https://www.netbird.io/"
end

View File

@@ -1,6 +1,6 @@
[Desktop Entry]
Name=Netbird Agent
Exec=/usr/bin/wiretrustee-ui
Exec=/usr/bin/netbird-ui
Icon=netbird
Type=Application
Terminal=false

BIN
client/ui/netbird.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

View File

@@ -47,32 +47,34 @@ For this tutorial we will be using domain ```test.netbird.io``` which points to
The [setup.env](../infrastructure_files/setup.env) file contains the following properties that have to be filled:
```bash
# e.g. app.mydomain.com
WIRETRUSTEE_DOMAIN=""
# Dashboard domain. e.g. app.mydomain.com
NETBIRD_DOMAIN=""
# e.g. dev-24vkclam.us.auth0.com
WIRETRUSTEE_AUTH0_DOMAIN=""
NETBIRD_AUTH0_DOMAIN=""
# e.g. 61u3JMXRO0oOevc7gCkZLCwePQvT4lL0
WIRETRUSTEE_AUTH0_CLIENT_ID=""
# e.g. https://app.mydomain.com/
WIRETRUSTEE_AUTH0_AUDIENCE=""
NETBIRD_AUTH0_CLIENT_ID=""
# e.g. https://app.mydomain.com/ or https://app.mydomain.com,
# Make sure you used the exact same value for Identifier
# you used when creating your Auth0 API
NETBIRD_AUTH0_AUDIENCE=""
# e.g. hello@mydomain.com
WIRETRUSTEE_LETSENCRYPT_EMAIL=""
NETBIRD_LETSENCRYPT_EMAIL=""
```
> Other options are available, but they are automatically updated.
Please follow the steps to get the values.
4. Configure ```WIRETRUSTEE_AUTH0_DOMAIN``` ```WIRETRUSTEE_AUTH0_CLIENT_ID``` ```WIRETRUSTEE_AUTH0_AUDIENCE``` properties.
4. Configure ```NETBIRD_AUTH0_DOMAIN``` ```NETBIRD_AUTH0_CLIENT_ID``` ```NETBIRD_AUTH0_AUDIENCE``` properties.
* To obtain these, please use [Auth0 React SDK Guide](https://auth0.com/docs/quickstart/spa/react/01-login#configure-auth0) up until "Install the Auth0 React SDK".
:grey_exclamation: Use ```https://YOUR DOMAIN``` as ````Allowed Callback URLs````, ```Allowed Logout URLs```, ```Allowed Web Origins``` and ```Allowed Origins (CORS)```
* set the variables in the ```setup.env```
5. Configure ```WIRETRUSTEE_AUTH0_AUDIENCE``` property.
5. Configure ```NETBIRD_AUTH0_AUDIENCE``` property.
* Check [Auth0 Golang API Guide](https://auth0.com/docs/quickstart/backend/golang) to obtain AuthAudience.
* set the property in the ```setup.env``` file.
6. Configure ```WIRETRUSTEE_LETSENCRYPT_EMAIL``` property.
6. Configure ```NETBIRD_LETSENCRYPT_EMAIL``` property.
This can be any email address. [Let's Encrypt](https://letsencrypt.org/) will create an account while generating a new certificate.
@@ -97,8 +99,8 @@ For this tutorial we will be using domain ```test.netbird.io``` which points to
docker-compose logs coturn
docker-compose logs dashboard
10. Once the server is running, you can access the dashboard by https://$WIRETRUSTEE_DOMAIN
11. Adding a peer will require you to enter the management URL by following the steps in the page https://$WIRETRUSTEE_DOMAIN/add-peer and in the 3rd step:
10. Once the server is running, you can access the dashboard by https://$NETBIRD_DOMAIN
11. Adding a peer will require you to enter the management URL by following the steps in the page https://$NETBIRD_DOMAIN/add-peer and in the 3rd step:
```shell
sudo wiretrustee up --setup-key <PASTE-SETUP-KEY> --management-url https://$WIRETRUSTEE_DOMAIN:33073
sudo netbird up --setup-key <PASTE-SETUP-KEY> --management-url https://$NETBIRD_DOMAIN:33073
```

View File

@@ -2,18 +2,18 @@
source setup.env
if [[ "x-$WIRETRUSTEE_DOMAIN" == "x-" ]]
if [[ "x-$NETBIRD_DOMAIN" == "x-" ]]
then
echo WIRETRUSTEE_DOMAIN is not set, please update your setup.env file
echo NETBIRD_DOMAIN is not set, please update your setup.env file
exit 1
fi
# local development or tests
if [[ $WIRETRUSTEE_DOMAIN == "localhost" || $WIRETRUSTEE_DOMAIN == "127.0.0.1" ]]
if [[ $NETBIRD_DOMAIN == "localhost" || $NETBIRD_DOMAIN == "127.0.0.1" ]]
then
export WIRETRUSTEE_MGMT_API_ENDPOINT=http://$WIRETRUSTEE_DOMAIN:$WIRETRUSTEE_MGMT_API_PORT
unset WIRETRUSTEE_MGMT_API_CERT_FILE
unset WIRETRUSTEE_MGMT_API_CERT_KEY_FILE
export NETBIRD_MGMT_API_ENDPOINT=http://$NETBIRD_DOMAIN:$NETBIRD_MGMT_API_PORT
unset NETBIRD_MGMT_API_CERT_FILE
unset NETBIRD_MGMT_API_CERT_KEY_FILE
fi
# if not provided, we generate a turn password
@@ -22,19 +22,19 @@ then
export TURN_PASSWORD=$(openssl rand -base64 32|sed 's/=//g')
fi
MGMT_VOLUMENAME="${$VOLUME_PREFIX}${MGMT_VOLUMESUFFIX}"
SIGNAL_VOLUMENAME="${$VOLUME_PREFIX}${SIGNAL_VOLUMESUFFIX}"
LETSENCRYPT_VOLUMENAME="${$VOLUME_PREFIX}${LETSENCRYPT_VOLUMESUFFIX}"
MGMT_VOLUMENAME="${VOLUME_PREFIX}${MGMT_VOLUMESUFFIX}"
SIGNAL_VOLUMENAME="${VOLUME_PREFIX}${SIGNAL_VOLUMESUFFIX}"
LETSENCRYPT_VOLUMENAME="${VOLUME_PREFIX}${LETSENCRYPT_VOLUMESUFFIX}"
# if volume with wiretrustee- prefix already exists, use it, else create new with netbird-
OLD_PREFIX='wiretrustee-'
if docker volume ls | grep -q "${OLD_PREFIX}${MGMT_VOLUMESUFFIX}"; then
MGMT_VOLUMENAME="${$OLD_PREFIX}${MGMT_VOLUMESUFFIX}"
MGMT_VOLUMENAME="${OLD_PREFIX}${MGMT_VOLUMESUFFIX}"
fi
if docker volume ls | grep -q "${OLD_PREFIX}${SIGNAL_VOLUMESUFFIX}"; then
SIGNAL_VOLUMENAME="${$OLD_PREFIX}${SIGNAL_VOLUMESUFFIX}"
SIGNAL_VOLUMENAME="${OLD_PREFIX}${SIGNAL_VOLUMESUFFIX}"
fi
if docker volume ls | grep -q "${OLD_PREFIX}${LETSENCRYPT_VOLUMESUFFIX}"; then
LETSENCRYPT_VOLUMENAME="${$OLD_PREFIX}${LETSENCRYPT_VOLUMESUFFIX}"
LETSENCRYPT_VOLUMENAME="${OLD_PREFIX}${LETSENCRYPT_VOLUMESUFFIX}"
fi
export MGMT_VOLUMENAME

View File

@@ -8,18 +8,18 @@ services:
- 80:80
- 443:443
environment:
- AUTH0_DOMAIN=$WIRETRUSTEE_AUTH0_DOMAIN
- AUTH0_CLIENT_ID=$WIRETRUSTEE_AUTH0_CLIENT_ID
- AUTH0_AUDIENCE=$WIRETRUSTEE_AUTH0_AUDIENCE
- WIRETRUSTEE_MGMT_API_ENDPOINT=$WIRETRUSTEE_MGMT_API_ENDPOINT
- AUTH0_DOMAIN=$NETBIRD_AUTH0_DOMAIN
- AUTH0_CLIENT_ID=$NETBIRD_AUTH0_CLIENT_ID
- AUTH0_AUDIENCE=$NETBIRD_AUTH0_AUDIENCE
- NETBIRD_MGMT_API_ENDPOINT=$NETBIRD_MGMT_API_ENDPOINT
- NGINX_SSL_PORT=443
- LETSENCRYPT_DOMAIN=$WIRETRUSTEE_DOMAIN
- LETSENCRYPT_EMAIL=$WIRETRUSTEE_LETSENCRYPT_EMAIL
- LETSENCRYPT_DOMAIN=$NETBIRD_DOMAIN
- LETSENCRYPT_EMAIL=$NETBIRD_LETSENCRYPT_EMAIL
volumes:
- $LETSENCRYPT_VOLUMENAME:/etc/letsencrypt/
# Signal
signal:
image: netbird/signal:latest
image: netbirdio/signal:latest
restart: unless-stopped
volumes:
- $SIGNAL_VOLUMENAME:/var/lib/netbird
@@ -27,10 +27,10 @@ services:
- 10000:10000
# # port and command for Let's Encrypt validation
# - 443:443
# command: ["--letsencrypt-domain", "$WIRETRUSTEE_DOMAIN", "--log-file", "console"]
# command: ["--letsencrypt-domain", "$NETBIRD_DOMAIN", "--log-file", "console"]
# Management
management:
image: netbird/management:latest
image: netbirdio/management:latest
restart: unless-stopped
depends_on:
- dashboard
@@ -40,15 +40,15 @@ services:
- ./management.json:/etc/netbird/management.json
ports:
- 33073:33073 #gRPC port
- $WIRETRUSTEE_MGMT_API_PORT:33071 #API port
- $NETBIRD_MGMT_API_PORT:33071 #API port
# # port and command for Let's Encrypt validation
# - 443:443
# command: ["--letsencrypt-domain", "$WIRETRUSTEE_DOMAIN", "--log-file", "console"]
# command: ["--letsencrypt-domain", "$NETBIRD_DOMAIN", "--log-file", "console"]
# Coturn
coturn:
image: coturn/coturn
restart: unless-stopped
domainname: $WIRETRUSTEE_DOMAIN
domainname: $NETBIRD_DOMAIN
volumes:
- ./turnserver.conf:/etc/turnserver.conf:ro
# - ./privkey.pem:/etc/coturn/private/privkey.pem:ro

View File

@@ -2,7 +2,7 @@
"Stuns": [
{
"Proto": "udp",
"URI": "stun:$WIRETRUSTEE_DOMAIN:3478",
"URI": "stun:$NETBIRD_DOMAIN:3478",
"Username": "",
"Password": null
}
@@ -11,7 +11,7 @@
"Turns": [
{
"Proto": "udp",
"URI": "turn:$WIRETRUSTEE_DOMAIN:3478",
"URI": "turn:$NETBIRD_DOMAIN:3478",
"Username": "$TURN_USER",
"Password": "$TURN_PASSWORD"
}
@@ -22,18 +22,18 @@
},
"Signal": {
"Proto": "http",
"URI": "$WIRETRUSTEE_DOMAIN:10000",
"URI": "$NETBIRD_DOMAIN:10000",
"Username": "",
"Password": null
},
"Datadir": "",
"HttpConfig": {
"Address": "0.0.0.0:$WIRETRUSTEE_MGMT_API_PORT",
"AuthIssuer": "https://$WIRETRUSTEE_AUTH0_DOMAIN/",
"AuthAudience": "$WIRETRUSTEE_AUTH0_AUDIENCE",
"AuthKeysLocation": "https://$WIRETRUSTEE_AUTH0_DOMAIN/.well-known/jwks.json",
"CertFile":"$WIRETRUSTEE_MGMT_API_CERT_FILE",
"CertKey":"$WIRETRUSTEE_MGMT_API_CERT_KEY_FILE"
"Address": "0.0.0.0:$NETBIRD_MGMT_API_PORT",
"AuthIssuer": "https://$NETBIRD_AUTH0_DOMAIN/",
"AuthAudience": "$NETBIRD_AUTH0_AUDIENCE",
"AuthKeysLocation": "https://$NETBIRD_AUTH0_DOMAIN/.well-known/jwks.json",
"CertFile":"$NETBIRD_MGMT_API_CERT_FILE",
"CertKey":"$NETBIRD_MGMT_API_CERT_KEY_FILE"
},
"IdpManagerConfig": {
"Manager": "none"

View File

@@ -1,30 +1,30 @@
# Dashboard domain and auth0 configuration
# Dashboard domain. e.g. app.mydomain.com
WIRETRUSTEE_DOMAIN=""
NETBIRD_DOMAIN=""
# e.g. dev-24vkclam.us.auth0.com
WIRETRUSTEE_AUTH0_DOMAIN=""
NETBIRD_AUTH0_DOMAIN=""
# e.g. 61u3JMXRO0oOevc7gCkZLCwePQvT4lL0
WIRETRUSTEE_AUTH0_CLIENT_ID=""
NETBIRD_AUTH0_CLIENT_ID=""
# e.g. https://app.mydomain.com/ or https://app.mydomain.com,
# Make sure you used the exact same value for Identifier
# you used when creating your Auth0 API
WIRETRUSTEE_AUTH0_AUDIENCE=""
NETBIRD_AUTH0_AUDIENCE=""
# e.g. hello@mydomain.com
WIRETRUSTEE_LETSENCRYPT_EMAIL=""
NETBIRD_LETSENCRYPT_EMAIL=""
## From this point, most settings are being done automatically, but you can edit if you need some customization
# Management API
# Management API port
WIRETRUSTEE_MGMT_API_PORT=33071
NETBIRD_MGMT_API_PORT=33071
# Management API endpoint address, used by the Dashboard
WIRETRUSTEE_MGMT_API_ENDPOINT=https://$WIRETRUSTEE_DOMAIN:$WIRETRUSTEE_MGMT_API_PORT
NETBIRD_MGMT_API_ENDPOINT=https://$NETBIRD_DOMAIN:$NETBIRD_MGMT_API_PORT
# Management Certficate file path. These are generated by the Dashboard container
WIRETRUSTEE_MGMT_API_CERT_FILE="/etc/letsencrypt/live/$WIRETRUSTEE_DOMAIN/fullchain.pem"
NETBIRD_MGMT_API_CERT_FILE="/etc/letsencrypt/live/$NETBIRD_DOMAIN/fullchain.pem"
# Management Certficate key file path.
WIRETRUSTEE_MGMT_API_CERT_KEY_FILE="/etc/letsencrypt/live/$WIRETRUSTEE_DOMAIN/privkey.pem"
NETBIRD_MGMT_API_CERT_KEY_FILE="/etc/letsencrypt/live/$NETBIRD_DOMAIN/privkey.pem"
# Turn credentials
@@ -43,15 +43,15 @@ SIGNAL_VOLUMESUFFIX="signal"
LETSENCRYPT_VOLUMESUFFIX="letsencrypt"
# exports
export WIRETRUSTEE_DOMAIN
export WIRETRUSTEE_AUTH0_DOMAIN
export WIRETRUSTEE_AUTH0_CLIENT_ID
export WIRETRUSTEE_AUTH0_AUDIENCE
export WIRETRUSTEE_LETSENCRYPT_EMAIL
export WIRETRUSTEE_MGMT_API_PORT
export WIRETRUSTEE_MGMT_API_ENDPOINT
export WIRETRUSTEE_MGMT_API_CERT_FILE
export WIRETRUSTEE_MGMT_API_CERT_KEY_FILE
export NETBIRD_DOMAIN
export NETBIRD_AUTH0_DOMAIN
export NETBIRD_AUTH0_CLIENT_ID
export NETBIRD_AUTH0_AUDIENCE
export NETBIRD_LETSENCRYPT_EMAIL
export NETBIRD_MGMT_API_PORT
export NETBIRD_MGMT_API_ENDPOINT
export NETBIRD_MGMT_API_CERT_FILE
export NETBIRD_MGMT_API_CERT_KEY_FILE
export TURN_USER
export TURN_PASSWORD
export TURN_MIN_PORT

View File

@@ -10,16 +10,17 @@ Usage:
netbird-mgmt management [flags]
Flags:
--datadir string server data directory location (default "/var/lib/netbird/")
--cert-file string Location of your SSL certificate. Can be used when you have an existing certificate and don't want a new certificate be generated automatically. If letsencrypt-domain is specified this property has no effect
--cert-key string Location of your SSL certificate private key. Can be used when you have an existing certificate and don't want a new certificate be generated automatically. If letsencrypt-domain is specified this property has no effect
--datadir string server data directory location
-h, --help help for management
--letsencrypt-domain string a domain to issue Let's Encrypt certificate for. Enables TLS using Let's Encrypt. Will fetch and renew certificate, and run the server with TLS
--port int server port to listen on (default 33073)
--cert-file string Location of your SSL certificate. Can be used when you have an existing certificate and don't want a new certificate be generated automatically. If letsencrypt-domain is specified this property has no effect
--cert-key string Location of your SSL certificate private key. Can be used when you have an existing certificate and don't want a new certificate be generated automatically. If letsencrypt-domain is specified this property has no effect
Global Flags:
--config string Netbird config file location to write new config to (default "/etc/netbird/config.json")
--log-level string (default "info")
--config string Netbird config file location to write new config to (default "/etc/netbird")
--log-file string sets Netbird log path. If console is specified the the log will be output to stdout (default "/var/log/netbird/management.log")
--log-level string (default "info")
```
## Run Management service (Docker)
@@ -42,7 +43,7 @@ docker run -d --name netbird-management \
-p 443:443 \
-v netbird-mgmt:/var/lib/netbird \
-v ./config.json:/etc/netbird/config.json \
netbird/management:latest \
netbirdio/management:latest \
--letsencrypt-domain <YOUR-DOMAIN>
```
> An example of config.json can be found here [management.json](../infrastructure_files/management.json.tmpl)
@@ -81,7 +82,7 @@ docker run -d --name netbird-management \
-p 33073:33073 \
-v netbird-mgmt:/var/lib/netbird \
-v ./config.json:/etc/netbird/config.json \
netbird/management:latest
netbirdio/management:latest
```
### Debug tag
We also publish a docker image with the debug tag which has the log-level set to default, plus it uses the ```gcr.io/distroless/base:debug``` image that can be used with docker exec in order to run some commands in the Management container.
@@ -90,7 +91,7 @@ shell $ docker run -d --name netbird-management-debug \
-p 33073:33073 \
-v netbird-mgmt:/var/lib/netbird \
-v ./config.json:/etc/netbird/config.json \
netbird/management:debug-latest
netbirdio/management:debug-latest
shell $ docker exec -ti netbird-management-debug /bin/sh
container-shell $

View File

@@ -13,6 +13,6 @@ type Client interface {
Sync(msgHandler func(msg *proto.SyncResponse) error) error
GetServerPublicKey() (*wgtypes.Key, error)
Register(serverKey wgtypes.Key, setupKey string, jwtToken string, info *system.Info) (*proto.LoginResponse, error)
Login(serverKey wgtypes.Key) (*proto.LoginResponse, error)
Login(serverKey wgtypes.Key, info *system.Info) (*proto.LoginResponse, error)
GetDeviceAuthorizationFlow(serverKey wgtypes.Key) (*proto.DeviceAuthorizationFlow, error)
}

View File

@@ -28,7 +28,6 @@ import (
const ValidKey = "A2C8E62B-38F5-4553-B31E-DD66C696CEBB"
func startManagement(t *testing.T) (*grpc.Server, net.Listener) {
level, _ := log.ParseLevel("debug")
log.SetLevel(level)
@@ -56,7 +55,10 @@ func startManagement(t *testing.T) (*grpc.Server, net.Listener) {
}
peersUpdateManager := mgmt.NewPeersUpdateManager()
accountManager := mgmt.NewManager(store, peersUpdateManager, nil)
accountManager, err := mgmt.BuildManager(store, peersUpdateManager, nil)
if err != nil {
t.Fatal(err)
}
turnManager := mgmt.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig)
mgmtServer, err := mgmt.NewServer(config, accountManager, peersUpdateManager, turnManager)
if err != nil {
@@ -155,7 +157,7 @@ func TestClient_LoginUnregistered_ShouldThrow_401(t *testing.T) {
if err != nil {
t.Fatal(err)
}
_, err = client.Login(*key)
_, err = client.Login(*key, nil)
if err == nil {
t.Error("expecting err on unregistered login, got nil")
}
@@ -256,6 +258,7 @@ func TestClient_Sync(t *testing.T) {
}
if len(resp.GetRemotePeers()) != 1 {
t.Errorf("expecting RemotePeers size %d got %d", 1, len(resp.GetRemotePeers()))
return
}
if resp.GetRemotePeersIsEmpty() == true {
t.Error("expecting RemotePeers property to be false, got true")
@@ -295,37 +298,36 @@ func Test_SystemMetaDataFromClient(t *testing.T) {
var wg sync.WaitGroup
wg.Add(1)
mgmtMockServer.LoginFunc =
func(ctx context.Context, msg *proto.EncryptedMessage) (*proto.EncryptedMessage, error) {
peerKey, err := wgtypes.ParseKey(msg.GetWgPubKey())
if err != nil {
log.Warnf("error while parsing peer's Wireguard public key %s on Sync request.", msg.WgPubKey)
return nil, status.Errorf(codes.InvalidArgument, "provided wgPubKey %s is invalid", msg.WgPubKey)
}
loginReq := &proto.LoginRequest{}
err = encryption.DecryptMessage(peerKey, serverKey, msg.Body, loginReq)
if err != nil {
log.Fatal(err)
}
actualMeta = loginReq.GetMeta()
actualValidKey = loginReq.GetSetupKey()
wg.Done()
loginResp := &proto.LoginResponse{}
encryptedResp, err := encryption.EncryptMessage(peerKey, serverKey, loginResp)
if err != nil {
return nil, err
}
return &mgmtProto.EncryptedMessage{
WgPubKey: serverKey.PublicKey().String(),
Body: encryptedResp,
Version: 0,
}, nil
mgmtMockServer.LoginFunc = func(ctx context.Context, msg *proto.EncryptedMessage) (*proto.EncryptedMessage, error) {
peerKey, err := wgtypes.ParseKey(msg.GetWgPubKey())
if err != nil {
log.Warnf("error while parsing peer's Wireguard public key %s on Sync request.", msg.WgPubKey)
return nil, status.Errorf(codes.InvalidArgument, "provided wgPubKey %s is invalid", msg.WgPubKey)
}
loginReq := &proto.LoginRequest{}
err = encryption.DecryptMessage(peerKey, serverKey, msg.Body, loginReq)
if err != nil {
log.Fatal(err)
}
actualMeta = loginReq.GetMeta()
actualValidKey = loginReq.GetSetupKey()
wg.Done()
loginResp := &proto.LoginResponse{}
encryptedResp, err := encryption.EncryptMessage(peerKey, serverKey, loginResp)
if err != nil {
return nil, err
}
return &mgmtProto.EncryptedMessage{
WgPubKey: serverKey.PublicKey().String(),
Body: encryptedResp,
Version: 0,
}, nil
}
info := system.GetInfo()
_, err = testClient.Register(*key, ValidKey, "", info)
if err != nil {
@@ -370,21 +372,19 @@ func Test_GetDeviceAuthorizationFlow(t *testing.T) {
ProviderConfig: &proto.ProviderConfig{ClientID: "client"},
}
mgmtMockServer.GetDeviceAuthorizationFlowFunc =
func(ctx context.Context, req *mgmtProto.EncryptedMessage) (*proto.EncryptedMessage, error) {
encryptedResp, err := encryption.EncryptMessage(serverKey, client.key, expectedFlowInfo)
if err != nil {
return nil, err
}
return &mgmtProto.EncryptedMessage{
WgPubKey: serverKey.PublicKey().String(),
Body: encryptedResp,
Version: 0,
}, nil
mgmtMockServer.GetDeviceAuthorizationFlowFunc = func(ctx context.Context, req *mgmtProto.EncryptedMessage) (*proto.EncryptedMessage, error) {
encryptedResp, err := encryption.EncryptMessage(serverKey, client.key, expectedFlowInfo)
if err != nil {
return nil, err
}
return &mgmtProto.EncryptedMessage{
WgPubKey: serverKey.PublicKey().String(),
Body: encryptedResp,
Version: 0,
}, nil
}
flowInfo, err := client.GetDeviceAuthorizationFlow(serverKey)
if err != nil {
t.Error("error while retrieving device auth flow information")

View File

@@ -229,21 +229,17 @@ func (c *GrpcClient) login(serverKey wgtypes.Key, req *proto.LoginRequest) (*pro
// Takes care of encrypting and decrypting messages.
// This method will also collect system info and send it with the request (e.g. hostname, os, etc)
func (c *GrpcClient) Register(serverKey wgtypes.Key, setupKey string, jwtToken string, info *system.Info) (*proto.LoginResponse, error) {
meta := &proto.PeerSystemMeta{
Hostname: info.Hostname,
GoOS: info.GoOS,
OS: info.OS,
Core: info.OSVersion,
Platform: info.Platform,
Kernel: info.Kernel,
WiretrusteeVersion: info.WiretrusteeVersion,
}
return c.login(serverKey, &proto.LoginRequest{SetupKey: setupKey, Meta: meta, JwtToken: jwtToken})
return c.login(serverKey,
&proto.LoginRequest{
SetupKey: setupKey,
Meta: infoToMetaData(info),
JwtToken: jwtToken,
})
}
// Login attempts login to Management Server. Takes care of encrypting and decrypting messages.
func (c *GrpcClient) Login(serverKey wgtypes.Key) (*proto.LoginResponse, error) {
return c.login(serverKey, &proto.LoginRequest{})
func (c *GrpcClient) Login(serverKey wgtypes.Key, info *system.Info) (*proto.LoginResponse, error) {
return c.login(serverKey, &proto.LoginRequest{Meta: infoToMetaData(info)})
}
// GetDeviceAuthorizationFlow returns a device authorization flow information.
@@ -279,3 +275,19 @@ func (c *GrpcClient) GetDeviceAuthorizationFlow(serverKey wgtypes.Key) (*proto.D
return flowInfoResp, nil
}
func infoToMetaData(info *system.Info) *proto.PeerSystemMeta {
if info == nil {
return nil
}
return &proto.PeerSystemMeta{
Hostname: info.Hostname,
GoOS: info.GoOS,
OS: info.OS,
Core: info.OSVersion,
Platform: info.Platform,
Kernel: info.Kernel,
WiretrusteeVersion: info.WiretrusteeVersion,
Caller: info.Caller,
}
}

View File

@@ -43,7 +43,7 @@ func (m *MockClient) Register(serverKey wgtypes.Key, setupKey string, jwtToken s
return m.RegisterFunc(serverKey, setupKey, jwtToken, info)
}
func (m *MockClient) Login(serverKey wgtypes.Key) (*proto.LoginResponse, error) {
func (m *MockClient) Login(serverKey wgtypes.Key, info *system.Info) (*proto.LoginResponse, error) {
if m.LoginFunc == nil {
return nil, nil
}

View File

@@ -3,9 +3,11 @@ package cmd
import (
"context"
"crypto/tls"
"errors"
"flag"
"fmt"
"io"
"io/fs"
"io/ioutil"
"net"
"os"
@@ -108,20 +110,23 @@ var (
}
}
accountManager := server.NewManager(store, peersUpdateManager, idpManager)
accountManager, err := server.BuildManager(store, peersUpdateManager, idpManager)
if err != nil {
log.Fatalln("failed build default manager: ", err)
}
var opts []grpc.ServerOption
var httpServer *http.Server
if config.HttpConfig.LetsEncryptDomain != "" {
//automatically generate a new certificate with Let's Encrypt
// automatically generate a new certificate with Let's Encrypt
certManager := encryption.CreateCertManager(config.Datadir, config.HttpConfig.LetsEncryptDomain)
transportCredentials := credentials.NewTLS(certManager.TLSConfig())
opts = append(opts, grpc.Creds(transportCredentials))
httpServer = http.NewHttpsServer(config.HttpConfig, certManager, accountManager)
} else if config.HttpConfig.CertFile != "" && config.HttpConfig.CertKey != "" {
//use provided certificate
// use provided certificate
tlsConfig, err := loadTLSConfig(config.HttpConfig.CertFile, config.HttpConfig.CertKey)
if err != nil {
log.Fatal("cannot load TLS credentials: ", err)
@@ -130,7 +135,7 @@ var (
opts = append(opts, grpc.Creds(transportCredentials))
httpServer = http.NewHttpsServerWithTLSConfig(config.HttpConfig, tlsConfig, accountManager)
} else {
//start server without SSL
// start server without SSL
httpServer = http.NewHttpServer(config.HttpConfig, accountManager)
}
@@ -291,10 +296,10 @@ func cpDir(src string, dst string) error {
}
func migrateToNetbird(oldPath, newPath string) bool {
_, old := os.Stat(oldPath)
_, new := os.Stat(newPath)
_, errOld := os.Stat(oldPath)
_, errNew := os.Stat(newPath)
if os.IsNotExist(old) || os.IsExist(new) {
if errors.Is(errOld, fs.ErrNotExist) || errNew == nil {
return false
}
@@ -309,5 +314,4 @@ func init() {
mgmtCmd.Flags().StringVar(&certFile, "cert-file", "", "Location of your SSL certificate. Can be used when you have an existing certificate and don't want a new certificate be generated automatically. If letsencrypt-domain is specified this property has no effect")
mgmtCmd.Flags().StringVar(&certKey, "cert-key", "", "Location of your SSL certificate private key. Can be used when you have an existing certificate and don't want a new certificate be generated automatically. If letsencrypt-domain is specified this property has no effect")
rootCmd.MarkFlagRequired("config") //nolint
}

View File

@@ -1,15 +1,15 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.19.4
// protoc v3.12.4
// source: management.proto
package proto
import (
timestamp "github.com/golang/protobuf/ptypes/timestamp"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
sync "sync"
)
@@ -387,6 +387,7 @@ type PeerSystemMeta struct {
Platform string `protobuf:"bytes,5,opt,name=platform,proto3" json:"platform,omitempty"`
OS string `protobuf:"bytes,6,opt,name=OS,proto3" json:"OS,omitempty"`
WiretrusteeVersion string `protobuf:"bytes,7,opt,name=wiretrusteeVersion,proto3" json:"wiretrusteeVersion,omitempty"`
Caller string `protobuf:"bytes,8,opt,name=caller,proto3" json:"caller,omitempty"`
}
func (x *PeerSystemMeta) Reset() {
@@ -470,6 +471,13 @@ func (x *PeerSystemMeta) GetWiretrusteeVersion() string {
return ""
}
func (x *PeerSystemMeta) GetCaller() string {
if x != nil {
return x.Caller
}
return ""
}
type LoginResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -535,7 +543,7 @@ type ServerKeyResponse struct {
// Server's Wireguard public key
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
// Key expiration timestamp after which the key should be fetched again by the client
ExpiresAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=expiresAt,proto3" json:"expiresAt,omitempty"`
ExpiresAt *timestamp.Timestamp `protobuf:"bytes,2,opt,name=expiresAt,proto3" json:"expiresAt,omitempty"`
// Version of the Wiretrustee Management Service protocol
Version int32 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"`
}
@@ -579,7 +587,7 @@ func (x *ServerKeyResponse) GetKey() string {
return ""
}
func (x *ServerKeyResponse) GetExpiresAt() *timestamppb.Timestamp {
func (x *ServerKeyResponse) GetExpiresAt() *timestamp.Timestamp {
if x != nil {
return x.ExpiresAt
}
@@ -1231,7 +1239,7 @@ var file_management_proto_rawDesc = []byte{
0x74, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4d, 0x65, 0x74, 0x61,
0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x6a, 0x77, 0x74, 0x54, 0x6f, 0x6b,
0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6a, 0x77, 0x74, 0x54, 0x6f, 0x6b,
0x65, 0x6e, 0x22, 0xc8, 0x01, 0x0a, 0x0e, 0x50, 0x65, 0x65, 0x72, 0x53, 0x79, 0x73, 0x74, 0x65,
0x65, 0x6e, 0x22, 0xe0, 0x01, 0x0a, 0x0e, 0x50, 0x65, 0x65, 0x72, 0x53, 0x79, 0x73, 0x74, 0x65,
0x6d, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d,
0x65, 0x12, 0x12, 0x0a, 0x04, 0x67, 0x6f, 0x4f, 0x53, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
@@ -1243,122 +1251,124 @@ var file_management_proto_rawDesc = []byte{
0x02, 0x4f, 0x53, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x4f, 0x53, 0x12, 0x2e, 0x0a,
0x12, 0x77, 0x69, 0x72, 0x65, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x65, 0x56, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x77, 0x69, 0x72, 0x65, 0x74,
0x72, 0x75, 0x73, 0x74, 0x65, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x94, 0x01,
0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x4b, 0x0a, 0x11, 0x77, 0x69, 0x72, 0x65, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x65, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6d, 0x61, 0x6e,
0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x57, 0x69, 0x72, 0x65, 0x74, 0x72, 0x75, 0x73,
0x74, 0x65, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x77, 0x69, 0x72, 0x65, 0x74,
0x72, 0x75, 0x73, 0x74, 0x65, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x0a,
0x70, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x65,
0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0a, 0x70, 0x65, 0x65, 0x72, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x22, 0x79, 0x0a, 0x11, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4b, 0x65,
0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x38, 0x0a, 0x09, 0x65,
0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x65, 0x78, 0x70, 0x69,
0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22,
0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0xa8, 0x01, 0x0a, 0x11, 0x57, 0x69, 0x72,
0x65, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2c,
0x0a, 0x05, 0x73, 0x74, 0x75, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e,
0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x05, 0x73, 0x74, 0x75, 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x05,
0x74, 0x75, 0x72, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6d, 0x61,
0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74,
0x65, 0x64, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x05, 0x74, 0x75,
0x72, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74,
0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x73, 0x69, 0x67,
0x6e, 0x61, 0x6c, 0x22, 0x98, 0x01, 0x0a, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x03, 0x75, 0x72, 0x69, 0x12, 0x3b, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x50,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x22, 0x3b, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x07, 0x0a,
0x03, 0x55, 0x44, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x10, 0x01, 0x12,
0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x48, 0x54, 0x54,
0x50, 0x53, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x54, 0x4c, 0x53, 0x10, 0x04, 0x22, 0x7d,
0x0a, 0x13, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x48, 0x6f, 0x73, 0x74, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x0a, 0x68, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x61,
0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x52, 0x0a, 0x68, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a,
0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65,
0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20,
0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x38, 0x0a,
0x0a, 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x61,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64,
0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x64, 0x6e, 0x73, 0x22, 0xcc, 0x01, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x77,
0x6f, 0x72, 0x6b, 0x4d, 0x61, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c,
0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x36,
0x0a, 0x0a, 0x70, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e,
0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0a, 0x70, 0x65, 0x65, 0x72,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3e, 0x0a, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65,
0x50, 0x65, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x61,
0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50,
0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74,
0x65, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65,
0x50, 0x65, 0x65, 0x72, 0x73, 0x49, 0x73, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01,
0x28, 0x08, 0x52, 0x12, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x73, 0x49,
0x73, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x4e, 0x0a, 0x10, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65,
0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x67,
0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x67,
0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65,
0x64, 0x49, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x6c, 0x6c, 0x6f,
0x77, 0x65, 0x64, 0x49, 0x70, 0x73, 0x22, 0x20, 0x0a, 0x1e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6c, 0x6f,
0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xbf, 0x01, 0x0a, 0x17, 0x44, 0x65, 0x76,
0x69, 0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x46, 0x6c, 0x6f, 0x77, 0x12, 0x48, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6c, 0x6f, 0x77, 0x2e, 0x70, 0x72, 0x6f, 0x76,
0x69, 0x64, 0x65, 0x72, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x42,
0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x52, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x22, 0x16, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x0a,
0x0a, 0x06, 0x48, 0x4f, 0x53, 0x54, 0x45, 0x44, 0x10, 0x00, 0x22, 0x84, 0x01, 0x0a, 0x0e, 0x50,
0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a,
0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x22, 0x0a, 0x0c, 0x43, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x16, 0x0a,
0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x44,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x41, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63,
0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x41, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63,
0x65, 0x32, 0xf7, 0x02, 0x0a, 0x11, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74,
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x45, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e,
0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e,
0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c,
0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72,
0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x46,
0x0a, 0x04, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d,
0x72, 0x75, 0x73, 0x74, 0x65, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a,
0x06, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63,
0x61, 0x6c, 0x6c, 0x65, 0x72, 0x22, 0x94, 0x01, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x11, 0x77, 0x69, 0x72, 0x65, 0x74,
0x72, 0x75, 0x73, 0x74, 0x65, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e,
0x57, 0x69, 0x72, 0x65, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x52, 0x11, 0x77, 0x69, 0x72, 0x65, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x65, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67,
0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x52, 0x0a, 0x70, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x79, 0x0a, 0x11,
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
0x6b, 0x65, 0x79, 0x12, 0x38, 0x0a, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x6d, 0x70, 0x52, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x18, 0x0a,
0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07,
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79,
0x22, 0xa8, 0x01, 0x0a, 0x11, 0x57, 0x69, 0x72, 0x65, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x65,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2c, 0x0a, 0x05, 0x73, 0x74, 0x75, 0x6e, 0x73, 0x18,
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65,
0x6e, 0x74, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x05, 0x73,
0x74, 0x75, 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x05, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x18, 0x02, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74,
0x2e, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x52, 0x05, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x06, 0x73,
0x69, 0x67, 0x6e, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61,
0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x22, 0x98, 0x01, 0x0a, 0x0a,
0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72,
0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x3b, 0x0a, 0x08,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f,
0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x48, 0x6f, 0x73, 0x74,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52,
0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x22, 0x3b, 0x0a, 0x08, 0x50, 0x72, 0x6f,
0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x10, 0x00, 0x12, 0x07,
0x0a, 0x03, 0x54, 0x43, 0x50, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10,
0x02, 0x12, 0x09, 0x0a, 0x05, 0x48, 0x54, 0x54, 0x50, 0x53, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04,
0x44, 0x54, 0x4c, 0x53, 0x10, 0x04, 0x22, 0x7d, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63,
0x74, 0x65, 0x64, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a,
0x0a, 0x68, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x48,
0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0a, 0x68, 0x6f, 0x73, 0x74, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73,
0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73,
0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x38, 0x0a, 0x0a, 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a,
0x03, 0x64, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, 0x6e, 0x73, 0x22,
0xcc, 0x01, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4d, 0x61, 0x70, 0x12, 0x16,
0x0a, 0x06, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06,
0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x65, 0x65, 0x72, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e,
0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x52, 0x0a, 0x70, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3e,
0x0a, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74,
0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x52, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x2e,
0x0a, 0x12, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x73, 0x49, 0x73, 0x45,
0x6d, 0x70, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x72, 0x65, 0x6d, 0x6f,
0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x73, 0x49, 0x73, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x4e,
0x0a, 0x10, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x67, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x67, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x1e,
0x0a, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x49, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03,
0x28, 0x09, 0x52, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x49, 0x70, 0x73, 0x22, 0x20,
0x0a, 0x1e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x22, 0xbf, 0x01, 0x0a, 0x17, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f,
0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x48, 0x0a, 0x08,
0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c,
0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x65, 0x76, 0x69,
0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46,
0x6c, 0x6f, 0x77, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x08, 0x50, 0x72,
0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x42, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64,
0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x76,
0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x50, 0x72, 0x6f, 0x76,
0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x16, 0x0a, 0x08, 0x70, 0x72,
0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x0a, 0x0a, 0x06, 0x48, 0x4f, 0x53, 0x54, 0x45, 0x44,
0x10, 0x00, 0x22, 0x84, 0x01, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49,
0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49,
0x44, 0x12, 0x22, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65,
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53,
0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18,
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x1a, 0x0a,
0x08, 0x41, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
0x08, 0x41, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x32, 0xf7, 0x02, 0x0a, 0x11, 0x4d, 0x61,
0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
0x45, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67,
0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e,
0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x42, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72,
0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x11, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1d, 0x2e, 0x6d, 0x61, 0x6e, 0x61,
0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x33, 0x0a, 0x09, 0x69, 0x73,
0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x12, 0x11, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x6e,
0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12,
0x5a, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x75, 0x74, 0x68,
0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x1c, 0x2e,
0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79,
0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x6d, 0x61,
0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74,
0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x42, 0x08, 0x5a, 0x06, 0x2f,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x04, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x1c,
0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72,
0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x6d,
0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70,
0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x42,
0x0a, 0x0c, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x11,
0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6d, 0x70, 0x74,
0x79, 0x1a, 0x1d, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53,
0x65, 0x72, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x00, 0x12, 0x33, 0x0a, 0x09, 0x69, 0x73, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x12,
0x11, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6d, 0x70,
0x74, 0x79, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e,
0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x44, 0x65,
0x76, 0x69, 0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65,
0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74,
0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x22, 0x00, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -1395,7 +1405,7 @@ var file_management_proto_goTypes = []interface{}{
(*DeviceAuthorizationFlowRequest)(nil), // 16: management.DeviceAuthorizationFlowRequest
(*DeviceAuthorizationFlow)(nil), // 17: management.DeviceAuthorizationFlow
(*ProviderConfig)(nil), // 18: management.ProviderConfig
(*timestamppb.Timestamp)(nil), // 19: google.protobuf.Timestamp
(*timestamp.Timestamp)(nil), // 19: google.protobuf.Timestamp
}
var file_management_proto_depIdxs = []int32{
10, // 0: management.SyncResponse.wiretrusteeConfig:type_name -> management.WiretrusteeConfig

View File

@@ -82,6 +82,7 @@ message PeerSystemMeta {
string platform = 5;
string OS = 6;
string wiretrusteeVersion = 7;
string caller = 8;
}
message LoginResponse {

View File

@@ -33,7 +33,9 @@ type ManagementServiceClient interface {
IsHealthy(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error)
// Exposes a device authorization flow information
// This is used for initiating a Oauth 2 device authorization grant flow
// which will be used by our clients to Login
// which will be used by our clients to Login.
// EncryptedMessage of the request has a body of DeviceAuthorizationFlowRequest.
// EncryptedMessage of the response has a body of DeviceAuthorizationFlow.
GetDeviceAuthorizationFlow(ctx context.Context, in *EncryptedMessage, opts ...grpc.CallOption) (*EncryptedMessage, error)
}
@@ -132,7 +134,9 @@ type ManagementServiceServer interface {
IsHealthy(context.Context, *Empty) (*Empty, error)
// Exposes a device authorization flow information
// This is used for initiating a Oauth 2 device authorization grant flow
// which will be used by our clients to Login
// which will be used by our clients to Login.
// EncryptedMessage of the request has a body of DeviceAuthorizationFlowRequest.
// EncryptedMessage of the response has a body of DeviceAuthorizationFlow.
GetDeviceAuthorizationFlow(context.Context, *EncryptedMessage) (*EncryptedMessage, error)
mustEmbedUnimplementedManagementServiceServer()
}

View File

@@ -24,7 +24,12 @@ const (
type AccountManager interface {
GetOrCreateAccountByUser(userId, domain string) (*Account, error)
GetAccountByUser(userId string) (*Account, error)
AddSetupKey(accountId string, keyName string, keyType SetupKeyType, expiresIn *util.Duration) (*SetupKey, error)
AddSetupKey(
accountId string,
keyName string,
keyType SetupKeyType,
expiresIn *util.Duration,
) (*SetupKey, error)
RevokeSetupKey(accountId string, keyId string) (*SetupKey, error)
RenameSetupKey(accountId string, keyId string, newName string) (*SetupKey, error)
GetAccountById(accountId string) (*Account, error)
@@ -47,6 +52,10 @@ type AccountManager interface {
GroupAddPeer(accountId, groupID, peerKey string) error
GroupDeletePeer(accountId, groupID, peerKey string) error
GroupListPeers(accountId, groupID string) ([]*Peer, error)
GetRule(accountId, ruleID string) (*Rule, error)
SaveRule(accountID string, rule *Rule) error
DeleteRule(accountId, ruleID string) error
ListRules(accountId string) ([]*Rule, error)
}
type DefaultAccountManager struct {
@@ -70,6 +79,7 @@ type Account struct {
Peers map[string]*Peer
Users map[string]*User
Groups map[string]*Group
Rules map[string]*Rule
}
type UserInfo struct {
@@ -101,6 +111,16 @@ func (a *Account) Copy() *Account {
setupKeys[id] = key.Copy()
}
groups := map[string]*Group{}
for id, group := range a.Groups {
groups[id] = group.Copy()
}
rules := map[string]*Rule{}
for id, rule := range a.Rules {
rules[id] = rule.Copy()
}
return &Account{
Id: a.Id,
CreatedBy: a.CreatedBy,
@@ -108,17 +128,43 @@ func (a *Account) Copy() *Account {
Network: a.Network.Copy(),
Peers: peers,
Users: users,
Groups: groups,
Rules: rules,
}
}
// NewManager creates a new DefaultAccountManager with a provided Store
func NewManager(store Store, peersUpdateManager *PeersUpdateManager, idpManager idp.Manager) *DefaultAccountManager {
return &DefaultAccountManager{
func (a *Account) GetGroupAll() (*Group, error) {
for _, g := range a.Groups {
if g.Name == "All" {
return g, nil
}
}
return nil, fmt.Errorf("no group ALL found")
}
// BuildManager creates a new DefaultAccountManager with a provided Store
func BuildManager(
store Store, peersUpdateManager *PeersUpdateManager, idpManager idp.Manager,
) (*DefaultAccountManager, error) {
dam := &DefaultAccountManager{
Store: store,
mux: sync.Mutex{},
peersUpdateManager: peersUpdateManager,
idpManager: idpManager,
}
// if account has not default account
// we build 'all' group and add all peers into it
// also we create default rule with source an destination
// groups 'all'
for _, account := range store.GetAllAccounts() {
dam.addAllGroup(account)
if err := store.SaveAccount(account); err != nil {
return nil, err
}
}
return dam, nil
}
// AddSetupKey generates a new setup key with a given name and type, and adds it to the specified account
@@ -223,7 +269,9 @@ func (am *DefaultAccountManager) GetAccountById(accountId string) (*Account, err
// GetAccountByUserOrAccountId look for an account by user or account Id, if no account is provided and
// user id doesn't have an account associated with it, one account is created
func (am *DefaultAccountManager) GetAccountByUserOrAccountId(userId, accountId, domain string) (*Account, error) {
func (am *DefaultAccountManager) GetAccountByUserOrAccountId(
userId, accountId, domain string,
) (*Account, error) {
if accountId != "" {
return am.GetAccountById(accountId)
} else if userId != "" {
@@ -490,6 +538,8 @@ func (am *DefaultAccountManager) AddAccount(accountId, userId, domain string) (*
func (am *DefaultAccountManager) createAccount(accountId, userId, domain string) (*Account, error) {
account := newAccountWithId(accountId, userId, domain)
am.addAllGroup(account)
err := am.Store.SaveAccount(account)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed creating account")
@@ -498,6 +548,28 @@ func (am *DefaultAccountManager) createAccount(accountId, userId, domain string)
return account, nil
}
// addAllGroup to account object it it doesn't exists
func (am *DefaultAccountManager) addAllGroup(account *Account) {
if len(account.Groups) == 0 {
allGroup := &Group{
ID: xid.New().String(),
Name: "All",
}
for _, peer := range account.Peers {
allGroup.Peers = append(allGroup.Peers, peer.Key)
}
account.Groups = map[string]*Group{allGroup.ID: allGroup}
defaultRule := &Rule{
ID: xid.New().String(),
Name: "Default",
Source: []string{allGroup.ID},
Destination: []string{allGroup.ID},
}
account.Rules = map[string]*Rule{defaultRule.ID: defaultRule}
}
}
// newAccountWithId creates a new Account with a default SetupKey (doesn't store in a Store) and provided id
func newAccountWithId(accountId, userId, domain string) *Account {
log.Debugf("creating new account")

View File

@@ -37,7 +37,6 @@ func TestAccountManager_GetOrCreateAccountByUser(t *testing.T) {
}
func TestDefaultAccountManager_GetAccountWithAuthorizationClaims(t *testing.T) {
type initUserParams jwtclaims.AuthorizationClaims
type test struct {
@@ -165,7 +164,6 @@ func TestDefaultAccountManager_GetAccountWithAuthorizationClaims(t *testing.T) {
}
for _, testCase := range []test{testCase1, testCase2, testCase3, testCase4, testCase5, testCase6} {
t.Run(testCase.name, func(t *testing.T) {
manager, err := createManager(t)
require.NoError(t, err, "unable to create account manager")
@@ -346,7 +344,6 @@ func TestAccountManager_AccountExists(t *testing.T) {
if !*exists {
t.Errorf("expected account to exist after creation, got false")
}
}
func TestAccountManager_GetAccount(t *testing.T) {
@@ -363,7 +360,7 @@ func TestAccountManager_GetAccount(t *testing.T) {
t.Fatal(err)
}
//AddAccount has been already tested so we can assume it is correct and compare results
// AddAccount has been already tested so we can assume it is correct and compare results
getAccount, err := manager.GetAccountById(expectedId)
if err != nil {
t.Fatal(err)
@@ -385,7 +382,6 @@ func TestAccountManager_GetAccount(t *testing.T) {
t.Errorf("expected account to have setup key %s, not found", key.Key)
}
}
}
func TestAccountManager_AddPeer(t *testing.T) {
@@ -400,7 +396,7 @@ func TestAccountManager_AddPeer(t *testing.T) {
t.Fatal(err)
}
serial := account.Network.CurrentSerial() //should be 0
serial := account.Network.CurrentSerial() // should be 0
var setupKey *SetupKey
for _, key := range account.SetupKeys {
@@ -457,7 +453,6 @@ func TestAccountManager_AddPeer(t *testing.T) {
if account.Network.CurrentSerial() != 1 {
t.Errorf("expecting Network Serial=%d to be incremented by 1 and be equal to %d when adding new peer to account", serial, account.Network.CurrentSerial())
}
}
func TestAccountManager_AddPeerWithUserID(t *testing.T) {
@@ -474,7 +469,7 @@ func TestAccountManager_AddPeerWithUserID(t *testing.T) {
t.Fatal(err)
}
serial := account.Network.CurrentSerial() //should be 0
serial := account.Network.CurrentSerial() // should be 0
if account.Network.Serial != 0 {
t.Errorf("expecting account network to have an initial Serial=0")
@@ -521,7 +516,6 @@ func TestAccountManager_AddPeerWithUserID(t *testing.T) {
if account.Network.CurrentSerial() != 1 {
t.Errorf("expecting Network Serial=%d to be incremented by 1 and be equal to %d when adding new peer to account", serial, account.Network.CurrentSerial())
}
}
func TestAccountManager_DeletePeer(t *testing.T) {
@@ -573,7 +567,6 @@ func TestAccountManager_DeletePeer(t *testing.T) {
if account.Network.CurrentSerial() != 2 {
t.Errorf("expecting Network Serial=%d to be incremented and be equal to 2 after adding and deleteing a peer", account.Network.CurrentSerial())
}
}
func TestGetUsersFromAccount(t *testing.T) {
@@ -614,7 +607,7 @@ func createManager(t *testing.T) (*DefaultAccountManager, error) {
if err != nil {
return nil, err
}
return NewManager(store, NewPeersUpdateManager(), nil), nil
return BuildManager(store, NewPeersUpdateManager(), nil)
}
func createStore(t *testing.T) (Store, error) {

View File

@@ -1,6 +1,7 @@
package server
import (
"fmt"
"os"
"path/filepath"
"strings"
@@ -18,10 +19,12 @@ const storeFileName = "store.json"
// FileStore represents an account storage backed by a file persisted to disk
type FileStore struct {
Accounts map[string]*Account
SetupKeyId2AccountId map[string]string `json:"-"`
PeerKeyId2AccountId map[string]string `json:"-"`
UserId2AccountId map[string]string `json:"-"`
PrivateDomain2AccountId map[string]string `json:"-"`
SetupKeyId2AccountId map[string]string `json:"-"`
PeerKeyId2AccountId map[string]string `json:"-"`
UserId2AccountId map[string]string `json:"-"`
PrivateDomain2AccountId map[string]string `json:"-"`
PeerKeyId2SrcRulesId map[string]map[string]struct{} `json:"-"`
PeerKeyId2DstRulesId map[string]map[string]struct{} `json:"-"`
// mutex to synchronise Store read/write operations
mux sync.Mutex `json:"-"`
@@ -47,6 +50,8 @@ func restore(file string) (*FileStore, error) {
PeerKeyId2AccountId: make(map[string]string),
UserId2AccountId: make(map[string]string),
PrivateDomain2AccountId: make(map[string]string),
PeerKeyId2SrcRulesId: make(map[string]map[string]struct{}),
PeerKeyId2DstRulesId: make(map[string]map[string]struct{}),
storeFile: file,
}
@@ -69,10 +74,39 @@ func restore(file string) (*FileStore, error) {
store.PeerKeyId2AccountId = make(map[string]string)
store.UserId2AccountId = make(map[string]string)
store.PrivateDomain2AccountId = make(map[string]string)
store.PeerKeyId2SrcRulesId = map[string]map[string]struct{}{}
store.PeerKeyId2DstRulesId = map[string]map[string]struct{}{}
for accountId, account := range store.Accounts {
for setupKeyId := range account.SetupKeys {
store.SetupKeyId2AccountId[strings.ToUpper(setupKeyId)] = accountId
}
for _, rule := range account.Rules {
for _, groupID := range rule.Source {
if group, ok := account.Groups[groupID]; ok {
for _, peerID := range group.Peers {
rules := store.PeerKeyId2SrcRulesId[peerID]
if rules == nil {
rules = map[string]struct{}{}
store.PeerKeyId2SrcRulesId[peerID] = rules
}
rules[rule.ID] = struct{}{}
}
}
}
for _, groupID := range rule.Destination {
if group, ok := account.Groups[groupID]; ok {
for _, peerID := range group.Peers {
rules := store.PeerKeyId2DstRulesId[peerID]
if rules == nil {
rules = map[string]struct{}{}
store.PeerKeyId2DstRulesId[peerID] = rules
}
rules[rule.ID] = struct{}{}
}
}
}
}
for _, peer := range account.Peers {
store.PeerKeyId2AccountId[peer.Key] = accountId
}
@@ -82,7 +116,8 @@ func restore(file string) (*FileStore, error) {
for _, user := range account.Users {
store.UserId2AccountId[user.Id] = accountId
}
if account.Domain != "" && account.DomainCategory == PrivateCategory && account.IsDomainPrimaryAccount {
if account.Domain != "" && account.DomainCategory == PrivateCategory &&
account.IsDomainPrimaryAccount {
store.PrivateDomain2AccountId[account.Domain] = accountId
}
}
@@ -106,6 +141,24 @@ func (s *FileStore) SavePeer(accountId string, peer *Peer) error {
return err
}
// if it is new peer, add it to default 'All' group
allGroup, err := account.GetGroupAll()
if err != nil {
return err
}
ind := -1
for i, pid := range allGroup.Peers {
if pid == peer.Key {
ind = i
break
}
}
if ind < 0 {
allGroup.Peers = append(allGroup.Peers, peer.Key)
}
account.Peers[peer.Key] = peer
return s.persist(s.storeFile)
}
@@ -128,6 +181,17 @@ func (s *FileStore) DeletePeer(accountId string, peerKey string) (*Peer, error)
delete(account.Peers, peerKey)
delete(s.PeerKeyId2AccountId, peerKey)
// cleanup groups
var peers []string
for _, g := range account.Groups {
for _, p := range g.Peers {
if p != peerKey {
peers = append(peers, p)
}
}
g.Peers = peers
}
err = s.persist(s.storeFile)
if err != nil {
return nil, err
@@ -176,6 +240,29 @@ func (s *FileStore) SaveAccount(account *Account) error {
s.PeerKeyId2AccountId[peer.Key] = account.Id
}
for _, rule := range account.Rules {
for _, gid := range rule.Source {
for _, pid := range account.Groups[gid].Peers {
rules := s.PeerKeyId2SrcRulesId[pid]
if rules == nil {
rules = map[string]struct{}{}
s.PeerKeyId2SrcRulesId[pid] = rules
}
rules[rule.ID] = struct{}{}
}
}
for _, gid := range rule.Destination {
for _, pid := range account.Groups[gid].Peers {
rules := s.PeerKeyId2DstRulesId[pid]
if rules == nil {
rules = map[string]struct{}{}
s.PeerKeyId2DstRulesId[pid] = rules
}
rules[rule.ID] = struct{}{}
}
}
}
for _, user := range account.Users {
s.UserId2AccountId[user.Id] = account.Id
}
@@ -190,7 +277,10 @@ func (s *FileStore) SaveAccount(account *Account) error {
func (s *FileStore) GetAccountByPrivateDomain(domain string) (*Account, error) {
accountId, accountIdFound := s.PrivateDomain2AccountId[strings.ToLower(domain)]
if !accountIdFound {
return nil, status.Errorf(codes.NotFound, "provided domain is not registered or is not private")
return nil, status.Errorf(
codes.NotFound,
"provided domain is not registered or is not private",
)
}
account, err := s.GetAccount(accountId)
@@ -232,6 +322,14 @@ func (s *FileStore) GetAccountPeers(accountId string) ([]*Peer, error) {
return peers, nil
}
func (s *FileStore) GetAllAccounts() (all []*Account) {
for _, a := range s.Accounts {
all = append(all, a)
}
return all
}
func (s *FileStore) GetAccount(accountId string) (*Account, error) {
account, accountFound := s.Accounts[accountId]
if !accountFound {
@@ -265,18 +363,52 @@ func (s *FileStore) GetPeerAccount(peerKey string) (*Account, error) {
return s.GetAccount(accountId)
}
func (s *FileStore) GetGroup(groupID string) (*Group, error) {
return nil, nil
func (s *FileStore) GetPeerSrcRules(accountId, peerKey string) ([]*Rule, error) {
s.mux.Lock()
defer s.mux.Unlock()
account, err := s.GetAccount(accountId)
if err != nil {
return nil, err
}
ruleIDs, ok := s.PeerKeyId2SrcRulesId[peerKey]
if !ok {
return nil, fmt.Errorf("no rules for peer: %v", ruleIDs)
}
rules := []*Rule{}
for id := range ruleIDs {
rule, ok := account.Rules[id]
if ok {
rules = append(rules, rule)
}
}
return rules, nil
}
func (s *FileStore) SaveGroup(group *Group) error {
return nil
}
func (s *FileStore) GetPeerDstRules(accountId, peerKey string) ([]*Rule, error) {
s.mux.Lock()
defer s.mux.Unlock()
func (s *FileStore) DeleteGroup(groupID string) error {
return nil
}
account, err := s.GetAccount(accountId)
if err != nil {
return nil, err
}
func (s *FileStore) ListGroups() ([]*Group, error) {
return nil, nil
ruleIDs, ok := s.PeerKeyId2DstRulesId[peerKey]
if !ok {
return nil, fmt.Errorf("no rules for peer: %v", ruleIDs)
}
rules := []*Rule{}
for id := range ruleIDs {
rule, ok := account.Rules[id]
if ok {
rules = append(rules, rule)
}
}
return rules, nil
}

View File

@@ -17,6 +17,14 @@ type Group struct {
Peers []string
}
func (g *Group) Copy() *Group {
return &Group{
ID: g.ID,
Name: g.Name,
Peers: g.Peers[:],
}
}
// GetGroup object of the peers
func (am *DefaultAccountManager) GetGroup(accountID, groupID string) (*Group, error) {
am.mux.Lock()

View File

@@ -3,11 +3,12 @@ package server
import (
"context"
"fmt"
"github.com/netbirdio/netbird/management/server/http/middleware"
"github.com/netbirdio/netbird/management/server/jwtclaims"
"strings"
"time"
"github.com/netbirdio/netbird/management/server/http/middleware"
"github.com/netbirdio/netbird/management/server/jwtclaims"
"github.com/golang/protobuf/ptypes/timestamp"
"github.com/netbirdio/netbird/encryption"
"github.com/netbirdio/netbird/management/proto"
@@ -64,7 +65,6 @@ func NewServer(config *Config, accountManager AccountManager, peersUpdateManager
}
func (s *Server) GetServerKey(ctx context.Context, req *proto.Empty) (*proto.ServerKeyResponse, error) {
// todo introduce something more meaningful with the key expiration/rotation
now := time.Now().Add(24 * time.Hour)
secs := int64(now.Second())
@@ -77,10 +77,9 @@ func (s *Server) GetServerKey(ctx context.Context, req *proto.Empty) (*proto.Ser
}, nil
}
//Sync validates the existence of a connecting peer, sends an initial state (all available for the connecting peers) and
// Sync validates the existence of a connecting peer, sends an initial state (all available for the connecting peers) and
// notifies the connected peer of any updates (e.g. new peers under the same account)
func (s *Server) Sync(req *proto.EncryptedMessage, srv proto.ManagementService_SyncServer) error {
log.Debugf("Sync request from peer %s", req.WgPubKey)
peerKey, err := wgtypes.ParseKey(req.GetWgPubKey())
@@ -155,7 +154,6 @@ func (s *Server) Sync(req *proto.EncryptedMessage, srv proto.ManagementService_S
}
func (s *Server) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest) (*Peer, error) {
var (
reqSetupKey string
userId string
@@ -209,7 +207,7 @@ func (s *Server) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest) (*Pe
return nil, status.Errorf(codes.NotFound, "provided setup key doesn't exists")
}
//todo move to DefaultAccountManager the code below
// todo move to DefaultAccountManager the code below
networkMap, err := s.accountManager.GetNetworkMap(peer.Key)
if err != nil {
return nil, status.Errorf(codes.Internal, "unable to fetch network map after registering peer, error: %v", err)
@@ -240,7 +238,6 @@ func (s *Server) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest) (*Pe
// In case it isn't, the endpoint checks whether setup key is provided within the request and tries to register a peer.
// In case of the successful registration login is also successful
func (s *Server) Login(ctx context.Context, req *proto.EncryptedMessage) (*proto.EncryptedMessage, error) {
log.Debugf("Login request from peer %s", req.WgPubKey)
peerKey, err := wgtypes.ParseKey(req.GetWgPubKey())
@@ -252,18 +249,18 @@ func (s *Server) Login(ctx context.Context, req *proto.EncryptedMessage) (*proto
peer, err := s.accountManager.GetPeer(peerKey.String())
if err != nil {
if errStatus, ok := status.FromError(err); ok && errStatus.Code() == codes.NotFound {
//peer doesn't exist -> check if setup key was provided
// peer doesn't exist -> check if setup key was provided
loginReq := &proto.LoginRequest{}
err = encryption.DecryptMessage(peerKey, s.wgKey, req.Body, loginReq)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid request message")
}
if loginReq.GetJwtToken() == "" && loginReq.GetSetupKey() == "" {
//absent setup key -> permission denied
// absent setup key -> permission denied
return nil, status.Errorf(codes.PermissionDenied, "provided peer with the key wgPubKey %s is not registered and no setup key or jwt was provided", peerKey.String())
}
//setup key or jwt is present -> try normal registration flow
// setup key or jwt is present -> try normal registration flow
peer, err = s.registerPeer(peerKey, loginReq)
if err != nil {
return nil, err
@@ -303,13 +300,12 @@ func ToResponseProto(configProto Protocol) proto.HostConfig_Protocol {
case TCP:
return proto.HostConfig_TCP
default:
//mbragin: todo something better?
// mbragin: todo something better?
panic(fmt.Errorf("unexpected config protocol type %v", configProto))
}
}
func toWiretrusteeConfig(config *Config, turnCredentials *TURNCredentials) *proto.WiretrusteeConfig {
var stuns []*proto.HostConfig
for _, stun := range config.Stuns {
stuns = append(stuns, &proto.HostConfig{
@@ -350,26 +346,23 @@ func toWiretrusteeConfig(config *Config, turnCredentials *TURNCredentials) *prot
func toPeerConfig(peer *Peer) *proto.PeerConfig {
return &proto.PeerConfig{
Address: peer.IP.String() + "/24", //todo make it explicit
Address: peer.IP.String() + "/24", // todo make it explicit
}
}
func toRemotePeerConfig(peers []*Peer) []*proto.RemotePeerConfig {
remotePeers := []*proto.RemotePeerConfig{}
for _, rPeer := range peers {
remotePeers = append(remotePeers, &proto.RemotePeerConfig{
WgPubKey: rPeer.Key,
AllowedIps: []string{fmt.Sprintf(AllowedIPsFormat, rPeer.IP)}, //todo /32
AllowedIps: []string{fmt.Sprintf(AllowedIPsFormat, rPeer.IP)}, // todo /32
})
}
return remotePeers
}
func toSyncResponse(config *Config, peer *Peer, peers []*Peer, turnCredentials *TURNCredentials, serial uint64) *proto.SyncResponse {
wtConfig := toWiretrusteeConfig(config, turnCredentials)
pConfig := toPeerConfig(peer)
@@ -397,7 +390,6 @@ func (s *Server) IsHealthy(ctx context.Context, req *proto.Empty) (*proto.Empty,
// sendInitialSync sends initial proto.SyncResponse to the peer requesting synchronization
func (s *Server) sendInitialSync(peerKey wgtypes.Key, peer *Peer, srv proto.ManagementService_SyncServer) error {
networkMap, err := s.accountManager.GetNetworkMap(peer.Key)
if err != nil {
log.Warnf("error getting a list of peers for a peer %s", peer.Key)
@@ -436,7 +428,6 @@ func (s *Server) sendInitialSync(peerKey wgtypes.Key, peer *Peer, srv proto.Mana
// This is used for initiating an Oauth 2 device authorization grant flow
// which will be used by our clients to Login
func (s *Server) GetDeviceAuthorizationFlow(ctx context.Context, req *proto.EncryptedMessage) (*proto.EncryptedMessage, error) {
peerKey, err := wgtypes.ParseKey(req.GetWgPubKey())
if err != nil {
errMSG := fmt.Sprintf("error while parsing peer's Wireguard public key %s on GetDeviceAuthorizationFlow request.", req.WgPubKey)

View File

@@ -13,20 +13,33 @@ import (
log "github.com/sirupsen/logrus"
)
// Groups is a handler that returns groups of the account
type Groups struct {
accountManager server.AccountManager
authAudience string
jwtExtractor jwtclaims.ClaimsExtractor
}
// GroupResponse is a response sent to the client
type GroupResponse struct {
ID string
Name string
Peers []GroupPeerResponse `json:",omitempty"`
}
// GroupPeerResponse is a response sent to the client
type GroupPeerResponse struct {
Key string
Name string
}
// GroupRequest to create or update group
type GroupRequest struct {
ID string
Name string
Peers []string
}
// Groups is a handler that returns groups of the account
type Groups struct {
jwtExtractor jwtclaims.ClaimsExtractor
accountManager server.AccountManager
authAudience string
}
func NewGroups(accountManager server.AccountManager, authAudience string) *Groups {
return &Groups{
accountManager: accountManager,
@@ -44,7 +57,12 @@ func (h *Groups) GetAllGroupsHandler(w http.ResponseWriter, r *http.Request) {
return
}
writeJSONObject(w, account.Groups)
var groups []*GroupResponse
for _, g := range account.Groups {
groups = append(groups, toGroupResponse(account, g))
}
writeJSONObject(w, groups)
}
func (h *Groups) CreateOrUpdateGroupHandler(w http.ResponseWriter, r *http.Request) {
@@ -54,7 +72,7 @@ func (h *Groups) CreateOrUpdateGroupHandler(w http.ResponseWriter, r *http.Reque
return
}
var req server.Group
var req GroupRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
@@ -64,13 +82,19 @@ func (h *Groups) CreateOrUpdateGroupHandler(w http.ResponseWriter, r *http.Reque
req.ID = xid.New().String()
}
if err := h.accountManager.SaveGroup(account.Id, &req); err != nil {
group := server.Group{
ID: req.ID,
Name: req.Name,
Peers: req.Peers,
}
if err := h.accountManager.SaveGroup(account.Id, &group); err != nil {
log.Errorf("failed updating group %s under account %s %v", req.ID, account.Id, err)
http.Redirect(w, r, "/", http.StatusInternalServerError)
return
}
writeJSONObject(w, &req)
writeJSONObject(w, toGroupResponse(account, &group))
}
func (h *Groups) DeleteGroupHandler(w http.ResponseWriter, r *http.Request) {
@@ -117,7 +141,7 @@ func (h *Groups) GetGroupHandler(w http.ResponseWriter, r *http.Request) {
return
}
writeJSONObject(w, group)
writeJSONObject(w, toGroupResponse(account, group))
default:
http.Error(w, "", http.StatusNotFound)
}
@@ -133,3 +157,29 @@ func (h *Groups) getGroupAccount(r *http.Request) (*server.Account, error) {
return account, nil
}
func toGroupResponse(account *server.Account, group *server.Group) *GroupResponse {
cache := make(map[string]GroupPeerResponse)
gr := GroupResponse{
ID: group.ID,
Name: group.Name,
}
for _, pid := range group.Peers {
peerResp, ok := cache[pid]
if !ok {
peer, ok := account.Peers[pid]
if !ok {
continue
}
peerResp = GroupPeerResponse{
Key: peer.Key,
Name: peer.Name,
}
cache[pid] = peerResp
}
gr.Peers = append(gr.Peers, peerResp)
}
return &gr
}

View File

@@ -0,0 +1,211 @@
package handler
import (
"encoding/json"
"fmt"
"net/http"
"github.com/netbirdio/netbird/management/server"
"github.com/netbirdio/netbird/management/server/jwtclaims"
"github.com/rs/xid"
"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
)
const FlowBidirectString = "bidirect"
// RuleResponse is a response sent to the client
type RuleResponse struct {
ID string
Name string
Source []RuleGroupResponse
Destination []RuleGroupResponse
Flow string
}
// RuleGroupResponse is a response sent to the client
type RuleGroupResponse struct {
ID string
Name string
PeersCount int
}
// RuleRequest to create or update rule
type RuleRequest struct {
ID string
Name string
Source []string
Destination []string
Flow string
}
// Rules is a handler that returns rules of the account
type Rules struct {
jwtExtractor jwtclaims.ClaimsExtractor
accountManager server.AccountManager
authAudience string
}
func NewRules(accountManager server.AccountManager, authAudience string) *Rules {
return &Rules{
accountManager: accountManager,
authAudience: authAudience,
jwtExtractor: *jwtclaims.NewClaimsExtractor(nil),
}
}
// GetAllRulesHandler list for the account
func (h *Rules) GetAllRulesHandler(w http.ResponseWriter, r *http.Request) {
account, err := h.getRuleAccount(r)
if err != nil {
log.Error(err)
http.Redirect(w, r, "/", http.StatusInternalServerError)
return
}
rules := []*RuleResponse{}
for _, r := range account.Rules {
rules = append(rules, toRuleResponse(account, r))
}
writeJSONObject(w, rules)
}
func (h *Rules) CreateOrUpdateRuleHandler(w http.ResponseWriter, r *http.Request) {
account, err := h.getRuleAccount(r)
if err != nil {
http.Redirect(w, r, "/", http.StatusInternalServerError)
return
}
var req RuleRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if r.Method == http.MethodPost {
req.ID = xid.New().String()
}
rule := server.Rule{
ID: req.ID,
Name: req.Name,
Source: req.Source,
Destination: req.Destination,
}
switch req.Flow {
case FlowBidirectString:
rule.Flow = server.TrafficFlowBidirect
default:
http.Error(w, "unknown flow type", http.StatusBadRequest)
return
}
if err := h.accountManager.SaveRule(account.Id, &rule); err != nil {
log.Errorf("failed updating rule %s under account %s %v", req.ID, account.Id, err)
http.Redirect(w, r, "/", http.StatusInternalServerError)
return
}
writeJSONObject(w, &req)
}
func (h *Rules) DeleteRuleHandler(w http.ResponseWriter, r *http.Request) {
account, err := h.getRuleAccount(r)
if err != nil {
http.Redirect(w, r, "/", http.StatusInternalServerError)
return
}
aID := account.Id
rID := mux.Vars(r)["id"]
if len(rID) == 0 {
http.Error(w, "invalid rule ID", http.StatusBadRequest)
return
}
if err := h.accountManager.DeleteRule(aID, rID); err != nil {
log.Errorf("failed delete rule %s under account %s %v", rID, aID, err)
http.Redirect(w, r, "/", http.StatusInternalServerError)
return
}
writeJSONObject(w, "")
}
func (h *Rules) GetRuleHandler(w http.ResponseWriter, r *http.Request) {
account, err := h.getRuleAccount(r)
if err != nil {
http.Redirect(w, r, "/", http.StatusInternalServerError)
return
}
switch r.Method {
case http.MethodGet:
ruleID := mux.Vars(r)["id"]
if len(ruleID) == 0 {
http.Error(w, "invalid rule ID", http.StatusBadRequest)
return
}
rule, err := h.accountManager.GetRule(account.Id, ruleID)
if err != nil {
http.Error(w, "rule not found", http.StatusNotFound)
return
}
writeJSONObject(w, toRuleResponse(account, rule))
default:
http.Error(w, "", http.StatusNotFound)
}
}
func (h *Rules) getRuleAccount(r *http.Request) (*server.Account, error) {
jwtClaims := h.jwtExtractor.ExtractClaimsFromRequestContext(r, h.authAudience)
account, err := h.accountManager.GetAccountWithAuthorizationClaims(jwtClaims)
if err != nil {
return nil, fmt.Errorf("failed getting account of a user %s: %v", jwtClaims.UserId, err)
}
return account, nil
}
func toRuleResponse(account *server.Account, rule *server.Rule) *RuleResponse {
gr := RuleResponse{
ID: rule.ID,
Name: rule.Name,
}
switch rule.Flow {
case server.TrafficFlowBidirect:
gr.Flow = FlowBidirectString
default:
gr.Flow = "unknown"
}
for _, gid := range rule.Source {
if group, ok := account.Groups[gid]; ok {
gr.Source = append(gr.Source, RuleGroupResponse{
ID: group.ID,
Name: group.Name,
PeersCount: len(group.Peers),
})
}
}
for _, gid := range rule.Destination {
if group, ok := account.Groups[gid]; ok {
gr.Destination = append(gr.Destination, RuleGroupResponse{
ID: group.ID,
Name: group.Name,
PeersCount: len(group.Peers),
})
}
}
return &gr
}

View File

@@ -0,0 +1,211 @@
package handler
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/gorilla/mux"
"github.com/netbirdio/netbird/management/server/jwtclaims"
"github.com/magiconair/properties/assert"
"github.com/netbirdio/netbird/management/server"
"github.com/netbirdio/netbird/management/server/mock_server"
)
func initRulesTestData(rules ...*server.Rule) *Rules {
return &Rules{
accountManager: &mock_server.MockAccountManager{
SaveRuleFunc: func(_ string, rule *server.Rule) error {
if !strings.HasPrefix(rule.ID, "id-") {
rule.ID = "id-was-set"
}
return nil
},
GetRuleFunc: func(_, ruleID string) (*server.Rule, error) {
if ruleID != "idoftherule" {
return nil, fmt.Errorf("not found")
}
return &server.Rule{
ID: "idoftherule",
Name: "Rule",
Source: []string{"idofsrcrule"},
Destination: []string{"idofdestrule"},
Flow: server.TrafficFlowBidirect,
}, nil
},
GetAccountWithAuthorizationClaimsFunc: func(claims jwtclaims.AuthorizationClaims) (*server.Account, error) {
return &server.Account{
Id: claims.AccountId,
Domain: "hotmail.com",
}, nil
},
},
authAudience: "",
jwtExtractor: jwtclaims.ClaimsExtractor{
ExtractClaimsFromRequestContext: func(r *http.Request, authAudiance string) jwtclaims.AuthorizationClaims {
return jwtclaims.AuthorizationClaims{
UserId: "test_user",
Domain: "hotmail.com",
AccountId: "test_id",
}
},
},
}
}
func TestRulesGetRule(t *testing.T) {
tt := []struct {
name string
expectedStatus int
expectedBody bool
requestType string
requestPath string
requestBody io.Reader
}{
{
name: "GetRule OK",
expectedBody: true,
requestType: http.MethodGet,
requestPath: "/api/rules/idoftherule",
expectedStatus: http.StatusOK,
},
{
name: "GetRule not found",
requestType: http.MethodGet,
requestPath: "/api/rules/notexists",
expectedStatus: http.StatusNotFound,
},
}
rule := &server.Rule{
ID: "idoftherule",
Name: "Rule",
}
p := initRulesTestData(rule)
for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
recorder := httptest.NewRecorder()
req := httptest.NewRequest(tc.requestType, tc.requestPath, tc.requestBody)
router := mux.NewRouter()
router.HandleFunc("/api/rules/{id}", p.GetRuleHandler).Methods("GET")
router.ServeHTTP(recorder, req)
res := recorder.Result()
defer res.Body.Close()
if status := recorder.Code; status != tc.expectedStatus {
t.Errorf("handler returned wrong status code: got %v want %v",
status, tc.expectedStatus)
return
}
if !tc.expectedBody {
return
}
content, err := io.ReadAll(res.Body)
if err != nil {
t.Fatalf("I don't know what I expected; %v", err)
}
var got RuleResponse
if err = json.Unmarshal(content, &got); err != nil {
t.Fatalf("Sent content is not in correct json format; %v", err)
}
assert.Equal(t, got.ID, rule.ID)
assert.Equal(t, got.Name, rule.Name)
})
}
}
func TestRulesSaveRule(t *testing.T) {
tt := []struct {
name string
expectedStatus int
expectedBody bool
expectedRule *server.Rule
requestType string
requestPath string
requestBody io.Reader
}{
{
name: "SaveRule POST OK",
requestType: http.MethodPost,
requestPath: "/api/rules",
requestBody: bytes.NewBuffer(
[]byte(`{"Name":"Default POSTed Rule","Flow":"bidirect"}`)),
expectedStatus: http.StatusOK,
expectedBody: true,
expectedRule: &server.Rule{
ID: "id-was-set",
Name: "Default POSTed Rule",
Flow: server.TrafficFlowBidirect,
},
},
{
name: "SaveRule PUT OK",
requestType: http.MethodPut,
requestPath: "/api/rules",
requestBody: bytes.NewBuffer(
[]byte(`{"ID":"id-existed","Name":"Default POSTed Rule","Flow":"bidirect"}`)),
expectedStatus: http.StatusOK,
expectedRule: &server.Rule{
ID: "id-existed",
Name: "Default POSTed Rule",
Flow: server.TrafficFlowBidirect,
},
},
}
p := initRulesTestData()
for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
recorder := httptest.NewRecorder()
req := httptest.NewRequest(tc.requestType, tc.requestPath, tc.requestBody)
router := mux.NewRouter()
router.HandleFunc("/api/rules", p.CreateOrUpdateRuleHandler).Methods("PUT", "POST")
router.ServeHTTP(recorder, req)
res := recorder.Result()
defer res.Body.Close()
content, err := io.ReadAll(res.Body)
if err != nil {
t.Fatalf("I don't know what I expected; %v", err)
}
if status := recorder.Code; status != tc.expectedStatus {
t.Errorf("handler returned wrong status code: got %v want %v, content: %s",
status, tc.expectedStatus, string(content))
return
}
if !tc.expectedBody {
return
}
got := &RuleRequest{}
if err = json.Unmarshal(content, &got); err != nil {
t.Fatalf("Sent content is not in correct json format; %v", err)
}
if tc.requestType != http.MethodPost {
assert.Equal(t, got.ID, tc.expectedRule.ID)
}
assert.Equal(t, got.Name, tc.expectedRule.Name)
assert.Equal(t, got.Flow, "bidirect")
})
}
}

View File

@@ -17,8 +17,10 @@ type UserHandler struct {
}
type UserResponse struct {
Email string
Role string
ID string `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
Role string `json:"role"`
}
func NewUserHandler(accountManager server.AccountManager, authAudience string) *UserHandler {
@@ -59,5 +61,19 @@ func (u *UserHandler) GetUsers(w http.ResponseWriter, r *http.Request) {
return
}
writeJSONObject(w, data)
users := []*UserResponse{}
for _, r := range data {
users = append(users, toUserResponse(r))
}
writeJSONObject(w, users)
}
func toUserResponse(user *server.UserInfo) *UserResponse {
return &UserResponse{
ID: user.ID,
Name: user.Name,
Email: user.Email,
Role: user.Role,
}
}

View File

@@ -96,6 +96,7 @@ func (s *Server) Start() error {
r.Use(jwtMiddleware.Handler, corsMiddleware.Handler)
groupsHandler := handler.NewGroups(s.accountManager, s.config.AuthAudience)
rulesHandler := handler.NewRules(s.accountManager, s.config.AuthAudience)
peersHandler := handler.NewPeers(s.accountManager, s.config.AuthAudience)
keysHandler := handler.NewSetupKeysHandler(s.accountManager, s.config.AuthAudience)
r.HandleFunc("/api/peers", peersHandler.GetPeers).Methods("GET", "OPTIONS")
@@ -112,6 +113,12 @@ func (s *Server) Start() error {
r.HandleFunc("/api/setup-keys/{id}", keysHandler.HandleKey).
Methods("GET", "PUT", "DELETE", "OPTIONS")
r.HandleFunc("/api/rules", rulesHandler.GetAllRulesHandler).Methods("GET", "OPTIONS")
r.HandleFunc("/api/rules", rulesHandler.CreateOrUpdateRuleHandler).
Methods("POST", "PUT", "OPTIONS")
r.HandleFunc("/api/rules/{id}", rulesHandler.GetRuleHandler).Methods("GET", "OPTIONS")
r.HandleFunc("/api/rules/{id}", rulesHandler.DeleteRuleHandler).Methods("DELETE", "OPTIONS")
r.HandleFunc("/api/groups", groupsHandler.GetAllGroupsHandler).Methods("GET", "OPTIONS")
r.HandleFunc("/api/groups", groupsHandler.CreateOrUpdateGroupHandler).
Methods("POST", "PUT", "OPTIONS")

View File

@@ -3,6 +3,13 @@ package server
import (
"context"
"fmt"
"net"
"os"
"path/filepath"
"runtime"
"testing"
"time"
"github.com/netbirdio/netbird/encryption"
mgmtProto "github.com/netbirdio/netbird/management/proto"
"github.com/netbirdio/netbird/util"
@@ -11,12 +18,6 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/keepalive"
"net"
"os"
"path/filepath"
"runtime"
"testing"
"time"
)
var (
@@ -39,8 +40,7 @@ const (
// registerPeers registers peersNum peers on the management service and returns their Wireguard keys
func registerPeers(peersNum int, client mgmtProto.ManagementServiceClient) ([]*wgtypes.Key, error) {
var peers = []*wgtypes.Key{}
peers := []*wgtypes.Key{}
for i := 0; i < peersNum; i++ {
key, err := wgtypes.GeneratePrivateKey()
if err != nil {
@@ -60,7 +60,6 @@ func registerPeers(peersNum int, client mgmtProto.ManagementServiceClient) ([]*w
// getServerKey gets Management Service Wireguard public key
func getServerKey(client mgmtProto.ManagementServiceClient) (*wgtypes.Key, error) {
keyResp, err := client.GetServerKey(context.TODO(), &mgmtProto.Empty{})
if err != nil {
return nil, err
@@ -75,7 +74,6 @@ func getServerKey(client mgmtProto.ManagementServiceClient) (*wgtypes.Key, error
}
func Test_SyncProtocol(t *testing.T) {
dir := t.TempDir()
err := util.CopyFileContents("testdata/store.json", filepath.Join(dir, "store.json"))
if err != nil {
@@ -263,7 +261,6 @@ func Test_SyncProtocol(t *testing.T) {
}
func loginPeerWithValidSetupKey(key wgtypes.Key, client mgmtProto.ManagementServiceClient) (*mgmtProto.LoginResponse, error) {
serverKey, err := getServerKey(client)
if err != nil {
return nil, err
@@ -298,11 +295,9 @@ func loginPeerWithValidSetupKey(key wgtypes.Key, client mgmtProto.ManagementServ
}
return loginResp, nil
}
func TestServer_GetDeviceAuthorizationFlow(t *testing.T) {
testingServerKey, err := wgtypes.GeneratePrivateKey()
if err != nil {
t.Errorf("unable to generate server wg key for testing GetDeviceAuthorizationFlow, error: %v", err)
@@ -362,7 +357,6 @@ func TestServer_GetDeviceAuthorizationFlow(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
mgmtServer := &Server{
wgKey: testingServerKey,
config: &Config{
@@ -397,7 +391,6 @@ func TestServer_GetDeviceAuthorizationFlow(t *testing.T) {
}
func startManagement(t *testing.T, port int, config *Config) (*grpc.Server, error) {
lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port))
if err != nil {
return nil, err
@@ -408,7 +401,10 @@ func startManagement(t *testing.T, port int, config *Config) (*grpc.Server, erro
return nil, err
}
peersUpdateManager := NewPeersUpdateManager()
accountManager := NewManager(store, peersUpdateManager, nil)
accountManager, err := BuildManager(store, peersUpdateManager, nil)
if err != nil {
return nil, err
}
turnManager := NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig)
mgmtServer, err := NewServer(config, accountManager, peersUpdateManager, turnManager)
if err != nil {

View File

@@ -2,8 +2,6 @@ package server_test
import (
"context"
server "github.com/netbirdio/netbird/management/server"
"google.golang.org/grpc/credentials/insecure"
"io/ioutil"
"math/rand"
"net"
@@ -13,6 +11,9 @@ import (
sync2 "sync"
"time"
server "github.com/netbirdio/netbird/management/server"
"google.golang.org/grpc/credentials/insecure"
pb "github.com/golang/protobuf/proto" //nolint
"github.com/netbirdio/netbird/encryption"
log "github.com/sirupsen/logrus"
@@ -31,7 +32,6 @@ const (
)
var _ = Describe("Management service", func() {
var (
addr string
s *grpc.Server
@@ -66,7 +66,6 @@ var _ = Describe("Management service", func() {
Expect(err).NotTo(HaveOccurred())
serverPubKey, err = wgtypes.ParseKey(resp.Key)
Expect(err).NotTo(HaveOccurred())
})
AfterEach(func() {
@@ -78,7 +77,6 @@ var _ = Describe("Management service", func() {
Context("when calling IsHealthy endpoint", func() {
Specify("a non-error result is returned", func() {
healthy, err := client.IsHealthy(context.TODO(), &mgmtProto.Empty{})
Expect(err).NotTo(HaveOccurred())
@@ -87,7 +85,6 @@ var _ = Describe("Management service", func() {
})
Context("when calling Sync endpoint", func() {
Context("when there is a new peer registered", func() {
Specify("a proper configuration is returned", func() {
key, _ := wgtypes.GenerateKey()
@@ -168,7 +165,6 @@ var _ = Describe("Management service", func() {
Expect(resp.GetRemotePeers()).To(HaveLen(2))
peers := []string{resp.GetRemotePeers()[0].WgPubKey, resp.GetRemotePeers()[1].WgPubKey}
Expect(peers).To(ContainElements(key1.PublicKey().String(), key2.PublicKey().String()))
})
})
@@ -211,7 +207,6 @@ var _ = Describe("Management service", func() {
resp = &mgmtProto.SyncResponse{}
err = pb.Unmarshal(decryptedBytes, resp)
wg.Done()
}()
// register a new peer
@@ -229,7 +224,6 @@ var _ = Describe("Management service", func() {
Context("when calling GetServerKey endpoint", func() {
Specify("a public Wireguard key of the service is returned", func() {
resp, err := client.GetServerKey(context.TODO(), &mgmtProto.Empty{})
Expect(err).NotTo(HaveOccurred())
@@ -237,19 +231,16 @@ var _ = Describe("Management service", func() {
Expect(resp.Key).ToNot(BeNil())
Expect(resp.ExpiresAt).ToNot(BeNil())
//check if the key is a valid Wireguard key
// check if the key is a valid Wireguard key
key, err := wgtypes.ParseKey(resp.Key)
Expect(err).NotTo(HaveOccurred())
Expect(key).ToNot(BeNil())
})
})
Context("when calling Login endpoint", func() {
Context("with an invalid setup key", func() {
Specify("an error is returned", func() {
key, _ := wgtypes.GenerateKey()
message, err := encryption.EncryptMessage(serverPubKey, key, &mgmtProto.LoginRequest{SetupKey: "invalid setup key"})
Expect(err).NotTo(HaveOccurred())
@@ -261,24 +252,20 @@ var _ = Describe("Management service", func() {
Expect(err).To(HaveOccurred())
Expect(resp).To(BeNil())
})
})
Context("with a valid setup key", func() {
It("a non error result is returned", func() {
key, _ := wgtypes.GenerateKey()
resp := loginPeerWithValidSetupKey(serverPubKey, key, client)
Expect(resp).ToNot(BeNil())
})
})
Context("with a registered peer", func() {
It("a non error result is returned", func() {
key, _ := wgtypes.GenerateKey()
regResp := loginPeerWithValidSetupKey(serverPubKey, key, client)
Expect(regResp).NotTo(BeNil())
@@ -324,7 +311,6 @@ var _ = Describe("Management service", func() {
Context("when there are 50 peers registered under one account", func() {
Context("when there are 10 more peers registered under the same account", func() {
Specify("all of the 50 peers will get updates of 10 newly registered peers", func() {
initialPeers := 20
additionalPeers := 10
@@ -369,7 +355,7 @@ var _ = Describe("Management service", func() {
err = pb.Unmarshal(decryptedBytes, resp)
Expect(err).NotTo(HaveOccurred())
if len(resp.GetRemotePeers()) > 0 {
//only consider peer updates
// only consider peer updates
wg.Done()
}
}
@@ -397,7 +383,6 @@ var _ = Describe("Management service", func() {
Context("when there are peers registered under one account concurrently", func() {
Specify("then there are no duplicate IPs", func() {
initialPeers := 30
ipChannel := make(chan string, 20)
@@ -423,7 +408,6 @@ var _ = Describe("Management service", func() {
Expect(err).NotTo(HaveOccurred())
ipChannel <- resp.GetPeerConfig().Address
}()
}
@@ -443,6 +427,7 @@ var _ = Describe("Management service", func() {
})
func loginPeerWithValidSetupKey(serverPubKey wgtypes.Key, key wgtypes.Key, client mgmtProto.ManagementServiceClient) *mgmtProto.LoginResponse {
defer GinkgoRecover()
meta := &mgmtProto.PeerSystemMeta{
Hostname: key.PublicKey().String(),
@@ -467,7 +452,6 @@ func loginPeerWithValidSetupKey(serverPubKey wgtypes.Key, key wgtypes.Key, clien
err = encryption.DecryptMessage(serverPubKey, key, resp.Body, loginResp)
Expect(err).NotTo(HaveOccurred())
return loginResp
}
func createRawClient(addr string) (mgmtProto.ManagementServiceClient, *grpc.ClientConn) {
@@ -496,7 +480,10 @@ func startServer(config *server.Config) (*grpc.Server, net.Listener) {
log.Fatalf("failed creating a store: %s: %v", config.Datadir, err)
}
peersUpdateManager := server.NewPeersUpdateManager()
accountManager := server.NewManager(store, peersUpdateManager, nil)
accountManager, err := server.BuildManager(store, peersUpdateManager, nil)
if err != nil {
log.Fatalf("failed creating a manager: %v", err)
}
turnManager := server.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig)
mgmtServer, err := server.NewServer(config, accountManager, peersUpdateManager, turnManager)
Expect(err).NotTo(HaveOccurred())

View File

@@ -33,6 +33,10 @@ type MockAccountManager struct {
GroupAddPeerFunc func(accountID, groupID, peerKey string) error
GroupDeletePeerFunc func(accountID, groupID, peerKey string) error
GroupListPeersFunc func(accountID, groupID string) ([]*server.Peer, error)
GetRuleFunc func(accountID, ruleID string) (*server.Rule, error)
SaveRuleFunc func(accountID string, rule *server.Rule) error
DeleteRuleFunc func(accountID, ruleID string) error
ListRulesFunc func(accountID string) ([]*server.Rule, error)
GetUsersFromAccountFunc func(accountID string) ([]*server.UserInfo, error)
}
@@ -41,7 +45,6 @@ func (am *MockAccountManager) GetUsersFromAccount(accountID string) ([]*server.U
return am.GetUsersFromAccountFunc(accountID)
}
return nil, status.Errorf(codes.Unimplemented, "method GetUsersFromAccount not implemented")
}
func (am *MockAccountManager) GetOrCreateAccountByUser(
@@ -207,7 +210,7 @@ func (am *MockAccountManager) SaveGroup(accountID string, group *server.Group) e
if am.SaveGroupFunc != nil {
return am.SaveGroupFunc(accountID, group)
}
return status.Errorf(codes.Unimplemented, "method UpdateGroup not implemented")
return status.Errorf(codes.Unimplemented, "method SaveGroup not implemented")
}
func (am *MockAccountManager) DeleteGroup(accountID, groupID string) error {
@@ -244,3 +247,31 @@ func (am *MockAccountManager) GroupListPeers(accountID, groupID string) ([]*serv
}
return nil, status.Errorf(codes.Unimplemented, "method GroupListPeers not implemented")
}
func (am *MockAccountManager) GetRule(accountID, ruleID string) (*server.Rule, error) {
if am.GetRuleFunc != nil {
return am.GetRuleFunc(accountID, ruleID)
}
return nil, status.Errorf(codes.Unimplemented, "method GetRule not implemented")
}
func (am *MockAccountManager) SaveRule(accountID string, rule *server.Rule) error {
if am.SaveRuleFunc != nil {
return am.SaveRuleFunc(accountID, rule)
}
return status.Errorf(codes.Unimplemented, "method SaveRule not implemented")
}
func (am *MockAccountManager) DeleteRule(accountID, ruleID string) error {
if am.DeleteRuleFunc != nil {
return am.DeleteRuleFunc(accountID, ruleID)
}
return status.Errorf(codes.Unimplemented, "method DeleteRule not implemented")
}
func (am *MockAccountManager) ListRules(accountID string) ([]*server.Rule, error) {
if am.ListRulesFunc != nil {
return am.ListRulesFunc(accountID)
}
return nil, status.Errorf(codes.Unimplemented, "method ListRules not implemented")
}

View File

@@ -1,12 +1,14 @@
package server
import (
"github.com/netbirdio/netbird/management/proto"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
log "github.com/sirupsen/logrus"
"net"
"strings"
"time"
"github.com/netbirdio/netbird/management/proto"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// PeerSystemMeta is a metadata of a Peer machine system
@@ -21,31 +23,31 @@ type PeerSystemMeta struct {
}
type PeerStatus struct {
//LastSeen is the last time peer was connected to the management service
// LastSeen is the last time peer was connected to the management service
LastSeen time.Time
//Connected indicates whether peer is connected to the management service or not
// Connected indicates whether peer is connected to the management service or not
Connected bool
}
//Peer represents a machine connected to the network.
//The Peer is a Wireguard peer identified by a public key
// Peer represents a machine connected to the network.
// The Peer is a Wireguard peer identified by a public key
type Peer struct {
//Wireguard public key
// Wireguard public key
Key string
//A setup key this peer was registered with
// A setup key this peer was registered with
SetupKey string
//IP address of the Peer
// IP address of the Peer
IP net.IP
//Meta is a Peer system meta data
// Meta is a Peer system meta data
Meta PeerSystemMeta
//Name is peer's name (machine name)
// Name is peer's name (machine name)
Name string
Status *PeerStatus
//The user ID that registered the peer
// The user ID that registered the peer
UserID string
}
//Copy copies Peer object
// Copy copies Peer object
func (p *Peer) Copy() *Peer {
return &Peer{
Key: p.Key,
@@ -58,7 +60,7 @@ func (p *Peer) Copy() *Peer {
}
}
//GetPeer returns a peer from a Store
// GetPeer returns a peer from a Store
func (am *DefaultAccountManager) GetPeer(peerKey string) (*Peer, error) {
am.mux.Lock()
defer am.mux.Unlock()
@@ -71,7 +73,7 @@ func (am *DefaultAccountManager) GetPeer(peerKey string) (*Peer, error) {
return peer, nil
}
//MarkPeerConnected marks peer as connected (true) or disconnected (false)
// MarkPeerConnected marks peer as connected (true) or disconnected (false)
func (am *DefaultAccountManager) MarkPeerConnected(peerKey string, connected bool) error {
am.mux.Lock()
defer am.mux.Unlock()
@@ -96,8 +98,12 @@ func (am *DefaultAccountManager) MarkPeerConnected(peerKey string, connected boo
return nil
}
//RenamePeer changes peer's name
func (am *DefaultAccountManager) RenamePeer(accountId string, peerKey string, newName string) (*Peer, error) {
// RenamePeer changes peer's name
func (am *DefaultAccountManager) RenamePeer(
accountId string,
peerKey string,
newName string,
) (*Peer, error) {
am.mux.Lock()
defer am.mux.Unlock()
@@ -116,7 +122,7 @@ func (am *DefaultAccountManager) RenamePeer(accountId string, peerKey string, ne
return peerCopy, nil
}
//DeletePeer removes peer from the account by it's IP
// DeletePeer removes peer from the account by it's IP
func (am *DefaultAccountManager) DeletePeer(accountId string, peerKey string) (*Peer, error) {
am.mux.Lock()
defer am.mux.Unlock()
@@ -149,12 +155,13 @@ func (am *DefaultAccountManager) DeletePeer(accountId string, peerKey string) (*
RemotePeers: []*proto.RemotePeerConfig{},
RemotePeersIsEmpty: true,
},
}})
},
})
if err != nil {
return nil, err
}
//notify other peers of the change
// notify other peers of the change
peers, err := am.Store.GetAccountPeers(accountId)
if err != nil {
return nil, err
@@ -180,7 +187,8 @@ func (am *DefaultAccountManager) DeletePeer(accountId string, peerKey string) (*
RemotePeers: update,
RemotePeersIsEmpty: len(update) == 0,
},
}})
},
})
if err != nil {
return nil, err
}
@@ -190,7 +198,7 @@ func (am *DefaultAccountManager) DeletePeer(accountId string, peerKey string) (*
return peer, nil
}
//GetPeerByIP returns peer by it's IP
// GetPeerByIP returns peer by it's IP
func (am *DefaultAccountManager) GetPeerByIP(accountId string, peerIP string) (*Peer, error) {
am.mux.Lock()
defer am.mux.Unlock()
@@ -220,10 +228,50 @@ func (am *DefaultAccountManager) GetNetworkMap(peerKey string) (*NetworkMap, err
}
var res []*Peer
for _, peer := range account.Peers {
// exclude original peer
if peer.Key != peerKey {
res = append(res, peer.Copy())
srcRules, err := am.Store.GetPeerSrcRules(account.Id, peerKey)
if err != nil {
return &NetworkMap{
Peers: res,
Network: account.Network.Copy(),
}, nil
}
dstRules, err := am.Store.GetPeerDstRules(account.Id, peerKey)
if err != nil {
return &NetworkMap{
Peers: res,
Network: account.Network.Copy(),
}, nil
}
groups := map[string]*Group{}
for _, r := range srcRules {
if r.Flow == TrafficFlowBidirect {
for _, gid := range r.Destination {
groups[gid] = account.Groups[gid]
}
}
}
for _, r := range dstRules {
if r.Flow == TrafficFlowBidirect {
for _, gid := range r.Source {
groups[gid] = account.Groups[gid]
}
}
}
for _, g := range groups {
for _, pid := range g.Peers {
peer, ok := account.Peers[pid]
if !ok {
log.Warnf("peer %s found in group %s but doesn't belong to account %s", pid, g.ID, account.Id)
continue
}
// exclude original peer
if peer.Key != peerKey {
res = append(res, peer.Copy())
}
}
}
@@ -240,7 +288,11 @@ func (am *DefaultAccountManager) GetNetworkMap(peerKey string) (*NetworkMap, err
// to it. We also add the User ID to the peer metadata to identify registrant.
// Each new Peer will be assigned a new next net.IP from the Account.Network and Account.Network.LastIP will be updated (IP's are not reused).
// The peer property is just a placeholder for the Peer properties to pass further
func (am *DefaultAccountManager) AddPeer(setupKey string, userID string, peer *Peer) (*Peer, error) {
func (am *DefaultAccountManager) AddPeer(
setupKey string,
userID string,
peer *Peer,
) (*Peer, error) {
am.mux.Lock()
defer am.mux.Unlock()
@@ -252,17 +304,28 @@ func (am *DefaultAccountManager) AddPeer(setupKey string, userID string, peer *P
if len(upperKey) != 0 {
account, err = am.Store.GetAccountBySetupKey(upperKey)
if err != nil {
return nil, status.Errorf(codes.NotFound, "unable to register peer, unable to find account with setupKey %s", upperKey)
return nil, status.Errorf(
codes.NotFound,
"unable to register peer, unable to find account with setupKey %s",
upperKey,
)
}
sk = getAccountSetupKeyByKey(account, upperKey)
if sk == nil {
// shouldn't happen actually
return nil, status.Errorf(codes.NotFound, "unable to register peer, unknown setupKey %s", upperKey)
return nil, status.Errorf(
codes.NotFound,
"unable to register peer, unknown setupKey %s",
upperKey,
)
}
if !sk.IsValid() {
return nil, status.Errorf(codes.FailedPrecondition, "unable to register peer, its setup key is invalid (expired, overused or revoked)")
return nil, status.Errorf(
codes.FailedPrecondition,
"unable to register peer, its setup key is invalid (expired, overused or revoked)",
)
}
} else if len(userID) != 0 {
@@ -293,6 +356,13 @@ func (am *DefaultAccountManager) AddPeer(setupKey string, userID string, peer *P
Status: &PeerStatus{Connected: false, LastSeen: time.Now()},
}
// add peer to 'All' group
group, err := account.GetGroupAll()
if err != nil {
return nil, err
}
group.Peers = append(group.Peers, newPeer.Key)
account.Peers[newPeer.Key] = newPeer
if len(upperKey) != 0 {
account.SetupKeys[sk.Key] = sk.IncrementUsage()
@@ -305,5 +375,4 @@ func (am *DefaultAccountManager) AddPeer(setupKey string, userID string, peer *P
}
return newPeer, nil
}

View File

@@ -1,8 +1,10 @@
package server
import (
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"testing"
"github.com/rs/xid"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
func TestAccountManager_GetNetworkMap(t *testing.T) {
@@ -70,7 +72,151 @@ func TestAccountManager_GetNetworkMap(t *testing.T) {
}
if networkMap.Peers[0].Key != peerKey2.PublicKey().String() {
t.Errorf("expecting Account NetworkMap to have peer with a key %s, got %s", peerKey2.PublicKey().String(), networkMap.Peers[0].Key)
t.Errorf(
"expecting Account NetworkMap to have peer with a key %s, got %s",
peerKey2.PublicKey().String(),
networkMap.Peers[0].Key,
)
}
}
func TestAccountManager_GetNetworkMapWithRule(t *testing.T) {
manager, err := createManager(t)
if err != nil {
t.Fatal(err)
return
}
expectedId := "test_account"
userId := "account_creator"
account, err := manager.AddAccount(expectedId, userId, "")
if err != nil {
t.Fatal(err)
}
var setupKey *SetupKey
for _, key := range account.SetupKeys {
if key.Type == SetupKeyReusable {
setupKey = key
}
}
peerKey1, err := wgtypes.GeneratePrivateKey()
if err != nil {
t.Fatal(err)
return
}
_, err = manager.AddPeer(setupKey.Key, "", &Peer{
Key: peerKey1.PublicKey().String(),
Meta: PeerSystemMeta{},
Name: "test-peer-2",
})
if err != nil {
t.Errorf("expecting peer to be added, got failure %v", err)
return
}
peerKey2, err := wgtypes.GeneratePrivateKey()
if err != nil {
t.Fatal(err)
return
}
_, err = manager.AddPeer(setupKey.Key, "", &Peer{
Key: peerKey2.PublicKey().String(),
Meta: PeerSystemMeta{},
Name: "test-peer-2",
})
if err != nil {
t.Errorf("expecting peer to be added, got failure %v", err)
return
}
rules, err := manager.ListRules(account.Id)
if err != nil {
t.Errorf("expecting to get a list of rules, got failure %v", err)
return
}
err = manager.DeleteRule(account.Id, rules[0].ID)
if err != nil {
t.Errorf("expecting to delete 1 group, got failure %v", err)
return
}
var (
group1 Group
group2 Group
rule Rule
)
group1.ID = xid.New().String()
group2.ID = xid.New().String()
group1.Name = "src"
group2.Name = "dst"
rule.ID = xid.New().String()
group1.Peers = append(group1.Peers, peerKey1.PublicKey().String())
group2.Peers = append(group2.Peers, peerKey2.PublicKey().String())
err = manager.SaveGroup(account.Id, &group1)
if err != nil {
t.Errorf("expecting group1 to be added, got failure %v", err)
return
}
err = manager.SaveGroup(account.Id, &group2)
if err != nil {
t.Errorf("expecting group2 to be added, got failure %v", err)
return
}
rule.Name = "test"
rule.Source = append(rule.Source, group1.ID)
rule.Destination = append(rule.Destination, group2.ID)
rule.Flow = TrafficFlowBidirect
err = manager.SaveRule(account.Id, &rule)
if err != nil {
t.Errorf("expecting rule to be added, got failure %v", err)
return
}
networkMap1, err := manager.GetNetworkMap(peerKey1.PublicKey().String())
if err != nil {
t.Fatal(err)
return
}
if len(networkMap1.Peers) != 1 {
t.Errorf(
"expecting Account NetworkMap to have 1 peers, got %v: %v",
len(networkMap1.Peers),
networkMap1.Peers,
)
}
if networkMap1.Peers[0].Key != peerKey2.PublicKey().String() {
t.Errorf(
"expecting Account NetworkMap to have peer with a key %s, got %s",
peerKey2.PublicKey().String(),
networkMap1.Peers[0].Key,
)
}
networkMap2, err := manager.GetNetworkMap(peerKey2.PublicKey().String())
if err != nil {
t.Fatal(err)
return
}
if len(networkMap2.Peers) != 1 {
t.Errorf("expecting Account NetworkMap to have 1 peers, got %v", len(networkMap2.Peers))
}
if len(networkMap2.Peers) > 0 && networkMap2.Peers[0].Key != peerKey1.PublicKey().String() {
t.Errorf(
"expecting Account NetworkMap to have peer with a key %s, got %s",
peerKey1.PublicKey().String(),
networkMap2.Peers[0].Key,
)
}
}

107
management/server/rule.go Normal file
View File

@@ -0,0 +1,107 @@
package server
import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// TrafficFlowType defines allowed direction of the traffic in the rule
type TrafficFlowType int
const (
// TrafficFlowBidirect allows traffic to both direction
TrafficFlowBidirect TrafficFlowType = iota
)
// Rule of ACL for groups
type Rule struct {
// ID of the rule
ID string
// Name of the rule visible in the UI
Name string
// Source list of groups IDs of peers
Source []string
// Destination list of groups IDs of peers
Destination []string
// Flow of the traffic allowed by the rule
Flow TrafficFlowType
}
func (r *Rule) Copy() *Rule {
return &Rule{
ID: r.ID,
Name: r.Name,
Source: r.Source[:],
Destination: r.Destination[:],
Flow: r.Flow,
}
}
// GetRule of ACL from the store
func (am *DefaultAccountManager) GetRule(accountID, ruleID string) (*Rule, error) {
am.mux.Lock()
defer am.mux.Unlock()
account, err := am.Store.GetAccount(accountID)
if err != nil {
return nil, status.Errorf(codes.NotFound, "account not found")
}
rule, ok := account.Rules[ruleID]
if ok {
return rule, nil
}
return nil, status.Errorf(codes.NotFound, "rule with ID %s not found", ruleID)
}
// SaveRule of ACL in the store
func (am *DefaultAccountManager) SaveRule(accountID string, rule *Rule) error {
am.mux.Lock()
defer am.mux.Unlock()
account, err := am.Store.GetAccount(accountID)
if err != nil {
return status.Errorf(codes.NotFound, "account not found")
}
account.Rules[rule.ID] = rule
return am.Store.SaveAccount(account)
}
// DeleteRule of ACL from the store
func (am *DefaultAccountManager) DeleteRule(accountID, ruleID string) error {
am.mux.Lock()
defer am.mux.Unlock()
account, err := am.Store.GetAccount(accountID)
if err != nil {
return status.Errorf(codes.NotFound, "account not found")
}
delete(account.Rules, ruleID)
return am.Store.SaveAccount(account)
}
// ListRules of ACL from the store
func (am *DefaultAccountManager) ListRules(accountID string) ([]*Rule, error) {
am.mux.Lock()
defer am.mux.Unlock()
account, err := am.Store.GetAccount(accountID)
if err != nil {
return nil, status.Errorf(codes.NotFound, "account not found")
}
rules := make([]*Rule, 0, len(account.Rules))
for _, item := range account.Rules {
rules = append(rules, item)
}
return rules, nil
}

View File

@@ -4,10 +4,13 @@ type Store interface {
GetPeer(peerKey string) (*Peer, error)
DeletePeer(accountId string, peerKey string) (*Peer, error)
SavePeer(accountId string, peer *Peer) error
GetAllAccounts() []*Account
GetAccount(accountId string) (*Account, error)
GetUserAccount(userId string) (*Account, error)
GetAccountPeers(accountId string) ([]*Peer, error)
GetPeerAccount(peerKey string) (*Account, error)
GetPeerSrcRules(accountId, peerKey string) ([]*Rule, error)
GetPeerDstRules(accountId, peerKey string) ([]*Rule, error)
GetAccountBySetupKey(setupKey string) (*Account, error)
GetAccountByPrivateDomain(domain string) (*Account, error)
SaveAccount(account *Account) error

View File

@@ -58,6 +58,7 @@ func (am *DefaultAccountManager) GetOrCreateAccountByUser(userId, domain string)
if s, ok := status.FromError(err); ok && s.Code() == codes.NotFound {
account = NewAccount(userId, lowerDomain)
account.Users[userId] = NewAdminUser(userId)
am.addAllGroup(account)
err = am.Store.SaveAccount(account)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed creating account")

View File

@@ -12,24 +12,24 @@ fi
cleanInstall() {
printf "\033[32m Post Install of an clean install\033[0m\n"
# Step 3 (clean install), enable the service in the proper way for this platform
/usr/bin/wiretrustee service install
/usr/bin/wiretrustee service start
/usr/bin/netbird service install
/usr/bin/netbird service start
}
upgrade() {
printf "\033[32m Post Install of an upgrade\033[0m\n"
if [ "${use_systemctl}" = "True" ]; then
printf "\033[32m Stopping the service\033[0m\n"
systemctl stop wiretrustee 2> /dev/null || true
systemctl stop netbird 2> /dev/null || true
fi
if [ -e /lib/systemd/system/wiretrustee.service ]; then
rm -f /lib/systemd/system/wiretrustee.service
if [ -e /lib/systemd/system/netbird.service ]; then
rm -f /lib/systemd/system/netbird.service
systemctl daemon-reload
fi
# will trow an error until everyone upgrade
/usr/bin/wiretrustee service uninstall 2> /dev/null || true
/usr/bin/wiretrustee service install
/usr/bin/wiretrustee service start
/usr/bin/netbird service uninstall 2> /dev/null || true
/usr/bin/netbird service install
/usr/bin/netbird service start
}
# Check if this is a clean install or an upgrade

View File

@@ -13,16 +13,16 @@ remove() {
if [ "${use_systemctl}" = "True" ]; then
printf "\033[32m Stopping the service\033[0m\n"
systemctl stop wiretrustee || true
systemctl stop netbird || true
if [ -e /lib/systemd/system/wiretrustee.service ]; then
rm -f /lib/systemd/system/wiretrustee.service
if [ -e /lib/systemd/system/netbird.service ]; then
rm -f /lib/systemd/system/netbird.service
systemctl daemon-reload || true
fi
fi
printf "\033[32m Uninstalling the service\033[0m\n"
/usr/bin/wiretrustee service uninstall || true
/usr/bin/netbird service uninstall || true
if [ "${use_systemctl}" = "True" ]; then

View File

@@ -5,31 +5,31 @@ This is a netbird signal-exchange server and client library to exchange connecti
## Command Options
The CLI accepts the command **management** with the following options:
```shell
start Wiretrustee Signal Server daemon
start Netbird Signal Server daemon
Usage:
wiretrustee-signal run [flags]
netbird-signal run [flags]
Flags:
-h, --help help for run
--letsencrypt-domain string a domain to issue Let's Encrypt certificate for. Enables TLS using Let's Encrypt. Will fetch and renew certificate, and run the server with TLS
--port int Server port to listen on (e.g. 10000) (default 10000)
--ssl-dir string server ssl directory location. *Required only for Let's Encrypt certificates. (default "/var/lib/wiretrustee/")
--ssl-dir string server ssl directory location. *Required only for Let's Encrypt certificates. (default "/var/lib/netbird/")
Global Flags:
--log-file string sets Netbird log path. If console is specified the the log will be output to stdout (default "/var/log/netbird/signal.log")
--log-level string (default "info")
--log-file string sets Wiretrustee log path. If console is specified the the log will be output to stdout (default "/var/log/wiretrustee/management.log")
```
## Running the Signal service (Docker)
We have packed the Signal server into docker image. You can pull the image from Docker Hub and execute it with the following commands:
````shell
docker pull wiretrustee/signal:latest
docker run -d --name wiretrustee-signal -p 10000:10000 wiretrustee/signal:latest
docker pull netbirdio/signal:latest
docker run -d --name netbird-signal -p 10000:10000 netbirdio/signal:latest
````
The default log-level is set to INFO, if you need you can change it using by updating the docker cmd as followed:
````shell
docker run -d --name wiretrustee-signal -p 10000:10000 wiretrustee/signal:latest --log-level DEBUG
docker run -d --name netbird-signal -p 10000:10000 netbirdio/signal:latest --log-level DEBUG
````
### Run with TLS (Let's Encrypt).
By specifying the **--letsencrypt-domain** the daemon will handle SSL certificate request and configuration.
@@ -43,11 +43,11 @@ Replace <YOUR-DOMAIN> with your server's public domain (e.g. mydomain.com or sub
# create a volume
docker volume create wiretrustee-signal
# run the docker container
docker run -d --name wiretrustee-management \
docker run -d --name netbird-signal \
-p 10000:10000 \
-p 443:443 \
-v wiretrustee-signal:/var/lib/wiretrustee \
wiretrustee/signal:latest \
-v netbird-signal:/var/lib/netbird \
netbirdio/signal:latest \
--letsencrypt-domain <YOUR-DOMAIN>
```
## For development purposes:

View File

@@ -1,9 +1,11 @@
package cmd
import (
"errors"
"flag"
"fmt"
"io"
"io/fs"
"io/ioutil"
"net"
"net/http"
@@ -178,10 +180,10 @@ func cpDir(src string, dst string) error {
}
func migrateToNetbird(oldPath, newPath string) bool {
_, old := os.Stat(oldPath)
_, new := os.Stat(newPath)
_, errOld := os.Stat(oldPath)
_, errNew := os.Stat(newPath)
if os.IsNotExist(old) || os.IsExist(new) {
if errors.Is(errOld, fs.ErrNotExist) || errNew == nil {
return false
}