forked from safing/spn
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclient.go
158 lines (139 loc) · 4.18 KB
/
client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package captain
import (
"context"
"errors"
"fmt"
"time"
"github.com/safing/portbase/database"
"github.com/tevino/abool"
"github.com/safing/portbase/log"
"github.com/safing/portbase/notifications"
"github.com/safing/spn/access"
)
var (
bootstrapped = abool.New()
ready = abool.New()
spnTestPhaseStatusLinkButton = notifications.Action{
Text: "Test Phase Status",
Type: notifications.ActionTypeOpenURL,
Payload: "https://docs.safing.io/spn/broader-testing/status",
}
spnLoginButton = notifications.Action{
Text: "Login",
Type: notifications.ActionTypeOpenPage,
Payload: "spn",
}
spnOpenAccountWeb = notifications.Action{
Text: "Open account.safing.io",
Type: notifications.ActionTypeOpenURL,
Payload: "https://account.safing.io",
}
spnSettingsButton = notifications.Action{
Text: "Configure",
Type: notifications.ActionTypeOpenSetting,
Payload: ¬ifications.ActionTypeOpenSettingPayload{
Key: CfgOptionEnableSPNKey,
},
}
)
// ClientBootstrapping signifies if the SPN is currently bootstrapping and
// requires normal connectivity for download assets.
func ClientBootstrapping() bool {
return bootstrapped.IsNotSet()
}
// ClientReady signifies if the SPN client is fully ready to handle connections.
func ClientReady() bool {
return ready.IsSet()
}
func clientManager(ctx context.Context) error {
defer bootstrapped.UnSet()
defer resetSPNStatus(StatusDisabled)
module.Hint(
"spn:establishing-home-hub",
"Connecting to SPN...",
"Connecting to the SPN network is in progress.",
)
for {
err := preFlightCheck(ctx)
if err != nil {
log.Warningf("spn/captain: pre-flight check failed: %s", err)
} else {
bootstrapped.Set()
err = homeHubManager(ctx)
if err != nil {
log.Warningf("spn/captain: primary hub manager failed: %s", err)
}
}
// Try again after a short break.
select {
case <-ctx.Done():
module.Resolve("")
return nil
case <-time.After(1 * time.Second):
}
}
}
func preFlightCheck(ctx context.Context) error {
// Get SPN user.
user, err := access.GetUser()
if err != nil && !errors.Is(err, database.ErrNotFound) {
notifications.NotifyError(
"spn:failed-to-get-user",
"SPN Internal Error",
`Please restart Portmaster.`,
spnSettingsButton,
).AttachToModule(module)
resetSPNStatus(StatusFailed)
return fmt.Errorf("internal error: %w", err)
}
// Check if user is logged in.
if user == nil || !user.IsLoggedIn() {
notifications.NotifyWarn(
"spn:not-logged-in",
"SPN Login Required",
`Please log in with your SPN account.`,
spnLoginButton,
spnSettingsButton,
).AttachToModule(module)
resetSPNStatus(StatusFailed)
return access.ErrNotLoggedIn
}
// FIXME: When we are starting and the SPN module is faster online than the
// nameserver, then updating the account will fail as the DNS query is
// redirected to a closed port.
// We also can't add the nameserver as a module dependency, as the nameserver
// is not part of the server.
time.Sleep(1 * time.Second)
// Update account and get tokens.
err = access.UpdateAccount(nil, nil)
if err != nil {
if errors.Is(err, access.ErrMayNotUseSPN) {
notifications.NotifyError(
"spn:subscription-inactive",
"SPN Subscription Inactive",
`Your account is currently not subscribed to the SPN. Follow the instructions on account.safing.io to get started.`,
spnOpenAccountWeb,
spnSettingsButton,
).AttachToModule(module)
resetSPNStatus(StatusFailed)
return errors.New("user may not use SPN")
}
log.Errorf("captain: failed to update account in pre-flight: %s", err)
module.NewErrorMessage("pre-flight account update", err).Report()
// There was an error updating the account.
// Check if we have enough tokens to continue anyway.
regular, fallback := access.GetTokenAmount(access.ExpandAndConnectZones)
if regular == 0 && fallback == 0 {
notifications.NotifyError(
"spn:tokens-exhausted",
"SPN Access Tokens Exhausted",
`The Portmaster failed to get new access tokens to access SPN. Please try again later.`,
spnSettingsButton,
).AttachToModule(module)
resetSPNStatus(StatusFailed)
return errors.New("access tokens exhausted")
}
}
// looking good so far!
return nil
}