Documentation
¶
Index ¶
- Constants
- func CountryList(servers []LogicalServer) []string
- func GroupServersByCountry(servers []LogicalServer) map[string][]LogicalServer
- func IsAuthError(err error) bool
- func Needs2FA(auth *AuthResponse) bool
- type APIError
- type Auth2FARequest
- type Auth2FAResponse
- type AuthInfoRequest
- type AuthInfoResponse
- type AuthRequest
- type AuthResponse
- type CertRefresher
- type CertificateFeatures
- type CertificateRequest
- type CertificateResponse
- type Client
- func (c *Client) BaseURL() string
- func (c *Client) GetClientConfig(ctx context.Context) (*ClientConfigResponse, error)
- func (c *Client) GetLocation(ctx context.Context) (*LocationResponse, error)
- func (c *Client) GetServerLoads(ctx context.Context) (*LogicalsResponse, error)
- func (c *Client) GetServers(ctx context.Context) (*LogicalsResponse, error)
- func (c *Client) GetSession() Session
- func (c *Client) GetSessions(ctx context.Context) (*SessionsResponse, error)
- func (c *Client) GetVPNInfo(ctx context.Context) (*VPNInfoResponse, error)
- func (c *Client) IsAuthenticated() bool
- func (c *Client) Login(ctx context.Context, username, password string) (*AuthResponse, error)
- func (c *Client) LoginEmail() string
- func (c *Client) Logout(ctx context.Context) error
- func (c *Client) PinnedAPIIPs() []string
- func (c *Client) RequestCert(ctx context.Context, kp *KeyPair, features CertificateFeatures) (*CertificateResponse, error)
- func (c *Client) RequestCertificate(ctx context.Context, req *CertificateRequest) (*CertificateResponse, error)
- func (c *Client) SetPinnedAPIIPs(ips []string)
- func (c *Client) SetSession(uid, accessToken, refreshToken string)
- func (c *Client) Submit2FA(ctx context.Context, code string) error
- type ClientConfigResponse
- type DefaultPorts
- type FeatureFlags
- type KeyPair
- type LocationResponse
- type LogicalServer
- func (s *LogicalServer) BestServer() *PhysicalServer
- func (s *LogicalServer) EffectiveTier() int
- func (s *LogicalServer) HasFeature(feature int) bool
- func (s *LogicalServer) IsOnline() bool
- func (s *LogicalServer) IsP2P() bool
- func (s *LogicalServer) IsSecureCore() bool
- func (s *LogicalServer) IsStreaming() bool
- func (s *LogicalServer) IsTor() bool
- type LogicalsResponse
- type PhysicalServer
- type ProtocolPorts
- type RefreshRequest
- type RefreshResponse
- type RequestError
- type ServerFilter
- type ServerLocation
- type Session
- type SessionStore
- type SessionsResponse
- type SmartProtocol
- type VPNInfo
- type VPNInfoResponse
- type VPNSession
Constants ¶
const ( DefaultBaseURL = "https://vpn-api.proton.me" AppVersion = "linux-vpn@4.13.1" UserAgent = "ProtonVPN/4.13.1 (Linux; go-pvpn)" DefaultTimeout = 30 * time.Second MaxRetries = 3 )
const ( ServerFeatureSecureCore = 1 ServerFeatureTor = 2 ServerFeatureP2P = 4 ServerFeatureStreaming = 8 ServerFeatureIPv6 = 16 )
Server feature bitmask
const ( ServerTierFree = 0 ServerTierBasic = 1 // Legacy, treat as Plus ServerTierPlus = 2 ServerTierVisionary = 3 )
Server tiers
Variables ¶
This section is empty.
Functions ¶
func CountryList ¶
func CountryList(servers []LogicalServer) []string
CountryList returns a sorted list of unique exit countries from the server list.
func GroupServersByCountry ¶
func GroupServersByCountry(servers []LogicalServer) map[string][]LogicalServer
GroupServersByCountry groups servers by their exit country.
func IsAuthError ¶ added in v0.1.7
IsAuthError checks whether an error represents a permanent auth failure. Returns false for network errors, timeouts, and other transient issues.
func Needs2FA ¶
func Needs2FA(auth *AuthResponse) bool
Needs2FA checks if the auth response requires 2FA to proceed.
Types ¶
type APIError ¶
type Auth2FARequest ¶
type Auth2FARequest struct {
TwoFactorCode string `json:"TwoFactorCode"`
}
type Auth2FAResponse ¶
type AuthInfoRequest ¶
type AuthInfoResponse ¶
type AuthInfoResponse struct {
Code int `json:"Code"`
Version int `json:"Version"`
Modulus string `json:"Modulus"`
ServerEphemeral string `json:"ServerEphemeral"`
Salt string `json:"Salt"`
SRPSession string `json:"SRPSession"`
TwoFA struct {
Enabled int `json:"Enabled"`
TOTP int `json:"TOTP"`
} `json:"2FA"`
}
type AuthRequest ¶
type AuthResponse ¶
type AuthResponse struct {
Code int `json:"Code"`
AccessToken string `json:"AccessToken"`
RefreshToken string `json:"RefreshToken"`
TokenType string `json:"TokenType"`
UID string `json:"UID"`
UserID string `json:"UserID"`
ServerProof string `json:"ServerProof"`
Scope string `json:"Scope"`
Scopes []string `json:"Scopes"`
ExpiresIn int `json:"ExpiresIn"`
TwoFA struct {
Enabled int `json:"Enabled"`
TOTP int `json:"TOTP"`
} `json:"2FA"`
}
type CertRefresher ¶
type CertRefresher struct {
// Called when a new certificate is obtained.
OnCertRefresh func(cert *CertificateResponse)
// contains filtered or unexported fields
}
CertRefresher manages automatic certificate rotation in the background.
func NewCertRefresher ¶
func NewCertRefresher(client *Client, kp *KeyPair, features CertificateFeatures) *CertRefresher
NewCertRefresher creates a new certificate refresher.
func (*CertRefresher) CurrentCert ¶
func (r *CertRefresher) CurrentCert() *CertificateResponse
CurrentCert returns the current certificate.
type CertificateFeatures ¶
type CertificateRequest ¶
type CertificateResponse ¶
type CertificateResponse struct {
Code int `json:"Code"`
SerialNumber string `json:"SerialNumber"`
ClientKeyFingerprint string `json:"ClientKeyFingerprint"`
ClientKey string `json:"ClientKey"`
Certificate string `json:"Certificate"`
ExpirationTime int64 `json:"ExpirationTime"`
RefreshTime int64 `json:"RefreshTime"`
Mode string `json:"Mode"`
DeviceName string `json:"DeviceName"`
ServerPublicKeyMode string `json:"ServerPublicKeyMode"`
ServerPublicKey string `json:"ServerPublicKey"`
}
func (*CertificateResponse) ExpiresAt ¶
func (c *CertificateResponse) ExpiresAt() time.Time
func (*CertificateResponse) RefreshAt ¶
func (c *CertificateResponse) RefreshAt() time.Time
type Client ¶
type Client struct {
// Called when tokens are rotated so the session can be persisted.
OnTokenRefresh func(uid, accessToken, refreshToken string)
// contains filtered or unexported fields
}
Client is the Proton VPN API client. It handles authenticated requests, automatic token refresh, and retry logic.
func NewClient ¶
NewClient creates a new API client. If session is non-nil, the client is initialized with existing auth tokens.
func (*Client) BaseURL ¶ added in v0.1.2
BaseURL returns the API base URL (needed for kill switch pinhole during reconnection).
func (*Client) GetClientConfig ¶
func (c *Client) GetClientConfig(ctx context.Context) (*ClientConfigResponse, error)
GetClientConfig returns the client configuration.
func (*Client) GetLocation ¶
func (c *Client) GetLocation(ctx context.Context) (*LocationResponse, error)
GetLocation returns the client's current IP and location.
func (*Client) GetServerLoads ¶
func (c *Client) GetServerLoads(ctx context.Context) (*LogicalsResponse, error)
GetServerLoads fetches just the server loads (lighter than full server list).
func (*Client) GetServers ¶
func (c *Client) GetServers(ctx context.Context) (*LogicalsResponse, error)
GetServers returns the full server list.
func (*Client) GetSession ¶
GetSession returns the current session tokens.
func (*Client) GetSessions ¶
func (c *Client) GetSessions(ctx context.Context) (*SessionsResponse, error)
GetSessions returns active VPN sessions.
func (*Client) GetVPNInfo ¶
func (c *Client) GetVPNInfo(ctx context.Context) (*VPNInfoResponse, error)
GetVPNInfo returns the VPN account info.
func (*Client) IsAuthenticated ¶
IsAuthenticated returns true if the client has auth tokens.
func (*Client) Login ¶
Login authenticates with the Proton API using SRP. Returns the auth response. If 2FA is required, the caller must call Submit2FA.
func (*Client) LoginEmail ¶
LoginEmail returns the email the user logged in with.
func (*Client) PinnedAPIIPs ¶ added in v0.2.1
PinnedAPIIPs returns a snapshot of the currently pinned IPs for the API hostname. Order matches the order given to SetPinnedAPIIPs.
func (*Client) RequestCert ¶
func (c *Client) RequestCert(ctx context.Context, kp *KeyPair, features CertificateFeatures) (*CertificateResponse, error)
RequestCert requests a VPN certificate from the API using the given key pair.
func (*Client) RequestCertificate ¶
func (c *Client) RequestCertificate(ctx context.Context, req *CertificateRequest) (*CertificateResponse, error)
RequestCertificate requests a new VPN certificate.
func (*Client) SetPinnedAPIIPs ¶ added in v0.2.1
SetPinnedAPIIPs installs a list of pre-resolved IP addresses for the Proton API hostname. Called by the daemon at startup after loading the cached IPs from disk, so the first API request after boot does not require DNS — which would be blocked by the pre-boot kill switch. Safe to call with an empty list (clears pinning).
func (*Client) SetSession ¶
SetSession updates the client's auth tokens.
type ClientConfigResponse ¶
type ClientConfigResponse struct {
Code int `json:"Code"`
DefaultPorts DefaultPorts `json:"DefaultPorts"`
HolesIPs []string `json:"HolesIPs"`
FeatureFlags FeatureFlags `json:"FeatureFlags"`
SmartProtocol SmartProtocol `json:"SmartProtocol"`
}
type DefaultPorts ¶
type DefaultPorts struct {
OpenVPN ProtocolPorts `json:"OpenVPN"`
WireGuard ProtocolPorts `json:"WireGuard"`
}
type FeatureFlags ¶
type KeyPair ¶
type KeyPair struct {
// Ed25519 key pair (used for API cert requests and Local Agent mTLS)
Ed25519 *ed25519.KeyPair
// X25519 private key in base64 (used as WireGuard private key)
WireGuardPrivateKey string
// Ed25519 public key in PEM format (sent to API)
PublicKeyPEM string
}
KeyPair holds the generated Ed25519/X25519 keys for VPN use.
func GenerateKeyPair ¶
GenerateKeyPair creates a new Ed25519 key pair and derives the X25519 WireGuard private key from it.
type LocationResponse ¶
type LogicalServer ¶
type LogicalServer struct {
ID string `json:"ID"`
Name string `json:"Name"`
EntryCountry string `json:"EntryCountry"`
ExitCountry string `json:"ExitCountry"`
Domain string `json:"Domain"`
Tier int `json:"Tier"`
Features int `json:"Features"`
Region string `json:"Region,omitempty"`
City string `json:"City,omitempty"`
Score float64 `json:"Score"`
Load int `json:"Load"`
Status int `json:"Status"`
HostCountry string `json:"HostCountry,omitempty"`
Location ServerLocation `json:"Location"`
Servers []PhysicalServer `json:"Servers"`
}
func FilterServers ¶
func FilterServers(servers []LogicalServer, filter ServerFilter, userTier int) []LogicalServer
FilterServers filters and sorts the server list based on the given criteria. Servers are sorted by score (lower is better), then by load (lower is better).
func FindFastestServer ¶
func FindFastestServer(servers []LogicalServer, filter ServerFilter, userTier int) *LogicalServer
FindFastestServer returns the best server matching the filter. "Best" = lowest score, then lowest load.
func FindServerByName ¶
func FindServerByName(servers []LogicalServer, name string) *LogicalServer
FindServerByName finds a server by its name (e.g., "CH#10").
func (*LogicalServer) BestServer ¶
func (s *LogicalServer) BestServer() *PhysicalServer
BestServer returns the first online physical server, or nil.
func (*LogicalServer) EffectiveTier ¶
func (s *LogicalServer) EffectiveTier() int
EffectiveTier returns the tier, treating legacy Basic as Plus.
func (*LogicalServer) HasFeature ¶
func (s *LogicalServer) HasFeature(feature int) bool
func (*LogicalServer) IsOnline ¶
func (s *LogicalServer) IsOnline() bool
func (*LogicalServer) IsP2P ¶
func (s *LogicalServer) IsP2P() bool
func (*LogicalServer) IsSecureCore ¶
func (s *LogicalServer) IsSecureCore() bool
func (*LogicalServer) IsStreaming ¶
func (s *LogicalServer) IsStreaming() bool
func (*LogicalServer) IsTor ¶
func (s *LogicalServer) IsTor() bool
type LogicalsResponse ¶
type LogicalsResponse struct {
Code int `json:"Code"`
LogicalServers []LogicalServer `json:"LogicalServers"`
LastModifiedTime string `json:"LastModifiedTime,omitempty"`
}
type PhysicalServer ¶
type PhysicalServer struct {
ID string `json:"ID"`
EntryIP string `json:"EntryIP"`
ExitIP string `json:"ExitIP"`
Domain string `json:"Domain"`
Status int `json:"Status"`
Generation int `json:"Generation"`
Label string `json:"Label"`
X25519PublicKey string `json:"X25519PublicKey"`
ServicesDownReason string `json:"ServicesDownReason,omitempty"`
}
type ProtocolPorts ¶
type RefreshRequest ¶
type RefreshResponse ¶
type RequestError ¶
RequestError represents an API error response.
func (*RequestError) Error ¶
func (e *RequestError) Error() string
func (*RequestError) IsAuthError ¶ added in v0.1.7
func (e *RequestError) IsAuthError() bool
IsAuthError returns true if this error indicates the session is permanently dead and the user must re-login (e.g. refresh token revoked, account disabled). Transient errors (network, timeout, 5xx) return false.
type ServerFilter ¶
type ServerFilter struct {
Country string // ISO country code (e.g., "US", "CH")
MinTier int // Minimum tier (0=free, 2=plus)
MaxTier int // Maximum tier (0 = no limit)
Features int // Required feature bitmask (OR'd)
ExcludeFeatures int // Excluded feature bitmask
OnlineOnly bool // Only include online servers
FreeOnly bool // Only free servers
SecureCore bool // Only Secure Core servers
P2P bool // Only P2P servers
Tor bool // Only Tor servers
Streaming bool // Only streaming servers
SearchQuery string // Fuzzy match on name/city/country
ExcludeName string // Exclude server by name (for "change server")
}
ServerFilter defines criteria for filtering the server list.
type ServerLocation ¶
type Session ¶
type Session struct {
UID string `json:"uid"`
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
// Ed25519 private key in base64 for certificate re-requests
PrivateKey string `json:"private_key,omitempty"`
// Login email/username used for display purposes
LoginEmail string `json:"login_email,omitempty"`
}
type SessionStore ¶
type SessionStore struct {
// contains filtered or unexported fields
}
SessionStore handles encrypted persistence of session tokens.
func NewSessionStore ¶
func NewSessionStore(path string) (*SessionStore, error)
NewSessionStore creates a session store at the given path. The encryption key is derived from /etc/machine-id using Argon2id.
func (*SessionStore) Delete ¶
func (s *SessionStore) Delete() error
Delete removes the session file.
func (*SessionStore) Exists ¶
func (s *SessionStore) Exists() bool
Exists returns true if a session file exists.
func (*SessionStore) Load ¶
func (s *SessionStore) Load() (*Session, error)
Load decrypts and reads the session from disk. Returns nil, nil if the file doesn't exist (not an error — just needs login).
func (*SessionStore) Save ¶
func (s *SessionStore) Save(session *Session) error
Save encrypts and persists the session to disk.
type SessionsResponse ¶
type SessionsResponse struct {
Code int `json:"Code"`
Sessions []VPNSession `json:"Sessions"`
}
type SmartProtocol ¶
type VPNInfo ¶
type VPNInfo struct {
ExpirationTime int `json:"ExpirationTime"`
Name string `json:"Name"`
Password string `json:"Password"`
GroupID string `json:"GroupID"`
Status int `json:"Status"`
PlanName string `json:"PlanName"`
PlanTitle string `json:"PlanTitle"`
MaxTier int `json:"MaxTier"`
MaxConnect int `json:"MaxConnect"`
Groups []string `json:"Groups"`
}