Compare commits

..

1 Commits
v0.3.2 ... ebpf

Author SHA1 Message Date
braginini
b78ec082a3 ebpf test 2021-12-05 18:17:13 +01:00
28 changed files with 551 additions and 1323 deletions

View File

@@ -8,7 +8,7 @@ jobs:
test:
strategy:
matrix:
go-version: [1.17.x]
go-version: [1.16.x]
runs-on: ubuntu-latest
steps:
- name: Install Go
@@ -24,7 +24,7 @@ jobs:
strategy:
matrix:
os: [ windows, linux, darwin ]
go-version: [1.17.x]
go-version: [1.16.x]
runs-on: ubuntu-latest
steps:
- name: Checkout code

View File

@@ -18,7 +18,7 @@ jobs:
name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.17
go-version: 1.16
-
name: Cache Go modules
uses: actions/cache@v1

View File

@@ -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.**
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:**
* Centralized Peer IP management with a UI dashboard.
@@ -56,17 +56,14 @@ Hosted demo version:
### A bit on Wiretrustee internals
* Wiretrustee features a Management Service that offers peer IP management and network updates distribution (e.g. when a new peer joins the network).
* Wiretrustee features a Management Service that offers peer IP management and network updates distribution (e.g. when 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.
* Peers negotiate connection through [Signal Service](signal/).
* 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.
* 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.
<p float="left" align="middle">
<img src="https://docs.wiretrustee.com/img/architecture/high-level-dia.png" width="700"/>
</p>
* Occasionally, the NAT-traversal is unsuccessful due to strict NATs (e.g. mobile carrier-grade NAT).
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.
### Product Roadmap
- [Public Roadmap](https://github.com/wiretrustee/wiretrustee/projects/2)

36
ebpf/filter.go Normal file
View File

@@ -0,0 +1,36 @@
package main
import (
"github.com/cilium/ebpf"
"net"
"syscall"
)
// Filter represents a classic BPF filter program that can be applied to a socket
type Filter struct {
*ebpf.ProgramSpec
}
// ApplyTo applies the current filter onto the provided UDPConn
func (filter Filter) ApplyTo(conn *net.UDPConn) error {
file, err := conn.File()
if err != nil {
return err
}
p, err := ebpf.NewProgramWithOptions(filter.ProgramSpec, ebpf.ProgramOptions{
LogLevel: 6,
})
if err != nil {
return err
}
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.SOL_SOCKET, SO_ATTACH_BPF, p.FD()); err != nil {
return err
}
return nil
}

71
ebpf/main.go Normal file
View File

@@ -0,0 +1,71 @@
package main
import (
"encoding/hex"
"fmt"
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/asm"
"net"
)
const (
SO_ATTACH_BPF int = 50
StunMagicCookie uint32 = 0x2112A442
)
func main() {
// open a raw socket
/*fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_UDP)
if err != nil {
panic(err)
}
fmt.Print(fd)*/
addr := net.UDPAddr{
IP: net.IPv4zero,
Port: 12345,
}
conn, err := net.ListenUDP("udp4", &addr)
if err != nil {
return
}
filter := &Filter{
ProgramSpec: &ebpf.ProgramSpec{
Type: ebpf.SocketFilter,
License: "GPL",
Instructions: asm.Instructions{
asm.Mov.Reg(asm.R6, asm.R1), // LDABS requires ctx in R6
asm.LoadAbs(-0x100000+22, asm.Half),
asm.JNE.Imm(asm.R0, int32(addr.Port), "skip"),
/* asm.LoadAbs(-0x100000+32, asm.Word),
asm.JNE.Imm(asm.R0, int32(StunMagicCookie), "skip"),
asm.Mov.Imm(asm.R0, -1).Sym("exit"),*/
/*asm.Return(),*/
asm.Mov.Imm(asm.R0, 0).Sym("skip"),
asm.Return(),
},
},
}
err = filter.ApplyTo(conn)
if err != nil {
panic(err)
}
fmt.Printf("start")
buf := make([]byte, 1024)
for {
n, ra, err := conn.ReadFrom(buf)
if err != nil {
panic(err)
}
fmt.Printf("Bytes read: %d\n", n)
fmt.Printf("Remote Addr: %+v\n", ra)
fmt.Printf("Bytes HEX: %s\n", hex.EncodeToString(buf[:n]))
fmt.Printf("Bytes String: %s\n", string(buf[:n]))
fmt.Println()
}
}

186
ebpf/test/main.go Normal file
View File

@@ -0,0 +1,186 @@
package main
// This code is derived from https://github.com/cloudflare/cloudflare-blog/tree/master/2018-03-ebpf
//
// Copyright (c) 2015-2017 Cloudflare, Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of the Cloudflare, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import (
"fmt"
"net"
"syscall"
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/asm"
)
// ExampleExtractDistance shows how to attach an eBPF socket filter to
// extract the network distance of an IP host.
func main() {
filter, TTLs, err := newDistanceFilter()
if err != nil {
panic(err)
}
defer filter.Close()
defer TTLs.Close()
// Attach filter before the call to connect()
dialer := net.Dialer{
Control: func(network, address string, c syscall.RawConn) (err error) {
const SO_ATTACH_BPF = 50
err = c.Control(func(fd uintptr) {
err = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, SO_ATTACH_BPF, filter.FD())
})
return err
},
}
conn, err := dialer.Dial("tcp", "1.1.1.1:53")
if err != nil {
panic(err)
}
conn.Close()
minDist, err := minDistance(TTLs)
if err != nil {
panic(err)
}
fmt.Println("1.1.1.1:53 is", minDist, "hops away")
}
func newDistanceFilter() (*ebpf.Program, *ebpf.Map, error) {
const ETH_P_IPV6 uint16 = 0x86DD
ttls, err := ebpf.NewMap(&ebpf.MapSpec{
Type: ebpf.Hash,
KeySize: 4,
ValueSize: 8,
MaxEntries: 4,
})
if err != nil {
return nil, nil, err
}
insns := asm.Instructions{
// r1 has ctx
// r0 = ctx[16] (aka protocol)
asm.LoadMem(asm.R0, asm.R1, 16, asm.Word),
// Perhaps ipv6
asm.LoadImm(asm.R2, int64(ETH_P_IPV6), asm.DWord),
asm.HostTo(asm.BE, asm.R2, asm.Half),
asm.JEq.Reg(asm.R0, asm.R2, "ipv6"),
// otherwise assume ipv4
// 8th byte in IPv4 is TTL
// LDABS requires ctx in R6
asm.Mov.Reg(asm.R6, asm.R1),
asm.LoadAbs(-0x100000+8, asm.Byte),
asm.Ja.Label("store-ttl"),
// 7th byte in IPv6 is Hop count
// LDABS requires ctx in R6
asm.Mov.Reg(asm.R6, asm.R1).Sym("ipv6"),
asm.LoadAbs(-0x100000+7, asm.Byte),
// stash the load result into FP[-4]
asm.StoreMem(asm.RFP, -4, asm.R0, asm.Word).Sym("store-ttl"),
// stash the &FP[-4] into r2
asm.Mov.Reg(asm.R2, asm.RFP),
asm.Add.Imm(asm.R2, -4),
// r1 must point to map
asm.LoadMapPtr(asm.R1, ttls.FD()),
asm.FnMapLookupElem.Call(),
// load ok? inc. Otherwise? jmp to mapupdate
asm.JEq.Imm(asm.R0, 0, "update-map"),
asm.Mov.Imm(asm.R1, 1),
asm.StoreXAdd(asm.R0, asm.R1, asm.DWord),
asm.Ja.Label("exit"),
// MapUpdate
// r1 has map ptr
asm.LoadMapPtr(asm.R1, ttls.FD()).Sym("update-map"),
// r2 has key -> &FP[-4]
asm.Mov.Reg(asm.R2, asm.RFP),
asm.Add.Imm(asm.R2, -4),
// r3 has value -> &FP[-16] , aka 1
asm.StoreImm(asm.RFP, -16, 1, asm.DWord),
asm.Mov.Reg(asm.R3, asm.RFP),
asm.Add.Imm(asm.R3, -16),
// r4 has flags, 0
asm.Mov.Imm(asm.R4, 0),
asm.FnMapUpdateElem.Call(),
// set exit code to -1, don't trunc packet
asm.Mov.Imm(asm.R0, -1).Sym("exit"),
asm.Return(),
}
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
Name: "distance_filter",
Type: ebpf.SocketFilter,
License: "GPL",
Instructions: insns,
})
if err != nil {
ttls.Close()
return nil, nil, err
}
return prog, ttls, nil
}
func minDistance(TTLs *ebpf.Map) (int, error) {
var (
entries = TTLs.Iterate()
ttl uint32
minDist uint32 = 255
count uint64
)
for entries.Next(&ttl, &count) {
var dist uint32
switch {
case ttl > 128:
dist = 255 - ttl
case ttl > 64:
dist = 128 - ttl
case ttl > 32:
dist = 64 - ttl
default:
dist = 32 - ttl
}
if minDist > dist {
minDist = dist
}
}
return int(minDist), entries.Err()
}

