Documentation
¶
Overview ¶
Package account provides Proton Account-specific types and operations.
Index ¶
- Constants
- Variables
- func CookieFork(ctx context.Context, acctSession *api.Session, ...) (*api.Session, []byte, error)
- func CookieLoginSave(cookieStore, accountStore api.SessionStore, session *api.Session, ...) error
- func CookieSRPAuth(ctx context.Context, cs *CookieSession, username string, password []byte) (*proton.Auth, error)
- func CookieSessionFromForkPull(ctx context.Context, pull *ForkPullResp, svc api.ServiceConfig, ...) *api.Session
- func CookieSessionRestore(ctx context.Context, options []proton.Option, cookieStore api.SessionStore, ...) (*api.Session, error)
- func CookieTwoFA(ctx context.Context, cs *CookieSession, code string) error
- func EncryptForkBlob(blob *ForkBlob) (ciphertext string, key []byte, err error)
- func ForkSession(ctx context.Context, parent *api.Session, targetService api.ServiceConfig, ...) (*api.Session, []byte, error)
- func ForkSessionWithKeyPass(ctx context.Context, parent *api.Session, targetService api.ServiceConfig, ...) (*api.Session, []byte, error)
- func IsStale(accountRefresh, serviceRefresh time.Time) bool
- func NeedsCookieRefresh(lastRefresh time.Time) bool
- func NeedsProactiveRefresh(lastRefresh time.Time) bool
- func NewAuthHandler(store api.SessionStore, session *api.Session) proton.AuthHandler
- func NewDeauthHandler() proton.Handler
- func NewProtonCookieJar(cookies []api.SerialCookie, baseURL string) http.CookieJar
- func PopulateAccountCache(uid string, user proton.User, addrs []proton.Address)
- func ReadySession(ctx context.Context, options []proton.Option, store api.SessionStore, ...) (*api.Session, error)
- func RestoreServiceSession(ctx context.Context, service string, options []proton.Option, ...) (*api.Session, error)
- func SessionFromCredentials(ctx context.Context, options []proton.Option, config *api.SessionCredentials, ...) (*api.Session, error)
- func SessionFromForkPull(ctx context.Context, pull *ForkPullResp, svc api.ServiceConfig, _ string) *api.Session
- func SessionFromLogin(ctx context.Context, options []proton.Option, username string, password string, ...) (*api.Session, error)
- func SessionList(store api.SessionStore) ([]string, error)
- func SessionRestore(ctx context.Context, options []proton.Option, store api.SessionStore, ...) (*api.Session, error)
- func SessionRetryWithHV(ctx context.Context, session *api.Session, username, password string, ...) error
- func SessionRevoke(ctx context.Context, session *api.Session, store api.SessionStore, force bool) error
- func SessionSave(store api.SessionStore, session *api.Session, keypass []byte) error
- type Address
- type AnonSessionResp
- type AuthCookiesReq
- type Client
- type CookieSession
- func CookieSessionFromConfig(config *CookieSessionConfig, baseURL string) *CookieSession
- func NewCookieAuthHandler(cookieConfig *api.SessionCredentials, baseURL string, ...) *CookieSession
- func NewCookieSession(uid, baseURL string, jar http.CookieJar) *CookieSession
- func NewCookieSessionForRefresh(uid, baseURL, appVersion string, jar http.CookieJar, store api.SessionStore) *CookieSession
- func TransitionToCookies(ctx context.Context, session *api.Session) (*CookieSession, error)
- func (cs *CookieSession) Config() *CookieSessionConfig
- func (cs *CookieSession) DoJSON(ctx context.Context, method, path string, body, result any) error
- func (cs *CookieSession) DoSSE(ctx context.Context, path string, body any) (io.ReadCloser, error)
- func (cs *CookieSession) RefreshCookies(ctx context.Context) error
- type CookieSessionConfig
- type CookieTransport
- type ForkBlob
- type ForkPullResp
- type ForkPushReq
- type ForkPushResp
- type User
- func (u User) CalendarUsedSpace() int64
- func (u User) ContactUsedSpace() int64
- func (u User) DisplayName() string
- func (u User) DriveUsedSpace() int64
- func (u User) Email() string
- func (u User) ID() string
- func (u User) MailUsedSpace() int64
- func (u User) MaxSpace() int64
- func (u User) Name() string
- func (u User) PassUsedSpace() int64
- func (u User) UsedSpace() int64
Constants ¶
const CookieDomain = "proton.me"
CookieDomain is the domain used for all Proton session cookies. The server sets Domain=proton.me on Set-Cookie headers, making cookies valid for all *.proton.me subdomains. We use this constant when loading persisted cookies back into a jar so the domain scoping is preserved.
Variables ¶
var ( // ErrSessionExpired indicates that the session tokens have expired // and the session cannot be restored without re-authentication. ErrSessionExpired = errors.New("account: session expired") // ErrAuthFailed indicates that authentication failed (bad credentials, // SRP proof mismatch, or server rejection). ErrAuthFailed = errors.New("account: authentication failed") // ErrHVRequired indicates that the server requires human verification // (CAPTCHA) before the request can proceed. ErrHVRequired = errors.New("account: human verification required") // ErrForkFailed indicates that the session fork protocol failed. ErrForkFailed = errors.New("account: session fork failed") )
Functions ¶
func CookieFork ¶
func CookieFork(ctx context.Context, acctSession *api.Session, acctConfig *api.SessionCredentials, targetService api.ServiceConfig, _ string, keyPass []byte, cookieStore api.SessionStore) (*api.Session, []byte, error)
CookieFork performs a cookie-aware fork for CookieAuth services.
The flow:
- Load or create a CookieSession from cookieStore.
- If no valid cookie session exists, fork a TEMPORARY session from account (Bearer), transition it to cookies, and save.
- Use CookieSession.DoJSON for the fork push (AUTH cookie → full scopes).
- Fork pull is unchanged (unauthenticated, Session-Id only).
- Build child Session from fork pull response.
CRITICAL: The account Bearer session is never passed to TransitionToCookies. A temporary forked session is transitioned instead, preserving the account session for Drive operations.
func CookieLoginSave ¶
func CookieLoginSave(cookieStore, accountStore api.SessionStore, session *api.Session, cookieSess *CookieSession, keypass []byte) error
CookieLoginSave persists both the cookie session and account metadata after a login-time cookie transition. The cookieStore receives the serialized cookies, and the accountStore receives CookieAuth=true with empty Bearer tokens (they are invalid after transition).
func CookieSRPAuth ¶
func CookieSRPAuth(ctx context.Context, cs *CookieSession, username string, password []byte) (*proton.Auth, error)
CookieSRPAuth performs SRP authentication within a cookie session. It calls auth/info to get SRP parameters, computes proofs via go-srp, submits the proof to auth, and verifies the server's proof. Returns the Auth response containing UID, tokens, 2FA status, and password mode.
func CookieSessionFromForkPull ¶
func CookieSessionFromForkPull(ctx context.Context, pull *ForkPullResp, svc api.ServiceConfig, cookieJar http.CookieJar) *api.Session
CookieSessionFromForkPull constructs a Session that uses cookie auth instead of Bearer auth. The provided cookie jar must contain the AUTH-<uid> cookie. CookieTransport strips the Bearer header that Resty adds, so the server only sees cookie auth.
func CookieSessionRestore ¶
func CookieSessionRestore(ctx context.Context, options []proton.Option, cookieStore api.SessionStore, acctConfig *api.SessionCredentials, managerHook func(*proton.Manager)) (*api.Session, error)
CookieSessionRestore restores a cookie-mode session from the cookie store. It loads persisted cookies, optionally performs a proactive refresh, builds a proton.Manager with CookieTransport, and unlocks keyrings. The returned Session uses cookie auth for all Resty-based API calls (GetUser, GetAddresses, etc.). Session.Auth holds the UID but empty Bearer tokens.
func CookieTwoFA ¶
func CookieTwoFA(ctx context.Context, cs *CookieSession, code string) error
CookieTwoFA submits a TOTP 2FA code within a cookie session.
func EncryptForkBlob ¶
EncryptForkBlob encrypts a ForkBlob using AES-256-GCM with a random 32-byte key. Returns the base64-encoded ciphertext (nonce || ciphertext) and the raw key. The additional data is the UTF-8 bytes of "fork", matching WebClient v3 format.
func ForkSession ¶
func ForkSession(ctx context.Context, parent *api.Session, targetService api.ServiceConfig, version string) (*api.Session, []byte, error)
ForkSession creates a child session for targetService by forking from the parent session. Both push and pull go to the target service's host — the parent's auth headers authenticate the push, and the selector authenticates the pull.
The parent session must be authenticated (valid UID/AccessToken). The child session is returned with BaseURL and AppVersion set to the target service's values. The decrypted SaltedKeyPass from the fork blob is returned as the second value.
func ForkSessionWithKeyPass ¶
func ForkSessionWithKeyPass(ctx context.Context, parent *api.Session, targetService api.ServiceConfig, version string, keyPass []byte) (*api.Session, []byte, error)
ForkSessionWithKeyPass creates a child session, encrypting the given SaltedKeyPass in the fork blob instead of using the parent's UID.
func IsStale ¶
IsStale reports whether a service session is stale relative to the account session. A service session is stale when the account's LastRefresh is after the service's LastRefresh, or when the service's LastRefresh is zero.
func NeedsCookieRefresh ¶
NeedsCookieRefresh reports whether the cookie session's LastRefresh age exceeds CookieRefreshAge. A zero-valued LastRefresh always triggers refresh.
func NeedsProactiveRefresh ¶
NeedsProactiveRefresh reports whether the session's LastRefresh age exceeds ProactiveRefreshAge. A zero-valued LastRefresh always triggers refresh.
func NewAuthHandler ¶
func NewAuthHandler(store api.SessionStore, session *api.Session) proton.AuthHandler
NewAuthHandler returns a proton.AuthHandler that persists updated tokens and cookies to the session store. Uses the session's own cookie jar.
func NewDeauthHandler ¶
NewDeauthHandler returns a proton.Handler that logs deauth events.
func NewProtonCookieJar ¶
func NewProtonCookieJar(cookies []api.SerialCookie, baseURL string) http.CookieJar
NewProtonCookieJar creates a new cookie jar and injects the given cookies with Proton domain scoping. Used for session restore.
func PopulateAccountCache ¶
PopulateAccountCache creates a temporary ObjectCache scoped to the given UID and stores the provided User and Address data. This is a convenience for callers (e.g., login flows) that do not hold a Client but need to populate the account cache.
func ReadySession ¶
func ReadySession(ctx context.Context, options []proton.Option, store api.SessionStore, cookieStore api.SessionStore, managerHook func(*proton.Manager)) (*api.Session, error)
ReadySession restores a session from the store, registers auth/deauth handlers, and returns a fully initialized Session ready for use. This is the recommended entry point for consumers that need an authenticated session. When cookieStore is non-nil and the session has CookieAuth=true, the cookie restore path is used.
func RestoreServiceSession ¶
func RestoreServiceSession(ctx context.Context, service string, options []proton.Option, store api.SessionStore, accountStore api.SessionStore, cookieStore api.SessionStore, version string, managerHook func(*proton.Manager)) (*api.Session, error)
RestoreServiceSession restores or creates a service-specific session. If no session exists for the service, it forks from the account session. If no account session exists, it returns ErrNotLoggedIn.
The flow:
- Load account session config from accountStore.
- If CookieAuth=true, use cookie fork path (CookieSessionRestore → cookieFork).
- Otherwise, build account session from credentials.
- If account session age > ProactiveRefreshAge, trigger proactive refresh.
- If service session missing or stale (account LastRefresh > service LastRefresh), fork from account session via ForkSessionWithKeyPass.
- Set session.BaseURL and AppVersion from the ServiceConfig.
- Return session.
func SessionFromCredentials ¶
func SessionFromCredentials(ctx context.Context, options []proton.Option, config *api.SessionCredentials, managerHook func(*proton.Manager)) (*api.Session, error)
SessionFromCredentials initializes a new session from the provided config. The session is not fully usable until it has been Unlock'ed using the user-provided keypass.
func SessionFromForkPull ¶
func SessionFromForkPull(ctx context.Context, pull *ForkPullResp, svc api.ServiceConfig, _ string) *api.Session
SessionFromForkPull constructs a Session from a ForkPullResp and ServiceConfig. The version string is passed through for backward compatibility but the service's own app version is used for all requests.
func SessionFromLogin ¶
func SessionFromLogin(ctx context.Context, options []proton.Option, username string, password string, hvDetails *proton.APIHVDetails, managerHook func(*proton.Manager)) (*api.Session, error)
SessionFromLogin initializes a new session from the provided login/password. If hvDetails is non-nil, the login includes the HV token for CAPTCHA retry. The same manager (and cookie jar) is used for both initial and HV-retried login attempts — this is required because Proton's backend correlates the solved CAPTCHA with the session cookie from the initial attempt.
On error, the returned *Session is intentionally non-nil and reusable for SessionRetryWithHV. The manager and cookie jar must be preserved across attempts so that the solved CAPTCHA correlates with the session cookie established during the initial (failed) login request.
func SessionList ¶
func SessionList(store api.SessionStore) ([]string, error)
SessionList returns account names from the session store.
func SessionRestore ¶
func SessionRestore(ctx context.Context, options []proton.Option, store api.SessionStore, cookieStore api.SessionStore, managerHook func(*proton.Manager)) (*api.Session, error)
SessionRestore loads credentials from the store and creates an unlocked session. Returns ErrNotLoggedIn if no session is stored. When the loaded config has CookieAuth=true and cookieStore is non-nil, the cookie restore path is used instead of the Bearer path.
func SessionRetryWithHV ¶
func SessionRetryWithHV(ctx context.Context, session *api.Session, username, password string, hv *proton.APIHVDetails) error
SessionRetryWithHV retries login on an existing session (reusing its manager and cookie jar) with HV details after the user solved the CAPTCHA. A fresh AuthInfo is fetched because the original SRP session is invalidated by the 9001 response. The solved CAPTCHA composite token is NOT bound to the SRP session — it's bound to the HumanVerificationToken.
func SessionRevoke ¶
func SessionRevoke(ctx context.Context, session *api.Session, store api.SessionStore, force bool) error
SessionRevoke revokes the API session and deletes it from the store. If force is true, store deletion proceeds even when the API revoke fails.
func SessionSave ¶
SessionSave persists session credentials, cookie jar state, and a refresh timestamp to the store. Uses CookieQueryURL (path=/api/auth/refresh) so the jar query matches both AUTH (path=/api/) and REFRESH (path=/api/auth/refresh) cookies.
Types ¶
type Address ¶
type Address struct {
// contains filtered or unexported fields
}
Address is an opaque wrapper around a Proton email address. Consumers access fields via methods — they cannot construct or inspect the struct directly.
type AnonSessionResp ¶
type AnonSessionResp struct {
Code int `json:"Code"`
UID string `json:"UID"`
AccessToken string `json:"AccessToken"`
RefreshToken string `json:"RefreshToken"`
}
AnonSessionResp is the response from POST /auth/v4/sessions.
func CreateAnonSession ¶
CreateAnonSession creates an anonymous session on the account host. This is the first step in the browser's login flow — it creates a session with no credentials, returning UID + tokens that can be used for subsequent SRP login. The session is created on account.proton.me matching the browser's flow exactly.
type AuthCookiesReq ¶
type AuthCookiesReq struct {
UID string `json:"UID"`
RefreshToken string `json:"RefreshToken"`
GrantType string `json:"GrantType"` // always "refresh_token"
RedirectURI string `json:"RedirectURI"` // "https://proton.me"
ResponseType string `json:"ResponseType"` // "token"
State string `json:"State"` // random state string
}
AuthCookiesReq is the request body for POST /core/v4/auth/cookies.
type Client ¶
Client wraps an api.Session with Account-specific operations.
func NewClientWithCache ¶
NewClientWithCache constructs an Account client with an ObjectCache scoped to the given UID. The cache stores raw encrypted User and Address API objects on disk at $XDG_RUNTIME_DIR/proton/account/{uid}/. Returns a Client with caching disabled when uid is empty or $XDG_RUNTIME_DIR is not set.
func (*Client) GetAddresses ¶
GetAddresses returns all email addresses associated with the account. The returned Address values are opaque wrappers — consumers access fields via accessor methods and do not need to import go-proton-api.
type CookieSession ¶
type CookieSession struct {
UID string // Proton UID
BaseURL string // API base URL (e.g., "https://account.proton.me/api")
AppVersion string // x-pm-appversion header value
UserAgent string // User-Agent header value
HVDetails *proton.APIHVDetails // when non-nil, HV headers are added to requests
Store api.SessionStore // when non-nil, cookies are persisted after refresh
// contains filtered or unexported fields
}
CookieSession holds cookie-based authentication state for services that require cookie auth (e.g., Lumo). Created from a Bearer session via TransitionToCookies, or restored from persisted cookies.
func CookieSessionFromConfig ¶
func CookieSessionFromConfig(config *CookieSessionConfig, baseURL string) *CookieSession
CookieSessionFromConfig creates a CookieSession from persisted cookies. No proton.Manager or Resty client is created — the session uses net/http directly with the restored cookie jar. The baseURL parameter determines the domain cookies are scoped to in the jar; pass the account service host (e.g., "https://account.proton.me/api").
func NewCookieAuthHandler ¶
func NewCookieAuthHandler(cookieConfig *api.SessionCredentials, baseURL string, transport *CookieTransport, cookieStore api.SessionStore) *CookieSession
NewCookieAuthHandler creates a CookieSession for 401 refresh and wires it into the CookieTransport. Returns the CookieSession so callers can use it for other cookie operations. The cookieStore is used to persist updated cookies after refresh.
func NewCookieSession ¶
func NewCookieSession(uid, baseURL string, jar http.CookieJar) *CookieSession
NewCookieSession creates a CookieSession with the given parameters. Used by tests and callers that need to construct a CookieSession directly rather than via TransitionToCookies or CookieSessionFromConfig.
func NewCookieSessionForRefresh ¶
func NewCookieSessionForRefresh(uid, baseURL, appVersion string, jar http.CookieJar, store api.SessionStore) *CookieSession
NewCookieSessionForRefresh creates a CookieSession suitable for proactive cookie refresh. Used by restoreExistingCookieService.
func TransitionToCookies ¶
TransitionToCookies calls POST /core/v4/auth/cookies to transition from Bearer auth to cookie auth. After this call, the Bearer tokens in the source session are INVALID server-side. Returns a CookieSession with the AUTH and REFRESH cookies set in its jar.
func (*CookieSession) Config ¶
func (cs *CookieSession) Config() *CookieSessionConfig
Config serializes the CookieSession's cookie jar into a CookieSessionConfig suitable for persistence. LastRefresh is set to the current time.
func (*CookieSession) DoJSON ¶
DoJSON executes an authenticated JSON API request using cookie auth. No Authorization: Bearer header is sent — auth is provided via the AUTH-<uid> cookie in the cookie jar. The x-pm-uid header is always set.
On success (Code 1000), result is populated if non-nil. On API error, returns *api.Error with Status, Code, and Message. On 401, attempts a cookie refresh via RefreshCookies and retries the request once.
func (*CookieSession) DoSSE ¶
func (cs *CookieSession) DoSSE(ctx context.Context, path string, body any) (io.ReadCloser, error)
DoSSE executes an authenticated POST and returns the raw response body for SSE streaming. The caller is responsible for closing the returned io.ReadCloser. Sets cookie auth headers (x-pm-uid, x-pm-appversion, User-Agent) plus Accept: text/event-stream. No Authorization: Bearer header is sent. Returns an *api.Error on non-2xx HTTP status.
func (*CookieSession) RefreshCookies ¶
func (cs *CookieSession) RefreshCookies(ctx context.Context) error
RefreshCookies calls POST /core/v4/auth/cookies with the REFRESH cookie to obtain new AUTH and REFRESH cookies. The cookie jar is updated with the new cookies from the response Set-Cookie headers. Concurrent calls are serialized via cs.mu — only one refresh HTTP call executes at a time.
CRITICAL: This method uses a raw http.Client, NOT DoJSON. Using DoJSON would cause infinite recursion because DoJSON's 401 retry calls RefreshCookies.
type CookieSessionConfig ¶
type CookieSessionConfig struct {
UID string `json:"uid"`
Cookies []api.SerialCookie `json:"cookies,omitempty"`
LastRefresh time.Time `json:"last_refresh,omitempty"`
Service string `json:"service,omitempty"`
}
CookieSessionConfig holds the minimal data to restore a CookieSession without Resty. Stored separately from the Bearer SessionCredentials.
type CookieTransport ¶
type CookieTransport struct {
// Base is the underlying transport. If nil, http.DefaultTransport is used.
Base http.RoundTripper
// contains filtered or unexported fields
}
CookieTransport is an http.RoundTripper that converts Bearer auth to cookie auth. It strips the Authorization header added by Resty and relies on the cookie jar (set on the http.Client by Resty) to send AUTH-<uid> cookies instead.
When a CookieSession is attached (via SetCookieSession), the transport intercepts 401 responses, triggers a cookie refresh, and retries the request once. This handles auth expiry transparently without relying on go-proton-api's Bearer-based authRefresh (which fails for cookie sessions).
Usage:
ct := &CookieTransport{Base: http.DefaultTransport}
manager := proton.New(
proton.WithTransport(ct),
proton.WithCookieJar(jar), // jar has AUTH-<uid> cookie
...
)
func (*CookieTransport) RoundTrip ¶
RoundTrip strips the Authorization header and delegates to the base transport. The cookie jar on the http.Client sends AUTH-<uid> cookies automatically. If a CookieSession is attached and the response is 401, triggers a cookie refresh and retries once.
func (*CookieTransport) SetCookieSession ¶
func (ct *CookieTransport) SetCookieSession(cs *CookieSession, store api.SessionStore)
SetCookieSession attaches a CookieSession and store for 401 refresh. When set, 401 responses trigger RefreshCookies and a retry.
type ForkBlob ¶
type ForkBlob struct {
Type string `json:"type"` // "default"
KeyPassword string `json:"keyPassword"` // SaltedKeyPass from parent
}
ForkBlob is the plaintext payload encrypted in the fork.
type ForkPullResp ¶
type ForkPullResp struct {
Code int `json:"Code"`
UID string `json:"UID"`
AccessToken string `json:"AccessToken"`
RefreshToken string `json:"RefreshToken"`
Payload string `json:"Payload,omitempty"`
Scopes []string `json:"Scopes,omitempty"`
}
ForkPullResp is the response from GET /auth/v4/sessions/forks/<selector>.
type ForkPushReq ¶
type ForkPushReq struct {
ChildClientID string `json:"ChildClientID"`
Independent int `json:"Independent"`
Payload string `json:"Payload,omitempty"`
}
ForkPushReq is the request body for POST /auth/v4/sessions/forks.
type ForkPushResp ¶
ForkPushResp is the response from POST /auth/v4/sessions/forks.
type User ¶
type User struct {
// contains filtered or unexported fields
}
User is an opaque wrapper around the Proton user profile. Consumers access fields via methods — they cannot construct or inspect the struct directly.
func (User) CalendarUsedSpace ¶
CalendarUsedSpace returns storage used by Calendar in bytes.
func (User) ContactUsedSpace ¶
ContactUsedSpace returns storage used by Contacts in bytes.
func (User) DisplayName ¶
DisplayName returns the user's display name.
func (User) DriveUsedSpace ¶
DriveUsedSpace returns storage used by Drive in bytes.
func (User) MailUsedSpace ¶
MailUsedSpace returns storage used by Mail in bytes.
func (User) PassUsedSpace ¶
PassUsedSpace returns storage used by Pass in bytes.