mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-06 17:08:53 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ae27c9a9b | ||
|
|
ff6e369a21 | ||
|
|
5c3b5e7f40 | ||
|
|
8c75ef8bef | ||
|
|
fdc11fff47 |
4
.github/workflows/golang-test.yml
vendored
4
.github/workflows/golang-test.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [1.16.x]
|
go-version: [1.17.x]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ windows, linux, darwin ]
|
os: [ windows, linux, darwin ]
|
||||||
go-version: [1.16.x]
|
go-version: [1.17.x]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
|
|||||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
|||||||
name: Set up Go
|
name: Set up Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.16
|
go-version: 1.17
|
||||||
-
|
-
|
||||||
name: Cache Go modules
|
name: Cache Go modules
|
||||||
uses: actions/cache@v1
|
uses: actions/cache@v1
|
||||||
|
|||||||
13
README.md
13
README.md
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
**Wiretrustee is an open-source VPN platform built on top of WireGuard® making it easy to create secure private networks for your organization or home.**
|
**Wiretrustee is an open-source VPN platform built on top of WireGuard® making it easy to create secure private networks for your organization or home.**
|
||||||
|
|
||||||
It requires zero configuration effort leaving behind the hassle of opening ports, complex firewall rules, vpn gateways, and so forth.
|
It requires zero configuration effort leaving behind the hassle of opening ports, complex firewall rules, VPN gateways, and so forth.
|
||||||
|
|
||||||
**Wiretrustee automates Wireguard-based networks, offering a management layer with:**
|
**Wiretrustee automates Wireguard-based networks, offering a management layer with:**
|
||||||
* Centralized Peer IP management with a UI dashboard.
|
* Centralized Peer IP management with a UI dashboard.
|
||||||
@@ -56,14 +56,17 @@ Hosted demo version:
|
|||||||
|
|
||||||
|
|
||||||
### A bit on Wiretrustee internals
|
### A bit on Wiretrustee internals
|
||||||
* Wiretrustee features a Management Service that offers peer IP management and network updates distribution (e.g. when new peer joins the network).
|
* Wiretrustee features a Management Service that offers peer IP management and network updates distribution (e.g. when a new peer joins the network).
|
||||||
* Wiretrustee uses WebRTC ICE implemented in [pion/ice library](https://github.com/pion/ice) to discover connection candidates when establishing a peer-to-peer connection between devices.
|
* Wiretrustee uses WebRTC ICE implemented in [pion/ice library](https://github.com/pion/ice) to discover connection candidates when establishing a peer-to-peer connection between devices.
|
||||||
* Peers negotiate connection through [Signal Service](signal/).
|
* Peers negotiate connection through [Signal Service](signal/).
|
||||||
* Signal Service uses public Wireguard keys to route messages between peers.
|
* Signal Service uses public Wireguard keys to route messages between peers.
|
||||||
Contents of the messages sent between peers through the signaling server are encrypted with Wireguard keys, making it impossible to inspect them.
|
Contents of the messages sent between peers through the signaling server are encrypted with Wireguard keys, making it impossible to inspect them.
|
||||||
* Occasionally, the NAT-traversal is unsuccessful due to strict NATs (e.g. mobile carrier-grade NAT).
|
* 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 Wiretrustee setups.
|
||||||
When this occurs the system falls back to relay server (TURN), and a secure Wireguard tunnel is established via TURN server.
|
|
||||||
[Coturn](https://github.com/coturn/coturn) is the one that has been successfully used for STUN and TURN in Wiretrustee setups.
|
<p float="left" align="middle">
|
||||||
|
<img src="https://docs.wiretrustee.com/img/architecture/high-level-dia.png" width="700"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
### Product Roadmap
|
### Product Roadmap
|
||||||
- [Public Roadmap](https://github.com/wiretrustee/wiretrustee/projects/2)
|
- [Public Roadmap](https://github.com/wiretrustee/wiretrustee/projects/2)
|
||||||
|
|||||||
66
go.mod
66
go.mod
@@ -1,28 +1,62 @@
|
|||||||
module github.com/wiretrustee/wiretrustee
|
module github.com/wiretrustee/wiretrustee
|
||||||
|
|
||||||
go 1.16
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/cenkalti/backoff/v4 v4.1.0
|
github.com/cenkalti/backoff/v4 v4.1.2
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
github.com/golang/protobuf v1.5.2
|
github.com/golang/protobuf v1.5.2
|
||||||
github.com/google/uuid v1.2.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/kardianos/service v1.2.1-0.20210728001519-a323c3813bc7
|
github.com/kardianos/service v1.2.1-0.20210728001519-a323c3813bc7 //keep this version otherwise wiretrustee up command breaks
|
||||||
github.com/onsi/ginkgo v1.16.4
|
github.com/onsi/ginkgo v1.16.5
|
||||||
github.com/onsi/gomega v1.13.0
|
github.com/onsi/gomega v1.17.0
|
||||||
github.com/pion/ice/v2 v2.1.7
|
github.com/pion/ice/v2 v2.1.17
|
||||||
github.com/rs/cors v1.8.0
|
github.com/rs/cors v1.8.0
|
||||||
github.com/sirupsen/logrus v1.7.0
|
github.com/sirupsen/logrus v1.8.1
|
||||||
github.com/spf13/cobra v1.1.3
|
github.com/spf13/cobra v1.3.0
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/vishvananda/netlink v1.1.0
|
github.com/vishvananda/netlink v1.1.0
|
||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
|
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20210805125648-3957e9b9dd19
|
golang.zx2c4.com/wireguard v0.0.0-20211209221555-9c9e7e272434
|
||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20211215182854-7a385b3431de
|
||||||
golang.zx2c4.com/wireguard/windows v0.4.5
|
golang.zx2c4.com/wireguard/windows v0.5.1
|
||||||
google.golang.org/grpc v1.32.0
|
google.golang.org/grpc v1.43.0
|
||||||
google.golang.org/protobuf v1.26.0
|
google.golang.org/protobuf v1.27.1
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require github.com/rs/xid v1.3.0
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/BurntSushi/toml v0.4.1 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||||
|
github.com/google/go-cmp v0.5.6 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
|
github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect
|
||||||
|
github.com/mdlayher/genetlink v1.1.0 // indirect
|
||||||
|
github.com/mdlayher/netlink v1.4.2 // indirect
|
||||||
|
github.com/mdlayher/socket v0.0.0-20211102153432-57e3fa563ecb // indirect
|
||||||
|
github.com/nxadm/tail v1.4.8 // indirect
|
||||||
|
github.com/pion/dtls/v2 v2.0.12 // indirect
|
||||||
|
github.com/pion/logging v0.2.2 // indirect
|
||||||
|
github.com/pion/mdns v0.0.5 // indirect
|
||||||
|
github.com/pion/randutil v0.1.0 // indirect
|
||||||
|
github.com/pion/stun v0.3.5 // indirect
|
||||||
|
github.com/pion/transport v0.12.3 // indirect
|
||||||
|
github.com/pion/turn/v2 v2.0.5 // indirect
|
||||||
|
github.com/pion/udp v0.1.1 // indirect
|
||||||
|
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect
|
||||||
|
golang.org/x/mod v0.5.1 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b // indirect
|
||||||
|
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 // indirect
|
||||||
|
golang.org/x/tools v0.1.8 // indirect
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
|
golang.zx2c4.com/go118/netip v0.0.0-20211111135330-a4a02eeacf9d // indirect
|
||||||
|
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
|
||||||
|
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
honnef.co/go/tools v0.2.2 // indirect
|
||||||
|
)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/connectivity"
|
"google.golang.org/grpc/connectivity"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
"google.golang.org/grpc/keepalive"
|
"google.golang.org/grpc/keepalive"
|
||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
@@ -28,7 +29,7 @@ type Client struct {
|
|||||||
// NewClient creates a new client to Management service
|
// NewClient creates a new client to Management service
|
||||||
func NewClient(ctx context.Context, addr string, ourPrivateKey wgtypes.Key, tlsEnabled bool) (*Client, error) {
|
func NewClient(ctx context.Context, addr string, ourPrivateKey wgtypes.Key, tlsEnabled bool) (*Client, error) {
|
||||||
|
|
||||||
transportOption := grpc.WithInsecure()
|
transportOption := grpc.WithTransportCredentials(insecure.NewCredentials())
|
||||||
|
|
||||||
if tlsEnabled {
|
if tlsEnabled {
|
||||||
transportOption = grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{}))
|
transportOption = grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{}))
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/rs/xid"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/wiretrustee/wiretrustee/util"
|
"github.com/wiretrustee/wiretrustee/util"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
@@ -20,9 +21,38 @@ type AccountManager struct {
|
|||||||
// Account represents a unique account of the system
|
// Account represents a unique account of the system
|
||||||
type Account struct {
|
type Account struct {
|
||||||
Id string
|
Id string
|
||||||
|
// User.Id it was created by
|
||||||
|
CreatedBy string
|
||||||
SetupKeys map[string]*SetupKey
|
SetupKeys map[string]*SetupKey
|
||||||
Network *Network
|
Network *Network
|
||||||
Peers map[string]*Peer
|
Peers map[string]*Peer
|
||||||
|
Users map[string]*User
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Account) Copy() *Account {
|
||||||
|
peers := map[string]*Peer{}
|
||||||
|
for id, peer := range a.Peers {
|
||||||
|
peers[id] = peer.Copy()
|
||||||
|
}
|
||||||
|
|
||||||
|
users := map[string]*User{}
|
||||||
|
for id, user := range a.Users {
|
||||||
|
users[id] = user.Copy()
|
||||||
|
}
|
||||||
|
|
||||||
|
setupKeys := map[string]*SetupKey{}
|
||||||
|
for id, key := range a.SetupKeys {
|
||||||
|
setupKeys[id] = key.Copy()
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Account{
|
||||||
|
Id: a.Id,
|
||||||
|
CreatedBy: a.CreatedBy,
|
||||||
|
SetupKeys: setupKeys,
|
||||||
|
Network: a.Network.Copy(),
|
||||||
|
Peers: peers,
|
||||||
|
Users: users,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewManager creates a new AccountManager with a provided Store
|
// NewManager creates a new AccountManager with a provided Store
|
||||||
@@ -125,29 +155,6 @@ func (am *AccountManager) GetAccount(accountId string) (*Account, error) {
|
|||||||
return account, nil
|
return account, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrCreateAccount returns an existing account or creates a new one if doesn't exist
|
|
||||||
func (am *AccountManager) GetOrCreateAccount(accountId string) (*Account, error) {
|
|
||||||
am.mux.Lock()
|
|
||||||
defer am.mux.Unlock()
|
|
||||||
|
|
||||||
_, err := am.Store.GetAccount(accountId)
|
|
||||||
if err != nil {
|
|
||||||
if s, ok := status.FromError(err); ok && s.Code() == codes.NotFound {
|
|
||||||
return am.createAccount(accountId)
|
|
||||||
} else {
|
|
||||||
// other error
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err := am.Store.GetAccount(accountId)
|
|
||||||
if err != nil {
|
|
||||||
return nil, status.Errorf(codes.Internal, "failed retrieving account")
|
|
||||||
}
|
|
||||||
|
|
||||||
return account, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//AccountExists checks whether account exists (returns true) or not (returns false)
|
//AccountExists checks whether account exists (returns true) or not (returns false)
|
||||||
func (am *AccountManager) AccountExists(accountId string) (*bool, error) {
|
func (am *AccountManager) AccountExists(accountId string) (*bool, error) {
|
||||||
am.mux.Lock()
|
am.mux.Lock()
|
||||||
@@ -168,18 +175,18 @@ func (am *AccountManager) AccountExists(accountId string) (*bool, error) {
|
|||||||
return &res, nil
|
return &res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddAccount generates a new Account with a provided accountId and saves to the Store
|
// AddAccount generates a new Account with a provided accountId and userId, saves to the Store
|
||||||
func (am *AccountManager) AddAccount(accountId string) (*Account, error) {
|
func (am *AccountManager) AddAccount(accountId string, userId string) (*Account, error) {
|
||||||
|
|
||||||
am.mux.Lock()
|
am.mux.Lock()
|
||||||
defer am.mux.Unlock()
|
defer am.mux.Unlock()
|
||||||
|
|
||||||
return am.createAccount(accountId)
|
return am.createAccount(accountId, userId)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (am *AccountManager) createAccount(accountId string) (*Account, error) {
|
func (am *AccountManager) createAccount(accountId string, userId string) (*Account, error) {
|
||||||
account, _ := newAccountWithId(accountId)
|
account, _ := newAccountWithId(accountId, userId)
|
||||||
|
|
||||||
err := am.Store.SaveAccount(account)
|
err := am.Store.SaveAccount(account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -190,7 +197,7 @@ func (am *AccountManager) createAccount(accountId string) (*Account, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newAccountWithId creates a new Account with a default SetupKey (doesn't store in a Store) and provided id
|
// newAccountWithId creates a new Account with a default SetupKey (doesn't store in a Store) and provided id
|
||||||
func newAccountWithId(accountId string) (*Account, *SetupKey) {
|
func newAccountWithId(accountId string, userId string) (*Account, *SetupKey) {
|
||||||
|
|
||||||
log.Debugf("creating new account")
|
log.Debugf("creating new account")
|
||||||
|
|
||||||
@@ -204,16 +211,17 @@ func newAccountWithId(accountId string) (*Account, *SetupKey) {
|
|||||||
Net: net.IPNet{IP: net.ParseIP("100.64.0.0"), Mask: net.IPMask{255, 192, 0, 0}},
|
Net: net.IPNet{IP: net.ParseIP("100.64.0.0"), Mask: net.IPMask{255, 192, 0, 0}},
|
||||||
Dns: ""}
|
Dns: ""}
|
||||||
peers := make(map[string]*Peer)
|
peers := make(map[string]*Peer)
|
||||||
|
users := make(map[string]*User)
|
||||||
|
|
||||||
log.Debugf("created new account %s with setup key %s", accountId, defaultKey.Key)
|
log.Debugf("created new account %s with setup key %s", accountId, defaultKey.Key)
|
||||||
|
|
||||||
return &Account{Id: accountId, SetupKeys: setupKeys, Network: network, Peers: peers}, defaultKey
|
return &Account{Id: accountId, SetupKeys: setupKeys, Network: network, Peers: peers, Users: users, CreatedBy: userId}, defaultKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// newAccount creates a new Account with a default SetupKey (doesn't store in a Store)
|
// newAccount creates a new Account with a default SetupKey and a provided User.Id of a user who issued account creation (doesn't store in a Store)
|
||||||
func newAccount() (*Account, *SetupKey) {
|
func newAccount(userId string) (*Account, *SetupKey) {
|
||||||
accountId := uuid.New().String()
|
accountId := xid.New().String()
|
||||||
return newAccountWithId(accountId)
|
return newAccountWithId(accountId, userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAccountSetupKeyById(acc *Account, keyId string) *SetupKey {
|
func getAccountSetupKeyById(acc *Account, keyId string) *SetupKey {
|
||||||
|
|||||||
@@ -2,12 +2,36 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
"google.golang.org/grpc/codes"
|
|
||||||
"google.golang.org/grpc/status"
|
|
||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestAccountManager_GetOrCreateAccountByUser(t *testing.T) {
|
||||||
|
manager, err := createManager(t)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userId := "test_user"
|
||||||
|
account, err := manager.GetOrCreateAccountByUser(userId)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if account == nil {
|
||||||
|
t.Fatalf("expected to create an account for a user %s", userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
account, err = manager.GetAccountByUser(userId)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("expected to get existing account after creation, no account was found for a user %s", userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if account != nil && account.Users[userId] == nil {
|
||||||
|
t.Fatalf("expected to create an account for a user %s but no user was found after creation udner the account %s", userId, account.Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAccountManager_AddAccount(t *testing.T) {
|
func TestAccountManager_AddAccount(t *testing.T) {
|
||||||
manager, err := createManager(t)
|
manager, err := createManager(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -16,6 +40,7 @@ func TestAccountManager_AddAccount(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expectedId := "test_account"
|
expectedId := "test_account"
|
||||||
|
userId := "account_creator"
|
||||||
expectedPeersSize := 0
|
expectedPeersSize := 0
|
||||||
expectedSetupKeysSize := 2
|
expectedSetupKeysSize := 2
|
||||||
expectedNetwork := net.IPNet{
|
expectedNetwork := net.IPNet{
|
||||||
@@ -23,7 +48,7 @@ func TestAccountManager_AddAccount(t *testing.T) {
|
|||||||
Mask: net.IPMask{255, 192, 0, 0},
|
Mask: net.IPMask{255, 192, 0, 0},
|
||||||
}
|
}
|
||||||
|
|
||||||
account, err := manager.AddAccount(expectedId)
|
account, err := manager.AddAccount(expectedId, userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -45,46 +70,6 @@ func TestAccountManager_AddAccount(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccountManager_GetOrCreateAccount(t *testing.T) {
|
|
||||||
manager, err := createManager(t)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedId := "test_account"
|
|
||||||
|
|
||||||
//make sure account doesn't exist
|
|
||||||
account, err := manager.GetAccount(expectedId)
|
|
||||||
if err != nil {
|
|
||||||
errStatus, ok := status.FromError(err)
|
|
||||||
if !(ok && errStatus.Code() == codes.NotFound) {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if account != nil {
|
|
||||||
t.Fatal("expecting empty account")
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err = manager.GetOrCreateAccount(expectedId)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if account.Id != expectedId {
|
|
||||||
t.Fatalf("expected to create an account, got wrong account")
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err = manager.GetOrCreateAccount(expectedId)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("expected to get existing account after creation, failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
if account.Id != expectedId {
|
|
||||||
t.Fatalf("expected to create an account, got wrong account")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAccountManager_AccountExists(t *testing.T) {
|
func TestAccountManager_AccountExists(t *testing.T) {
|
||||||
manager, err := createManager(t)
|
manager, err := createManager(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -93,7 +78,8 @@ func TestAccountManager_AccountExists(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expectedId := "test_account"
|
expectedId := "test_account"
|
||||||
_, err = manager.AddAccount(expectedId)
|
userId := "account_creator"
|
||||||
|
_, err = manager.AddAccount(expectedId, userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -117,7 +103,8 @@ func TestAccountManager_GetAccount(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expectedId := "test_account"
|
expectedId := "test_account"
|
||||||
account, err := manager.AddAccount(expectedId)
|
userId := "account_creator"
|
||||||
|
account, err := manager.AddAccount(expectedId, userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -154,7 +141,7 @@ func TestAccountManager_AddPeer(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
account, err := manager.AddAccount("test_account")
|
account, err := manager.AddAccount("test_account", "account_creator")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ type FileStore struct {
|
|||||||
Accounts map[string]*Account
|
Accounts map[string]*Account
|
||||||
SetupKeyId2AccountId map[string]string `json:"-"`
|
SetupKeyId2AccountId map[string]string `json:"-"`
|
||||||
PeerKeyId2AccountId map[string]string `json:"-"`
|
PeerKeyId2AccountId map[string]string `json:"-"`
|
||||||
|
UserId2AccountId map[string]string `json:"-"`
|
||||||
|
|
||||||
// mutex to synchronise Store read/write operations
|
// mutex to synchronise Store read/write operations
|
||||||
mux sync.Mutex `json:"-"`
|
mux sync.Mutex `json:"-"`
|
||||||
@@ -45,6 +46,7 @@ func restore(file string) (*FileStore, error) {
|
|||||||
mux: sync.Mutex{},
|
mux: sync.Mutex{},
|
||||||
SetupKeyId2AccountId: make(map[string]string),
|
SetupKeyId2AccountId: make(map[string]string),
|
||||||
PeerKeyId2AccountId: make(map[string]string),
|
PeerKeyId2AccountId: make(map[string]string),
|
||||||
|
UserId2AccountId: make(map[string]string),
|
||||||
storeFile: file,
|
storeFile: file,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +67,7 @@ func restore(file string) (*FileStore, error) {
|
|||||||
store.storeFile = file
|
store.storeFile = file
|
||||||
store.SetupKeyId2AccountId = make(map[string]string)
|
store.SetupKeyId2AccountId = make(map[string]string)
|
||||||
store.PeerKeyId2AccountId = make(map[string]string)
|
store.PeerKeyId2AccountId = make(map[string]string)
|
||||||
|
store.UserId2AccountId = make(map[string]string)
|
||||||
for accountId, account := range store.Accounts {
|
for accountId, account := range store.Accounts {
|
||||||
for setupKeyId := range account.SetupKeys {
|
for setupKeyId := range account.SetupKeys {
|
||||||
store.SetupKeyId2AccountId[strings.ToUpper(setupKeyId)] = accountId
|
store.SetupKeyId2AccountId[strings.ToUpper(setupKeyId)] = accountId
|
||||||
@@ -72,6 +75,9 @@ func restore(file string) (*FileStore, error) {
|
|||||||
for _, peer := range account.Peers {
|
for _, peer := range account.Peers {
|
||||||
store.PeerKeyId2AccountId[peer.Key] = accountId
|
store.PeerKeyId2AccountId[peer.Key] = accountId
|
||||||
}
|
}
|
||||||
|
for _, user := range account.Users {
|
||||||
|
store.UserId2AccountId[user.Id] = accountId
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return store, nil
|
return store, nil
|
||||||
@@ -168,6 +174,10 @@ func (s *FileStore) SaveAccount(account *Account) error {
|
|||||||
s.PeerKeyId2AccountId[peer.Key] = account.Id
|
s.PeerKeyId2AccountId[peer.Key] = account.Id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, user := range account.Users {
|
||||||
|
s.UserId2AccountId[user.Id] = account.Id
|
||||||
|
}
|
||||||
|
|
||||||
err := s.persist(s.storeFile)
|
err := s.persist(s.storeFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -217,6 +227,18 @@ func (s *FileStore) GetAccount(accountId string) (*Account, error) {
|
|||||||
return account, nil
|
return account, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *FileStore) GetUserAccount(userId string) (*Account, error) {
|
||||||
|
s.mux.Lock()
|
||||||
|
defer s.mux.Unlock()
|
||||||
|
|
||||||
|
accountId, accountIdFound := s.UserId2AccountId[userId]
|
||||||
|
if !accountIdFound {
|
||||||
|
return nil, status.Errorf(codes.NotFound, "account not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.GetAccount(accountId)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *FileStore) GetPeerAccount(peerKey string) (*Account, error) {
|
func (s *FileStore) GetPeerAccount(peerKey string) (*Account, error) {
|
||||||
s.mux.Lock()
|
s.mux.Lock()
|
||||||
defer s.mux.Unlock()
|
defer s.mux.Unlock()
|
||||||
|
|||||||
171
management/server/file_store_test.go
Normal file
171
management/server/file_store_test.go
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wiretrustee/wiretrustee/util"
|
||||||
|
"net"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewStore(t *testing.T) {
|
||||||
|
store := newStore(t)
|
||||||
|
|
||||||
|
if store.Accounts == nil || len(store.Accounts) != 0 {
|
||||||
|
t.Errorf("expected to create a new empty Accounts map when creating a new FileStore")
|
||||||
|
}
|
||||||
|
|
||||||
|
if store.SetupKeyId2AccountId == nil || len(store.SetupKeyId2AccountId) != 0 {
|
||||||
|
t.Errorf("expected to create a new empty SetupKeyId2AccountId map when creating a new FileStore")
|
||||||
|
}
|
||||||
|
|
||||||
|
if store.PeerKeyId2AccountId == nil || len(store.PeerKeyId2AccountId) != 0 {
|
||||||
|
t.Errorf("expected to create a new empty PeerKeyId2AccountId map when creating a new FileStore")
|
||||||
|
}
|
||||||
|
|
||||||
|
if store.UserId2AccountId == nil || len(store.UserId2AccountId) != 0 {
|
||||||
|
t.Errorf("expected to create a new empty UserId2AccountId map when creating a new FileStore")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSaveAccount(t *testing.T) {
|
||||||
|
store := newStore(t)
|
||||||
|
|
||||||
|
account, _ := newAccount("testuser")
|
||||||
|
account.Users["testuser"] = NewAdminUser("testuser")
|
||||||
|
setupKey := GenerateDefaultSetupKey()
|
||||||
|
account.SetupKeys[setupKey.Key] = setupKey
|
||||||
|
account.Peers["testpeer"] = &Peer{
|
||||||
|
Key: "peerkey",
|
||||||
|
SetupKey: "peerkeysetupkey",
|
||||||
|
IP: net.IP{127, 0, 0, 1},
|
||||||
|
Meta: PeerSystemMeta{},
|
||||||
|
Name: "peer name",
|
||||||
|
Status: &PeerStatus{Connected: true, LastSeen: time.Now()},
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveAccount should trigger persist
|
||||||
|
err := store.SaveAccount(account)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if store.Accounts[account.Id] == nil {
|
||||||
|
t.Errorf("expecting Account to be stored after SaveAccount()")
|
||||||
|
}
|
||||||
|
|
||||||
|
if store.PeerKeyId2AccountId["peerkey"] == "" {
|
||||||
|
t.Errorf("expecting PeerKeyId2AccountId index updated after SaveAccount()")
|
||||||
|
}
|
||||||
|
|
||||||
|
if store.UserId2AccountId["testuser"] == "" {
|
||||||
|
t.Errorf("expecting UserId2AccountId index updated after SaveAccount()")
|
||||||
|
}
|
||||||
|
|
||||||
|
if store.SetupKeyId2AccountId[setupKey.Key] == "" {
|
||||||
|
t.Errorf("expecting SetupKeyId2AccountId index updated after SaveAccount()")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStore(t *testing.T) {
|
||||||
|
store := newStore(t)
|
||||||
|
|
||||||
|
account, _ := newAccount("testuser")
|
||||||
|
account.Users["testuser"] = NewAdminUser("testuser")
|
||||||
|
account.Peers["testpeer"] = &Peer{
|
||||||
|
Key: "peerkey",
|
||||||
|
SetupKey: "peerkeysetupkey",
|
||||||
|
IP: net.IP{127, 0, 0, 1},
|
||||||
|
Meta: PeerSystemMeta{},
|
||||||
|
Name: "peer name",
|
||||||
|
Status: &PeerStatus{Connected: true, LastSeen: time.Now()},
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveAccount should trigger persist
|
||||||
|
err := store.SaveAccount(account)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
restored, err := NewStore(store.storeFile)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
restoredAccount := restored.Accounts[account.Id]
|
||||||
|
if restoredAccount == nil {
|
||||||
|
t.Errorf("failed to restore a FileStore file - missing Account %s", account.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if restoredAccount != nil && restoredAccount.Peers["testpeer"] == nil {
|
||||||
|
t.Errorf("failed to restore a FileStore file - missing Peer testpeer")
|
||||||
|
}
|
||||||
|
|
||||||
|
if restoredAccount != nil && restoredAccount.CreatedBy != "testuser" {
|
||||||
|
t.Errorf("failed to restore a FileStore file - missing Account CreatedBy")
|
||||||
|
}
|
||||||
|
|
||||||
|
if restoredAccount != nil && restoredAccount.Users["testuser"] == nil {
|
||||||
|
t.Errorf("failed to restore a FileStore file - missing User testuser")
|
||||||
|
}
|
||||||
|
|
||||||
|
if restoredAccount != nil && restoredAccount.Network == nil {
|
||||||
|
t.Errorf("failed to restore a FileStore file - missing Network")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRestore(t *testing.T) {
|
||||||
|
storeDir := t.TempDir()
|
||||||
|
|
||||||
|
err := util.CopyFileContents("testdata/store.json", filepath.Join(storeDir, "store.json"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
store, err := NewStore(storeDir)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
account := store.Accounts["bf1c8084-ba50-4ce7-9439-34653001fc3b"]
|
||||||
|
if account == nil {
|
||||||
|
t.Errorf("failed to restore a FileStore file - missing account bf1c8084-ba50-4ce7-9439-34653001fc3b")
|
||||||
|
}
|
||||||
|
|
||||||
|
if account != nil && account.Users["edafee4e-63fb-11ec-90d6-0242ac120003"] == nil {
|
||||||
|
t.Errorf("failed to restore a FileStore file - missing Account User edafee4e-63fb-11ec-90d6-0242ac120003")
|
||||||
|
}
|
||||||
|
|
||||||
|
if account != nil && account.Users["f4f6d672-63fb-11ec-90d6-0242ac120003"] == nil {
|
||||||
|
t.Errorf("failed to restore a FileStore file - missing Account User f4f6d672-63fb-11ec-90d6-0242ac120003")
|
||||||
|
}
|
||||||
|
|
||||||
|
if account != nil && account.Network == nil {
|
||||||
|
t.Errorf("failed to restore a FileStore file - missing Account Network")
|
||||||
|
}
|
||||||
|
|
||||||
|
if account != nil && account.SetupKeys["A2C8E62B-38F5-4553-B31E-DD66C696CEBB"] == nil {
|
||||||
|
t.Errorf("failed to restore a FileStore file - missing Account SetupKey A2C8E62B-38F5-4553-B31E-DD66C696CEBB")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(store.UserId2AccountId) != 2 {
|
||||||
|
t.Errorf("failed to restore a FileStore wrong UserId2AccountId mapping")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(store.SetupKeyId2AccountId) != 1 {
|
||||||
|
t.Errorf("failed to restore a FileStore wrong SetupKeyId2AccountId mapping")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func newStore(t *testing.T) *FileStore {
|
||||||
|
store, err := NewStore(t.TempDir())
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed creating a new store")
|
||||||
|
}
|
||||||
|
|
||||||
|
return store
|
||||||
|
}
|
||||||
@@ -62,7 +62,13 @@ func (h *Peers) deletePeer(accountId string, peer *server.Peer, w http.ResponseW
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Peers) HandlePeer(w http.ResponseWriter, r *http.Request) {
|
func (h *Peers) HandlePeer(w http.ResponseWriter, r *http.Request) {
|
||||||
accountId := extractAccountIdFromRequestContext(r)
|
userId := extractUserIdFromRequestContext(r)
|
||||||
|
account, err := h.accountManager.GetOrCreateAccountByUser(userId)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed getting account of a user %s: %v", userId, err)
|
||||||
|
http.Redirect(w, r, "/", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
peerId := vars["id"] //effectively peer IP address
|
peerId := vars["id"] //effectively peer IP address
|
||||||
if len(peerId) == 0 {
|
if len(peerId) == 0 {
|
||||||
@@ -70,7 +76,7 @@ func (h *Peers) HandlePeer(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
peer, err := h.accountManager.GetPeerByIP(accountId, peerId)
|
peer, err := h.accountManager.GetPeerByIP(account.Id, peerId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "peer not found", http.StatusNotFound)
|
http.Error(w, "peer not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
@@ -78,10 +84,10 @@ func (h *Peers) HandlePeer(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case http.MethodDelete:
|
case http.MethodDelete:
|
||||||
h.deletePeer(accountId, peer, w, r)
|
h.deletePeer(account.Id, peer, w, r)
|
||||||
return
|
return
|
||||||
case http.MethodPut:
|
case http.MethodPut:
|
||||||
h.updatePeer(accountId, peer, w, r)
|
h.updatePeer(account.Id, peer, w, r)
|
||||||
return
|
return
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
writeJSONObject(w, toPeerResponse(peer))
|
writeJSONObject(w, toPeerResponse(peer))
|
||||||
@@ -96,11 +102,11 @@ func (h *Peers) HandlePeer(w http.ResponseWriter, r *http.Request) {
|
|||||||
func (h *Peers) GetPeers(w http.ResponseWriter, r *http.Request) {
|
func (h *Peers) GetPeers(w http.ResponseWriter, r *http.Request) {
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
accountId := extractAccountIdFromRequestContext(r)
|
userId := extractUserIdFromRequestContext(r)
|
||||||
//new user -> create a new account
|
//new user -> create a new account
|
||||||
account, err := h.accountManager.GetOrCreateAccount(accountId)
|
account, err := h.accountManager.GetOrCreateAccountByUser(userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed getting user account %s: %v", accountId, err)
|
log.Errorf("failed getting account of a user %s: %v", userId, err)
|
||||||
http.Redirect(w, r, "/", http.StatusInternalServerError)
|
http.Redirect(w, r, "/", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,14 @@ func (h *SetupKeys) createKey(accountId string, w http.ResponseWriter, r *http.R
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *SetupKeys) HandleKey(w http.ResponseWriter, r *http.Request) {
|
func (h *SetupKeys) HandleKey(w http.ResponseWriter, r *http.Request) {
|
||||||
accountId := extractAccountIdFromRequestContext(r)
|
userId := extractUserIdFromRequestContext(r)
|
||||||
|
account, err := h.accountManager.GetOrCreateAccountByUser(userId)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed getting account of a user %s: %v", userId, err)
|
||||||
|
http.Redirect(w, r, "/", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
keyId := vars["id"]
|
keyId := vars["id"]
|
||||||
if len(keyId) == 0 {
|
if len(keyId) == 0 {
|
||||||
@@ -128,10 +135,10 @@ func (h *SetupKeys) HandleKey(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case http.MethodPut:
|
case http.MethodPut:
|
||||||
h.updateKey(accountId, keyId, w, r)
|
h.updateKey(account.Id, keyId, w, r)
|
||||||
return
|
return
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
h.getKey(accountId, keyId, w, r)
|
h.getKey(account.Id, keyId, w, r)
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
http.Error(w, "", http.StatusNotFound)
|
http.Error(w, "", http.StatusNotFound)
|
||||||
@@ -140,21 +147,20 @@ func (h *SetupKeys) HandleKey(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func (h *SetupKeys) GetKeys(w http.ResponseWriter, r *http.Request) {
|
func (h *SetupKeys) GetKeys(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
accountId := extractAccountIdFromRequestContext(r)
|
userId := extractUserIdFromRequestContext(r)
|
||||||
|
|
||||||
switch r.Method {
|
|
||||||
case http.MethodPost:
|
|
||||||
h.createKey(accountId, w, r)
|
|
||||||
return
|
|
||||||
case http.MethodGet:
|
|
||||||
|
|
||||||
//new user -> create a new account
|
//new user -> create a new account
|
||||||
account, err := h.accountManager.GetOrCreateAccount(accountId)
|
account, err := h.accountManager.GetOrCreateAccountByUser(userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed getting user account %s: %v", accountId, err)
|
log.Errorf("failed getting account of a user %s: %v", userId, err)
|
||||||
http.Redirect(w, r, "/", http.StatusInternalServerError)
|
http.Redirect(w, r, "/", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodPost:
|
||||||
|
h.createKey(account.Id, w, r)
|
||||||
|
return
|
||||||
|
case http.MethodGet:
|
||||||
w.WriteHeader(200)
|
w.WriteHeader(200)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
@@ -165,7 +171,7 @@ func (h *SetupKeys) GetKeys(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
err = json.NewEncoder(w).Encode(respBody)
|
err = json.NewEncoder(w).Encode(respBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed encoding account peers %s: %v", accountId, err)
|
log.Errorf("failed encoding account peers %s: %v", account.Id, err)
|
||||||
http.Redirect(w, r, "/", http.StatusInternalServerError)
|
http.Redirect(w, r, "/", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// extractAccountIdFromRequestContext extracts accountId from the request context previously filled by the JWT token (after auth)
|
// extractUserIdFromRequestContext extracts accountId from the request context previously filled by the JWT token (after auth)
|
||||||
func extractAccountIdFromRequestContext(r *http.Request) string {
|
func extractUserIdFromRequestContext(r *http.Request) string {
|
||||||
token := r.Context().Value("user").(*jwt.Token)
|
token := r.Context().Value("user").(*jwt.Token)
|
||||||
claims := token.Claims.(jwt.MapClaims)
|
claims := token.Claims.(jwt.MapClaims)
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package server_test
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
server "github.com/wiretrustee/wiretrustee/management/server"
|
server "github.com/wiretrustee/wiretrustee/management/server"
|
||||||
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
@@ -472,7 +473,9 @@ func loginPeerWithValidSetupKey(serverPubKey wgtypes.Key, key wgtypes.Key, clien
|
|||||||
func createRawClient(addr string) (mgmtProto.ManagementServiceClient, *grpc.ClientConn) {
|
func createRawClient(addr string) (mgmtProto.ManagementServiceClient, *grpc.ClientConn) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
conn, err := grpc.DialContext(ctx, addr, grpc.WithInsecure(),
|
|
||||||
|
conn, err := grpc.DialContext(ctx, addr,
|
||||||
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||||
grpc.WithBlock(),
|
grpc.WithBlock(),
|
||||||
grpc.WithKeepaliveParams(keepalive.ClientParameters{
|
grpc.WithKeepaliveParams(keepalive.ClientParameters{
|
||||||
Time: 10 * time.Second,
|
Time: 10 * time.Second,
|
||||||
|
|||||||
13
management/server/migration/README.md
Normal file
13
management/server/migration/README.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
## Migration from Store v2 to Store v2
|
||||||
|
|
||||||
|
Previously Account.Id was an Auth0 user id.
|
||||||
|
Conversion moves user id to Account.CreatedBy and generates a new Account.Id using xid.
|
||||||
|
It also adds a User with id = old Account.Id with a role Admin.
|
||||||
|
|
||||||
|
To start a conversion simply run the command below providing your current Wiretrustee Management datadir (where store.json file is located)
|
||||||
|
and a new data directory location (where a converted store.js will be stored):
|
||||||
|
```shell
|
||||||
|
./migration --oldDir /var/wiretrustee/datadir --newDir /var/wiretrustee/newdatadir/
|
||||||
|
```
|
||||||
|
|
||||||
|
Afterwards you can run the Management service providing ```/var/wiretrustee/newdatadir/ ``` as a datadir.
|
||||||
56
management/server/migration/convert_accounts.go
Normal file
56
management/server/migration/convert_accounts.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"github.com/rs/xid"
|
||||||
|
"github.com/wiretrustee/wiretrustee/management/server"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
oldDir := flag.String("oldDir", "old store directory", "/var/wiretrustee/datadir")
|
||||||
|
newDir := flag.String("newDir", "new store directory", "/var/wiretrustee/newdatadir")
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
oldStore, err := server.NewStore(*oldDir)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
newStore, err := server.NewStore(*newDir)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = Convert(oldStore, newStore)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("successfully converted")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert converts old store ato a new store
|
||||||
|
// Previously Account.Id was an Auth0 user id
|
||||||
|
// Conversion moved user id to Account.CreatedBy and generated a new Account.Id using xid
|
||||||
|
// It also adds a User with id = old Account.Id with a role Admin
|
||||||
|
func Convert(oldStore *server.FileStore, newStore *server.FileStore) error {
|
||||||
|
for _, account := range oldStore.Accounts {
|
||||||
|
accountCopy := account.Copy()
|
||||||
|
accountCopy.Id = xid.New().String()
|
||||||
|
accountCopy.CreatedBy = account.Id
|
||||||
|
accountCopy.Users[account.Id] = &server.User{
|
||||||
|
Id: account.Id,
|
||||||
|
Role: server.UserRoleAdmin,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := newStore.SaveAccount(accountCopy)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
76
management/server/migration/convert_accounts_test.go
Normal file
76
management/server/migration/convert_accounts_test.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wiretrustee/wiretrustee/management/server"
|
||||||
|
"github.com/wiretrustee/wiretrustee/util"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConvertAccounts(t *testing.T) {
|
||||||
|
|
||||||
|
storeDir := t.TempDir()
|
||||||
|
|
||||||
|
err := util.CopyFileContents("../testdata/storev1.json", filepath.Join(storeDir, "store.json"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
store, err := server.NewStore(storeDir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
convertedStore, err := server.NewStore(filepath.Join(storeDir, "converted"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = Convert(store, convertedStore)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(store.Accounts) != len(convertedStore.Accounts) {
|
||||||
|
t.Errorf("expecting the same number of accounts after conversion")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, account := range store.Accounts {
|
||||||
|
convertedAccount, err := convertedStore.GetUserAccount(account.Id)
|
||||||
|
if err != nil || convertedAccount == nil {
|
||||||
|
t.Errorf("expecting Account %s to be converted", account.Id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if convertedAccount.CreatedBy != account.Id {
|
||||||
|
t.Errorf("expecting converted Account.CreatedBy field to be equal to the old Account.Id")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if convertedAccount.Id == account.Id {
|
||||||
|
t.Errorf("expecting converted Account.Id to be different from Account.Id")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(convertedAccount.Users) != 1 {
|
||||||
|
t.Errorf("expecting converted Account.Users to be of size 1")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
user := convertedAccount.Users[account.Id]
|
||||||
|
if user == nil {
|
||||||
|
t.Errorf("expecting to find a user in converted Account.Users")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if user.Role != server.UserRoleAdmin {
|
||||||
|
t.Errorf("expecting to find a user in converted Account.Users with a role Admin")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for peerId := range account.Peers {
|
||||||
|
convertedPeer := convertedAccount.Peers[peerId]
|
||||||
|
if convertedPeer == nil {
|
||||||
|
t.Errorf("expecting Account Peer of StoreV1 to be found in StoreV2")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -17,6 +17,14 @@ type Network struct {
|
|||||||
Dns string
|
Dns string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *Network) Copy() *Network {
|
||||||
|
return &Network{
|
||||||
|
Id: n.Id,
|
||||||
|
Net: n.Net,
|
||||||
|
Dns: n.Dns,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AllocatePeerIP pics an available IP from an net.IPNet.
|
// AllocatePeerIP pics an available IP from an net.IPNet.
|
||||||
// This method considers already taken IPs and reuses IPs if there are gaps in takenIps
|
// This method considers already taken IPs and reuses IPs if there are gaps in takenIps
|
||||||
// E.g. if ipNet=100.30.0.0/16 and takenIps=[100.30.0.1, 100.30.0.5] then the result would be 100.30.0.2
|
// E.g. if ipNet=100.30.0.0/16 and takenIps=[100.30.0.1, 100.30.0.5] then the result would be 100.30.0.2
|
||||||
|
|||||||
@@ -206,7 +206,6 @@ func (am *AccountManager) GetPeersForAPeer(peerKey string) ([]*Peer, error) {
|
|||||||
// Each Account has a list of pre-authorised SetupKey and if no Account has a given key err wit ha code codes.Unauthenticated
|
// Each Account has a list of pre-authorised SetupKey and if no Account has a given key err wit ha code codes.Unauthenticated
|
||||||
// will be returned, meaning the key is invalid
|
// will be returned, meaning the key is invalid
|
||||||
// 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).
|
// 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).
|
||||||
// If the specified setupKey is empty then a new Account will be created //todo remove this part
|
|
||||||
// The peer property is just a placeholder for the Peer properties to pass further
|
// The peer property is just a placeholder for the Peer properties to pass further
|
||||||
func (am *AccountManager) AddPeer(setupKey string, peer Peer) (*Peer, error) {
|
func (am *AccountManager) AddPeer(setupKey string, peer Peer) (*Peer, error) {
|
||||||
am.mux.Lock()
|
am.mux.Lock()
|
||||||
@@ -218,8 +217,8 @@ func (am *AccountManager) AddPeer(setupKey string, peer Peer) (*Peer, error) {
|
|||||||
var err error
|
var err error
|
||||||
var sk *SetupKey
|
var sk *SetupKey
|
||||||
if len(upperKey) == 0 {
|
if len(upperKey) == 0 {
|
||||||
// Empty setup key, create a new account for it.
|
// Empty setup key, fail
|
||||||
account, sk = newAccount()
|
return nil, status.Errorf(codes.InvalidArgument, "empty setupKey %s", setupKey)
|
||||||
} else {
|
} else {
|
||||||
account, err = am.Store.GetAccountBySetupKey(upperKey)
|
account, err = am.Store.GetAccountBySetupKey(upperKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ type Store interface {
|
|||||||
DeletePeer(accountId string, peerKey string) (*Peer, error)
|
DeletePeer(accountId string, peerKey string) (*Peer, error)
|
||||||
SavePeer(accountId string, peer *Peer) error
|
SavePeer(accountId string, peer *Peer) error
|
||||||
GetAccount(accountId string) (*Account, error)
|
GetAccount(accountId string) (*Account, error)
|
||||||
|
GetUserAccount(userId string) (*Account, error)
|
||||||
GetAccountPeers(accountId string) ([]*Peer, error)
|
GetAccountPeers(accountId string) ([]*Peer, error)
|
||||||
GetPeerAccount(peerKey string) (*Account, error)
|
GetPeerAccount(peerKey string) (*Account, error)
|
||||||
GetAccountBySetupKey(setupKey string) (*Account, error)
|
GetAccountBySetupKey(setupKey string) (*Account, error)
|
||||||
|
|||||||
12
management/server/testdata/store.json
vendored
12
management/server/testdata/store.json
vendored
@@ -22,7 +22,17 @@
|
|||||||
},
|
},
|
||||||
"Dns": null
|
"Dns": null
|
||||||
},
|
},
|
||||||
"Peers": {}
|
"Peers": {},
|
||||||
|
"Users": {
|
||||||
|
"edafee4e-63fb-11ec-90d6-0242ac120003": {
|
||||||
|
"Id": "edafee4e-63fb-11ec-90d6-0242ac120003",
|
||||||
|
"Role": "admin"
|
||||||
|
},
|
||||||
|
"f4f6d672-63fb-11ec-90d6-0242ac120003": {
|
||||||
|
"Id": "f4f6d672-63fb-11ec-90d6-0242ac120003",
|
||||||
|
"Role": "user"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
154
management/server/testdata/storev1.json
vendored
Normal file
154
management/server/testdata/storev1.json
vendored
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
{
|
||||||
|
"Accounts": {
|
||||||
|
"auth0|61bf82ddeab084006aa1bccd": {
|
||||||
|
"Id": "auth0|61bf82ddeab084006aa1bccd",
|
||||||
|
"SetupKeys": {
|
||||||
|
"1B2B50B0-B3E8-4B0C-A426-525EDB8481BD": {
|
||||||
|
"Id": "831727121",
|
||||||
|
"Key": "1B2B50B0-B3E8-4B0C-A426-525EDB8481BD",
|
||||||
|
"Name": "One-off key",
|
||||||
|
"Type": "one-off",
|
||||||
|
"CreatedAt": "2021-12-24T16:09:45.926075752+01:00",
|
||||||
|
"ExpiresAt": "2022-01-23T16:09:45.926075752+01:00",
|
||||||
|
"Revoked": false,
|
||||||
|
"UsedTimes": 1,
|
||||||
|
"LastUsed": "2021-12-24T16:12:45.763424077+01:00"
|
||||||
|
},
|
||||||
|
"EB51E9EB-A11F-4F6E-8E49-C982891B405A": {
|
||||||
|
"Id": "1769568301",
|
||||||
|
"Key": "EB51E9EB-A11F-4F6E-8E49-C982891B405A",
|
||||||
|
"Name": "Default key",
|
||||||
|
"Type": "reusable",
|
||||||
|
"CreatedAt": "2021-12-24T16:09:45.926073628+01:00",
|
||||||
|
"ExpiresAt": "2022-01-23T16:09:45.926073628+01:00",
|
||||||
|
"Revoked": false,
|
||||||
|
"UsedTimes": 1,
|
||||||
|
"LastUsed": "2021-12-24T16:13:06.236748538+01:00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Network": {
|
||||||
|
"Id": "a443c07a-5765-4a78-97fc-390d9c1d0e49",
|
||||||
|
"Net": {
|
||||||
|
"IP": "100.64.0.0",
|
||||||
|
"Mask": "/8AAAA=="
|
||||||
|
},
|
||||||
|
"Dns": ""
|
||||||
|
},
|
||||||
|
"Peers": {
|
||||||
|
"oMNaI8qWi0CyclSuwGR++SurxJyM3pQEiPEHwX8IREo=": {
|
||||||
|
"Key": "oMNaI8qWi0CyclSuwGR++SurxJyM3pQEiPEHwX8IREo=",
|
||||||
|
"SetupKey": "EB51E9EB-A11F-4F6E-8E49-C982891B405A",
|
||||||
|
"IP": "100.64.0.2",
|
||||||
|
"Meta": {
|
||||||
|
"Hostname": "braginini",
|
||||||
|
"GoOS": "linux",
|
||||||
|
"Kernel": "Linux",
|
||||||
|
"Core": "21.04",
|
||||||
|
"Platform": "x86_64",
|
||||||
|
"OS": "Ubuntu",
|
||||||
|
"WtVersion": ""
|
||||||
|
},
|
||||||
|
"Name": "braginini",
|
||||||
|
"Status": {
|
||||||
|
"LastSeen": "2021-12-24T16:13:11.244342541+01:00",
|
||||||
|
"Connected": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"xlx9/9D8+ibnRiIIB8nHGMxGOzxV17r8ShPHgi4aYSM=": {
|
||||||
|
"Key": "xlx9/9D8+ibnRiIIB8nHGMxGOzxV17r8ShPHgi4aYSM=",
|
||||||
|
"SetupKey": "1B2B50B0-B3E8-4B0C-A426-525EDB8481BD",
|
||||||
|
"IP": "100.64.0.1",
|
||||||
|
"Meta": {
|
||||||
|
"Hostname": "braginini",
|
||||||
|
"GoOS": "linux",
|
||||||
|
"Kernel": "Linux",
|
||||||
|
"Core": "21.04",
|
||||||
|
"Platform": "x86_64",
|
||||||
|
"OS": "Ubuntu",
|
||||||
|
"WtVersion": ""
|
||||||
|
},
|
||||||
|
"Name": "braginini",
|
||||||
|
"Status": {
|
||||||
|
"LastSeen": "2021-12-24T16:12:49.089339333+01:00",
|
||||||
|
"Connected": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"google-oauth2|103201118415301331038": {
|
||||||
|
"Id": "google-oauth2|103201118415301331038",
|
||||||
|
"SetupKeys": {
|
||||||
|
"5AFB60DB-61F2-4251-8E11-494847EE88E9": {
|
||||||
|
"Id": "2485964613",
|
||||||
|
"Key": "5AFB60DB-61F2-4251-8E11-494847EE88E9",
|
||||||
|
"Name": "Default key",
|
||||||
|
"Type": "reusable",
|
||||||
|
"CreatedAt": "2021-12-24T16:10:02.238476+01:00",
|
||||||
|
"ExpiresAt": "2022-01-23T16:10:02.238476+01:00",
|
||||||
|
"Revoked": false,
|
||||||
|
"UsedTimes": 1,
|
||||||
|
"LastUsed": "2021-12-24T16:12:05.994307717+01:00"
|
||||||
|
},
|
||||||
|
"A72E4DC2-00DE-4542-8A24-62945438104E": {
|
||||||
|
"Id": "3504804807",
|
||||||
|
"Key": "A72E4DC2-00DE-4542-8A24-62945438104E",
|
||||||
|
"Name": "One-off key",
|
||||||
|
"Type": "one-off",
|
||||||
|
"CreatedAt": "2021-12-24T16:10:02.238478209+01:00",
|
||||||
|
"ExpiresAt": "2022-01-23T16:10:02.238478209+01:00",
|
||||||
|
"Revoked": false,
|
||||||
|
"UsedTimes": 1,
|
||||||
|
"LastUsed": "2021-12-24T16:11:27.015741738+01:00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Network": {
|
||||||
|
"Id": "b6d0b152-364e-40c1-a8a1-fa7bcac2267f",
|
||||||
|
"Net": {
|
||||||
|
"IP": "100.64.0.0",
|
||||||
|
"Mask": "/8AAAA=="
|
||||||
|
},
|
||||||
|
"Dns": ""
|
||||||
|
},
|
||||||
|
"Peers": {
|
||||||
|
"6kjbmVq1hmucVzvBXo5OucY5OYv+jSsB1jUTLq291Dw=": {
|
||||||
|
"Key": "6kjbmVq1hmucVzvBXo5OucY5OYv+jSsB1jUTLq291Dw=",
|
||||||
|
"SetupKey": "5AFB60DB-61F2-4251-8E11-494847EE88E9",
|
||||||
|
"IP": "100.64.0.2",
|
||||||
|
"Meta": {
|
||||||
|
"Hostname": "braginini",
|
||||||
|
"GoOS": "linux",
|
||||||
|
"Kernel": "Linux",
|
||||||
|
"Core": "21.04",
|
||||||
|
"Platform": "x86_64",
|
||||||
|
"OS": "Ubuntu",
|
||||||
|
"WtVersion": ""
|
||||||
|
},
|
||||||
|
"Name": "braginini",
|
||||||
|
"Status": {
|
||||||
|
"LastSeen": "2021-12-24T16:12:05.994305438+01:00",
|
||||||
|
"Connected": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Ok+5QMdt/UjoktNOvicGYj+IX2g98p+0N2PJ3vJ45RI=": {
|
||||||
|
"Key": "Ok+5QMdt/UjoktNOvicGYj+IX2g98p+0N2PJ3vJ45RI=",
|
||||||
|
"SetupKey": "A72E4DC2-00DE-4542-8A24-62945438104E",
|
||||||
|
"IP": "100.64.0.1",
|
||||||
|
"Meta": {
|
||||||
|
"Hostname": "braginini",
|
||||||
|
"GoOS": "linux",
|
||||||
|
"Kernel": "Linux",
|
||||||
|
"Core": "21.04",
|
||||||
|
"Platform": "x86_64",
|
||||||
|
"OS": "Ubuntu",
|
||||||
|
"WtVersion": ""
|
||||||
|
},
|
||||||
|
"Name": "braginini",
|
||||||
|
"Status": {
|
||||||
|
"LastSeen": "2021-12-24T16:11:27.015739803+01:00",
|
||||||
|
"Connected": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
71
management/server/user.go
Normal file
71
management/server/user.go
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserRoleAdmin UserRole = "admin"
|
||||||
|
UserRoleUser UserRole = "user"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UserRole is the role of the User
|
||||||
|
type UserRole string
|
||||||
|
|
||||||
|
// User represents a user of the system
|
||||||
|
type User struct {
|
||||||
|
Id string
|
||||||
|
Role UserRole
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) Copy() *User {
|
||||||
|
return &User{
|
||||||
|
Id: u.Id,
|
||||||
|
Role: u.Role,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUser creates a new user
|
||||||
|
func NewUser(id string, role UserRole) *User {
|
||||||
|
return &User{
|
||||||
|
Id: id,
|
||||||
|
Role: role,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAdminUser creates a new user with role UserRoleAdmin
|
||||||
|
func NewAdminUser(id string) *User {
|
||||||
|
return NewUser(id, UserRoleAdmin)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOrCreateAccountByUser returns an existing account for a given user id or creates a new one if doesn't exist
|
||||||
|
func (am *AccountManager) GetOrCreateAccountByUser(userId string) (*Account, error) {
|
||||||
|
am.mux.Lock()
|
||||||
|
defer am.mux.Unlock()
|
||||||
|
|
||||||
|
account, err := am.Store.GetUserAccount(userId)
|
||||||
|
if err != nil {
|
||||||
|
if s, ok := status.FromError(err); ok && s.Code() == codes.NotFound {
|
||||||
|
account, _ = newAccount(userId)
|
||||||
|
account.Users[userId] = NewAdminUser(userId)
|
||||||
|
err = am.Store.SaveAccount(account)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "failed creating account")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// other error
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return account, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccountByUser returns an existing account for a given user id, NotFound if account couldn't be found
|
||||||
|
func (am *AccountManager) GetAccountByUser(userId string) (*Account, error) {
|
||||||
|
am.mux.Lock()
|
||||||
|
defer am.mux.Unlock()
|
||||||
|
|
||||||
|
return am.Store.GetUserAccount(userId)
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/connectivity"
|
"google.golang.org/grpc/connectivity"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
"google.golang.org/grpc/keepalive"
|
"google.golang.org/grpc/keepalive"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
@@ -56,7 +57,7 @@ func (c *Client) Close() error {
|
|||||||
// NewClient creates a new Signal client
|
// NewClient creates a new Signal client
|
||||||
func NewClient(ctx context.Context, addr string, key wgtypes.Key, tlsEnabled bool) (*Client, error) {
|
func NewClient(ctx context.Context, addr string, key wgtypes.Key, tlsEnabled bool) (*Client, error) {
|
||||||
|
|
||||||
transportOption := grpc.WithInsecure()
|
transportOption := grpc.WithTransportCredentials(insecure.NewCredentials())
|
||||||
|
|
||||||
if tlsEnabled {
|
if tlsEnabled {
|
||||||
transportOption = grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{}))
|
transportOption = grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{}))
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/wiretrustee/wiretrustee/signal/server"
|
"github.com/wiretrustee/wiretrustee/signal/server"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
"google.golang.org/grpc/keepalive"
|
"google.golang.org/grpc/keepalive"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
"net"
|
"net"
|
||||||
@@ -170,7 +171,8 @@ func createSignalClient(addr string, key wgtypes.Key) *Client {
|
|||||||
|
|
||||||
func createRawSignalClient(addr string) sigProto.SignalExchangeClient {
|
func createRawSignalClient(addr string) sigProto.SignalExchangeClient {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
conn, err := grpc.DialContext(ctx, addr, grpc.WithInsecure(),
|
conn, err := grpc.DialContext(ctx, addr,
|
||||||
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||||
grpc.WithBlock(),
|
grpc.WithBlock(),
|
||||||
grpc.WithKeepaliveParams(keepalive.ClientParameters{
|
grpc.WithKeepaliveParams(keepalive.ClientParameters{
|
||||||
Time: 3 * time.Second,
|
Time: 3 * time.Second,
|
||||||
|
|||||||
Reference in New Issue
Block a user