69
go.mod
View File

@@ -1,62 +1,31 @@
module github.com/wiretrustee/wiretrustee
go 1.17
go 1.16
require (
github.com/cenkalti/backoff/v4 v4.1.2
github.com/cenkalti/backoff/v4 v4.1.0
github.com/cilium/ebpf v0.7.0
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/golang/protobuf v1.5.2
github.com/google/uuid v1.3.0
github.com/google/gopacket v1.1.19
github.com/google/uuid v1.2.0
github.com/gorilla/mux v1.8.0
github.com/kardianos/service v1.2.1-0.20210728001519-a323c3813bc7 //keep this version otherwise wiretrustee up command breaks
github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.17.0
github.com/pion/ice/v2 v2.1.17
github.com/kardianos/service v1.2.1-0.20210728001519-a323c3813bc7
github.com/onsi/ginkgo v1.16.4
github.com/onsi/gomega v1.13.0
github.com/pion/ice/v2 v2.1.7
github.com/rs/cors v1.8.0
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.3.0
github.com/sirupsen/logrus v1.7.0
github.com/spf13/cobra v1.1.3
github.com/spf13/pflag v1.0.5
github.com/vishvananda/netlink v1.1.0
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
golang.zx2c4.com/wireguard v0.0.0-20211209221555-9c9e7e272434
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20211215182854-7a385b3431de
golang.zx2c4.com/wireguard/windows v0.5.1
google.golang.org/grpc v1.43.0
google.golang.org/protobuf v1.27.1
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34
golang.zx2c4.com/wireguard v0.0.0-20210805125648-3957e9b9dd19
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c
golang.zx2c4.com/wireguard/windows v0.4.5
google.golang.org/grpc v1.32.0
google.golang.org/protobuf v1.26.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
)

