Skip to content

Commit 7324d67

Browse files
committed
ipn/yegor: managed perma creds
1 parent 5c9b1f3 commit 7324d67

1 file changed

Lines changed: 62 additions & 9 deletions

File tree

intra/ipn/rpn/yegor.go

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,13 @@ const (
117117
wsMaxPermaWgKeys = 5
118118

119119
disablePermaCreds = true
120+
121+
// managedPermaCreds selects a server-managed keypair strategy for permanent creds.
122+
// When true, the keypair is generated entirely by the server (no local key-gen and no
123+
// /WgConfigs/init call). The server-generated keypair is always returned by
124+
// /WgConfigs/list_keys, so liveness can be checked without any /init round-trip.
125+
// When false (default), the existing locally-generated key + /init + /permanent flow is used.
126+
managedPermaCreds = false
120127
)
121128

122129
// github.com/Windscribe/Android-App/blob/746d505dc69/base/src/main/java/com/windscribe/vpn/constants/NetworkErrorCodes.kt
@@ -1509,10 +1516,13 @@ func getServerList(h *http.Client, sess *WsSession, ent *WsEntitlement) (*WsServ
15091516

15101517
// initAndConnectCreds registers creds via /WgConfigs/init and then either:
15111518
// - dynamic creds (perma=false): reserves a WireGuard interface via /WgConfigs/connect.
1512-
// - perma creds (perma=true): registers the init'd pubkey via /WgConfigs/permanent.
1519+
// - perma creds (perma=true, managedPermaCreds=false): registers the init'd pubkey via
1520+
// /WgConfigs/permanent. The keypair is generated locally; /WgConfigs/init is required.
1521+
// - managed perma creds (perma=true, managedPermaCreds=true): delegates entirely to
1522+
// managedPermaCredsFn; no local key-gen and no /WgConfigs/init call is performed.
15131523
//
1514-
// For perma=true, if existingCreds is non-nil and its pubkey is still present in
1515-
// /WgConfigs/list_keys, existingCreds is returned as-is (no /init or /permanent needed).
1524+
// For perma=true (non-managed), if existingCreds is non-nil and its pubkey is still present
1525+
// in /WgConfigs/list_keys, existingCreds is returned as-is (no /init or /permanent needed).
15161526
// If the key is no longer listed, a fresh /init + /permanent cycle is performed.
15171527
// The /init error handling is identical for both dynamic and perma paths.
15181528
func initAndConnectCreds(h *http.Client, existingCreds *WsWgCreds, perma bool, sess *WsSession, ent *WsEntitlement, forceInit bool) (*WsWgCreds, error) {
@@ -1535,6 +1545,12 @@ func initAndConnectCreds(h *http.Client, existingCreds *WsWgCreds, perma bool, s
15351545
return nil, nil // perma creds disabled; no API calls, no error
15361546
}
15371547

1548+
// Managed perma creds: server generates both priv+pub; no /init call required.
1549+
// list_keys always includes remotely-generated keys, so liveness is cheap to verify.
1550+
if perma && managedPermaCreds {
1551+
return managedPermaCredsFn(h, existingCreds, ent, bearer)
1552+
}
1553+
15381554
force := "0" // 0 when forced registration (which deletes older keys) is not needed
15391555

15401556
// For perma creds, check whether the existing pubkey is still registered on the server.
@@ -2123,6 +2139,43 @@ func listKeys(h *http.Client, ent *WsEntitlement, bearer string) (*WsWgListKeysR
21232139
return &out, nil
21242140
}
21252141

2142+
// managedPermaCredsFn implements the managed-perma-creds flow (managedPermaCreds=true).
2143+
// The server generates both the private and public key; no /WgConfigs/init is needed.
2144+
// If existingCreds are still present in /WgConfigs/list_keys they are reused directly.
2145+
// Otherwise /WgConfigs/permanent is called without a pubkey so the server creates a fresh
2146+
// keypair. Remotely-generated keypairs are always included in subsequent list_keys responses.
2147+
func managedPermaCredsFn(h *http.Client, existingCreds *WsWgPermanentConfig, ent *WsEntitlement, bearer string) (*WsWgPermanentConfig, error) {
2148+
if len(bearer) <= 0 {
2149+
return nil, errWsNoToken
2150+
}
2151+
tokst := tokenState(bearer)
2152+
2153+
// If we already have remotely-generated creds, verify they are still active.
2154+
if existingCreds != nil && len(existingCreds.PublicKey) > 0 {
2155+
for range 2 {
2156+
keys, kerr := listKeys(h, ent, bearer)
2157+
if kerr != nil || keys == nil {
2158+
log.E("ws: wgconfs: perma(managed): list keys err (nil? %t / tok? %s): %v", keys == nil, tokst, kerr)
2159+
wsBriefPauseBeforeRetry()
2160+
continue
2161+
}
2162+
for _, k := range keys.Data.PubKeys {
2163+
if k == existingCreds.PublicKey {
2164+
log.I("ws: wgconfs: perma(managed): existing key %s active (%s); reusing", trunc8(existingCreds.PublicKey), tokst)
2165+
return existingCreds, nil
2166+
}
2167+
}
2168+
// key not found in list; fall through to generate a new remote keypair
2169+
log.I("ws: wgconfs: perma(managed): existing key %s missing from list_keys (%s); regenerating", trunc8(existingCreds.PublicKey), tokst)
2170+
break
2171+
}
2172+
}
2173+
2174+
// Let the server generate both the private and public keys.
2175+
// No pubkey is supplied; the returned creds include PrivateKey from the server.
2176+
return createPermaCreds(h, ent, bearer, "" /*no pubkey: server generates keypair*/)
2177+
}
2178+
21262179
// createPermaCreds calls POST WgConfigs/permanent to create a permanent WG config.
21272180
// If pubkey is empty the server generates both the private and public keys.
21282181
func createPermaCreds(h *http.Client, ent *WsEntitlement, bearer, pubkey string) (*WsWgPermanentConfig, error) {
@@ -2131,7 +2184,7 @@ func createPermaCreds(h *http.Client, ent *WsEntitlement, bearer, pubkey string)
21312184
}
21322185
port := wsRandomPort() // some port; doesn't matter which one
21332186
tokst := tokenState(bearer)
2134-
2187+
managed := len(pubkey) <= 0
21352188
// curl --location --request POST '.../WgConfigs/permanent' \
21362189
// --header 'Authorization: Bearer <token>' \
21372190
// --data-urlencode 'port=443' \
@@ -2145,19 +2198,19 @@ func createPermaCreds(h *http.Client, ent *WsEntitlement, bearer, pubkey string)
21452198
u := baseurl(ent.TestDomain, ent.Cid, ent.Did).JoinPath(wswgpermanentpath)
21462199
req, err := http.NewRequest("POST", u.String(), strings.NewReader(data.Encode()))
21472200
if err != nil {
2148-
return nil, log.EE("ws: conf: perma: req err: %v", err)
2201+
return nil, log.EE("ws: conf: perma: (m? %t) req err: %v", managed, err)
21492202
}
21502203
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
21512204
authHeader(req, bearer)
21522205
didHeader(req, ent.DidToken)
21532206

21542207
if settings.Debug {
2155-
log.V("ws: conf: perma: req: %s tok %s; port %s", u.String(), tokst, port)
2208+
log.V("ws: conf: perma: (m? %t) req: %s tok %s; port %s", managed, u.String(), tokst, port)
21562209
}
21572210

21582211
res, err := h.Do(req)
21592212
if err != nil || res == nil {
2160-
return nil, log.EE("ws: conf: perma: do err (nil? %t / tok? %s): %v", res == nil, tokst, err)
2213+
return nil, log.EE("ws: conf: perma: (m? %t) do err (nil? %t / tok? %s): %v", managed, res == nil, tokst, err)
21612214
}
21622215
defer core.Close(res.Body)
21632216
updateDidTokenIfNeeded(ent, res)
@@ -2171,11 +2224,11 @@ func createPermaCreds(h *http.Client, ent *WsEntitlement, bearer, pubkey string)
21712224
return nil, err
21722225
}
21732226
if out.Data.Success != 1 {
2174-
return nil, log.EE("ws: conf: perma: success != 1; tok? %s; debug: %v", tokst, out.Data.Debug)
2227+
return nil, log.EE("ws: conf: perma: (m? %t) success != 1; tok? %s; debug: %v", managed, tokst, out.Data.Debug)
21752228
}
21762229

21772230
cfg := out.Data.Config
2178-
log.I("ws: conf: perma: ok (tok? %s); pubkey: %s", tokst, trunc8(cfg.PublicKey))
2231+
log.I("ws: conf: perma: ok (m? %t / tok? %s); pubkey: %s", managed, tokst, trunc8(cfg.PublicKey))
21792232
return &cfg, nil
21802233
}
21812234

0 commit comments

Comments
 (0)