674
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,6 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/connectivity"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/keepalive"
"io"
"time"
@@ -29,7 +28,7 @@ type Client struct {
// NewClient creates a new client to Management service
func NewClient(ctx context.Context, addr string, ourPrivateKey wgtypes.Key, tlsEnabled bool) (*Client, error) {
transportOption := grpc.WithTransportCredentials(insecure.NewCredentials())
transportOption := grpc.WithInsecure()
if tlsEnabled {
transportOption = grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{}))

View File

@@ -2,7 +2,6 @@ package server
import (
"github.com/google/uuid"
"github.com/rs/xid"
log "github.com/sirupsen/logrus"
"github.com/wiretrustee/wiretrustee/util"
"google.golang.org/grpc/codes"
@@ -20,39 +19,10 @@ type AccountManager struct {
// Account represents a unique account of the system
type Account struct {
Id string
// User.Id it was created by
CreatedBy string
Id string
SetupKeys map[string]*SetupKey
Network *Network
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
@@ -155,6 +125,29 @@ func (am *AccountManager) GetAccount(accountId string) (*Account, error) {
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)
func (am *AccountManager) AccountExists(accountId string) (*bool, error) {
am.mux.Lock()
@@ -175,18 +168,18 @@ func (am *AccountManager) AccountExists(accountId string) (*bool, error) {
return &res, nil
}
// AddAccount generates a new Account with a provided accountId and userId, saves to the Store
func (am *AccountManager) AddAccount(accountId string, userId string) (*Account, error) {
// AddAccount generates a new Account with a provided accountId and saves to the Store
func (am *AccountManager) AddAccount(accountId string) (*Account, error) {
am.mux.Lock()
defer am.mux.Unlock()
return am.createAccount(accountId, userId)
return am.createAccount(accountId)
}
func (am *AccountManager) createAccount(accountId string, userId string) (*Account, error) {
account, _ := newAccountWithId(accountId, userId)
func (am *AccountManager) createAccount(accountId string) (*Account, error) {
account, _ := newAccountWithId(accountId)
err := am.Store.SaveAccount(account)
if err != nil {
@@ -197,7 +190,7 @@ func (am *AccountManager) createAccount(accountId string, userId string) (*Accou
}
// newAccountWithId creates a new Account with a default SetupKey (doesn't store in a Store) and provided id
func newAccountWithId(accountId string, userId string) (*Account, *SetupKey) {
func newAccountWithId(accountId string) (*Account, *SetupKey) {
log.Debugf("creating new account")
@@ -211,17 +204,16 @@ func newAccountWithId(accountId string, userId string) (*Account, *SetupKey) {
Net: net.IPNet{IP: net.ParseIP("100.64.0.0"), Mask: net.IPMask{255, 192, 0, 0}},
Dns: ""}
peers := make(map[string]*Peer)
users := make(map[string]*User)
log.Debugf("created new account %s with setup key %s", accountId, defaultKey.Key)
return &Account{Id: accountId, SetupKeys: setupKeys, Network: network, Peers: peers, Users: users, CreatedBy: userId}, defaultKey
return &Account{Id: accountId, SetupKeys: setupKeys, Network: network, Peers: peers}, defaultKey
}
// 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(userId string) (*Account, *SetupKey) {
accountId := xid.New().String()
return newAccountWithId(accountId, userId)
// newAccount creates a new Account with a default SetupKey (doesn't store in a Store)
func newAccount() (*Account, *SetupKey) {
accountId := uuid.New().String()
return newAccountWithId(accountId)
}
func getAccountSetupKeyById(acc *Account, keyId string) *SetupKey {

View File

@@ -2,36 +2,12 @@ package server
import (
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"net"
"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) {
manager, err := createManager(t)
if err != nil {
@@ -40,7 +16,6 @@ func TestAccountManager_AddAccount(t *testing.T) {
}
expectedId := "test_account"
userId := "account_creator"
expectedPeersSize := 0
expectedSetupKeysSize := 2
expectedNetwork := net.IPNet{
@@ -48,7 +23,7 @@ func TestAccountManager_AddAccount(t *testing.T) {
Mask: net.IPMask{255, 192, 0, 0},
}
account, err := manager.AddAccount(expectedId, userId)
account, err := manager.AddAccount(expectedId)
if err != nil {
t.Fatal(err)
}
@@ -70,6 +45,46 @@ 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) {
manager, err := createManager(t)
if err != nil {
@@ -78,8 +93,7 @@ func TestAccountManager_AccountExists(t *testing.T) {
}
expectedId := "test_account"
userId := "account_creator"
_, err = manager.AddAccount(expectedId, userId)
_, err = manager.AddAccount(expectedId)
if err != nil {
t.Fatal(err)
}
@@ -103,8 +117,7 @@ func TestAccountManager_GetAccount(t *testing.T) {
}
expectedId := "test_account"
userId := "account_creator"
account, err := manager.AddAccount(expectedId, userId)
account, err := manager.AddAccount(expectedId)
if err != nil {
t.Fatal(err)
}
@@ -141,7 +154,7 @@ func TestAccountManager_AddPeer(t *testing.T) {
return
}
account, err := manager.AddAccount("test_account", "account_creator")
account, err := manager.AddAccount("test_account")
if err != nil {
t.Fatal(err)
}

View File

@@ -20,7 +20,6 @@ type FileStore struct {
Accounts map[string]*Account
SetupKeyId2AccountId map[string]string `json:"-"`
PeerKeyId2AccountId map[string]string `json:"-"`
UserId2AccountId map[string]string `json:"-"`
// mutex to synchronise Store read/write operations
mux sync.Mutex `json:"-"`
@@ -46,7 +45,6 @@ func restore(file string) (*FileStore, error) {
mux: sync.Mutex{},
SetupKeyId2AccountId: make(map[string]string),
PeerKeyId2AccountId: make(map[string]string),
UserId2AccountId: make(map[string]string),
storeFile: file,
}
@@ -67,7 +65,6 @@ func restore(file string) (*FileStore, error) {
store.storeFile = file
store.SetupKeyId2AccountId = make(map[string]string)
store.PeerKeyId2AccountId = make(map[string]string)
store.UserId2AccountId = make(map[string]string)
for accountId, account := range store.Accounts {
for setupKeyId := range account.SetupKeys {
store.SetupKeyId2AccountId[strings.ToUpper(setupKeyId)] = accountId
@@ -75,9 +72,6 @@ func restore(file string) (*FileStore, error) {
for _, peer := range account.Peers {
store.PeerKeyId2AccountId[peer.Key] = accountId
}
for _, user := range account.Users {
store.UserId2AccountId[user.Id] = accountId
}
}
return store, nil
@@ -174,10 +168,6 @@ func (s *FileStore) SaveAccount(account *Account) error {
s.PeerKeyId2AccountId[peer.Key] = account.Id
}
for _, user := range account.Users {
s.UserId2AccountId[user.Id] = account.Id
}
err := s.persist(s.storeFile)
if err != nil {
return err
@@ -227,18 +217,6 @@ func (s *FileStore) GetAccount(accountId string) (*Account, error) {
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) {
s.mux.Lock()
defer s.mux.Unlock()

View File

@@ -1,171 +0,0 @@
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
}

View File

@@ -62,13 +62,7 @@ func (h *Peers) deletePeer(accountId string, peer *server.Peer, w http.ResponseW
}
func (h *Peers) HandlePeer(w http.ResponseWriter, r *http.Request) {
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
}
accountId := extractAccountIdFromRequestContext(r)
vars := mux.Vars(r)
peerId := vars["id"] //effectively peer IP address
if len(peerId) == 0 {
@@ -76,7 +70,7 @@ func (h *Peers) HandlePeer(w http.ResponseWriter, r *http.Request) {
return
}
peer, err := h.accountManager.GetPeerByIP(account.Id, peerId)
peer, err := h.accountManager.GetPeerByIP(accountId, peerId)
if err != nil {
http.Error(w, "peer not found", http.StatusNotFound)
return
@@ -84,10 +78,10 @@ func (h *Peers) HandlePeer(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodDelete:
h.deletePeer(account.Id, peer, w, r)
h.deletePeer(accountId, peer, w, r)
return
case http.MethodPut:
h.updatePeer(account.Id, peer, w, r)
h.updatePeer(accountId, peer, w, r)
return
case http.MethodGet:
writeJSONObject(w, toPeerResponse(peer))
@@ -102,11 +96,11 @@ func (h *Peers) HandlePeer(w http.ResponseWriter, r *http.Request) {
func (h *Peers) GetPeers(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
userId := extractUserIdFromRequestContext(r)
accountId := extractAccountIdFromRequestContext(r)
//new user -> create a new account
account, err := h.accountManager.GetOrCreateAccountByUser(userId)
account, err := h.accountManager.GetOrCreateAccount(accountId)
if err != nil {
log.Errorf("failed getting account of a user %s: %v", userId, err)
log.Errorf("failed getting user account %s: %v", accountId, err)
http.Redirect(w, r, "/", http.StatusInternalServerError)
return
}

View File

@@ -118,14 +118,7 @@ func (h *SetupKeys) createKey(accountId string, w http.ResponseWriter, r *http.R
}
func (h *SetupKeys) HandleKey(w http.ResponseWriter, r *http.Request) {
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
}
accountId := extractAccountIdFromRequestContext(r)
vars := mux.Vars(r)
keyId := vars["id"]
if len(keyId) == 0 {
@@ -135,10 +128,10 @@ func (h *SetupKeys) HandleKey(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodPut:
h.updateKey(account.Id, keyId, w, r)
h.updateKey(accountId, keyId, w, r)
return
case http.MethodGet:
h.getKey(account.Id, keyId, w, r)
h.getKey(accountId, keyId, w, r)
return
default:
http.Error(w, "", http.StatusNotFound)
@@ -147,20 +140,21 @@ func (h *SetupKeys) HandleKey(w http.ResponseWriter, r *http.Request) {
func (h *SetupKeys) GetKeys(w http.ResponseWriter, r *http.Request) {
userId := extractUserIdFromRequestContext(r)
//new user -> create a new account
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
}
accountId := extractAccountIdFromRequestContext(r)
switch r.Method {
case http.MethodPost:
h.createKey(account.Id, w, r)
h.createKey(accountId, w, r)
return
case http.MethodGet:
//new user -> create a new account
account, err := h.accountManager.GetOrCreateAccount(accountId)
if err != nil {
log.Errorf("failed getting user account %s: %v", accountId, err)
http.Redirect(w, r, "/", http.StatusInternalServerError)
return
}
w.WriteHeader(200)
w.Header().Set("Content-Type", "application/json")
@@ -171,7 +165,7 @@ func (h *SetupKeys) GetKeys(w http.ResponseWriter, r *http.Request) {
err = json.NewEncoder(w).Encode(respBody)
if err != nil {
log.Errorf("failed encoding account peers %s: %v", account.Id, err)
log.Errorf("failed encoding account peers %s: %v", accountId, err)
http.Redirect(w, r, "/", http.StatusInternalServerError)
return
}

View File

@@ -8,8 +8,8 @@ import (
"time"
)
// extractUserIdFromRequestContext extracts accountId from the request context previously filled by the JWT token (after auth)
func extractUserIdFromRequestContext(r *http.Request) string {
// extractAccountIdFromRequestContext extracts accountId from the request context previously filled by the JWT token (after auth)
func extractAccountIdFromRequestContext(r *http.Request) string {
token := r.Context().Value("user").(*jwt.Token)
claims := token.Claims.(jwt.MapClaims)

View File

@@ -3,7 +3,6 @@ package server_test
import (
"context"
server "github.com/wiretrustee/wiretrustee/management/server"
"google.golang.org/grpc/credentials/insecure"
"io/ioutil"
"math/rand"
"net"
@@ -473,9 +472,7 @@ func loginPeerWithValidSetupKey(serverPubKey wgtypes.Key, key wgtypes.Key, clien
func createRawClient(addr string) (mgmtProto.ManagementServiceClient, *grpc.ClientConn) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
conn, err := grpc.DialContext(ctx, addr,
grpc.WithTransportCredentials(insecure.NewCredentials()),
conn, err := grpc.DialContext(ctx, addr, grpc.WithInsecure(),
grpc.WithBlock(),
grpc.WithKeepaliveParams(keepalive.ClientParameters{
Time: 10 * time.Second,

View File

@@ -1,13 +0,0 @@
## 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.

View File

@@ -1,56 +0,0 @@
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
}

View File

@@ -1,76 +0,0 @@
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
}
}
}
}

View File

@@ -17,14 +17,6 @@ type Network struct {
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.
// 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

View File

@@ -206,6 +206,7 @@ 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
// 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).
// 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
func (am *AccountManager) AddPeer(setupKey string, peer Peer) (*Peer, error) {
am.mux.Lock()
@@ -217,8 +218,8 @@ func (am *AccountManager) AddPeer(setupKey string, peer Peer) (*Peer, error) {
var err error
var sk *SetupKey
if len(upperKey) == 0 {
// Empty setup key, fail
return nil, status.Errorf(codes.InvalidArgument, "empty setupKey %s", setupKey)
// Empty setup key, create a new account for it.
account, sk = newAccount()
} else {
account, err = am.Store.GetAccountBySetupKey(upperKey)
if err != nil {

View File

@@ -5,7 +5,6 @@ type Store interface {
DeletePeer(accountId string, peerKey string) (*Peer, error)
SavePeer(accountId string, peer *Peer) error
GetAccount(accountId string) (*Account, error)
GetUserAccount(userId string) (*Account, error)
GetAccountPeers(accountId string) ([]*Peer, error)
GetPeerAccount(peerKey string) (*Account, error)
GetAccountBySetupKey(setupKey string) (*Account, error)

View File

@@ -22,17 +22,7 @@
},
"Dns": null
},
"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"
}
}
"Peers": {}
}
}
}

View File

@@ -1,154 +0,0 @@
{
"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
}
}
}
}
}
}

View File

@@ -1,71 +0,0 @@
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)
}

View File

@@ -13,7 +13,6 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/connectivity"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/keepalive"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
@@ -57,7 +56,7 @@ func (c *Client) Close() error {
// NewClient creates a new Signal client
func NewClient(ctx context.Context, addr string, key wgtypes.Key, tlsEnabled bool) (*Client, error) {
transportOption := grpc.WithTransportCredentials(insecure.NewCredentials())
transportOption := grpc.WithInsecure()
if tlsEnabled {
transportOption = grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{}))

View File

@@ -9,7 +9,6 @@ import (
"github.com/wiretrustee/wiretrustee/signal/server"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/keepalive"
"google.golang.org/grpc/metadata"
"net"
@@ -171,8 +170,7 @@ func createSignalClient(addr string, key wgtypes.Key) *Client {
func createRawSignalClient(addr string) sigProto.SignalExchangeClient {
ctx := context.Background()
conn, err := grpc.DialContext(ctx, addr,
grpc.WithTransportCredentials(insecure.NewCredentials()),
conn, err := grpc.DialContext(ctx, addr, grpc.WithInsecure(),
grpc.WithBlock(),
grpc.WithKeepaliveParams(keepalive.ClientParameters{
Time: 3 * time.Second,