83 lines
2.7 KiB
Go
83 lines
2.7 KiB
Go
package auth
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"protonvpn-wg-confgen/internal/constants"
|
|
)
|
|
|
|
// Error codes from ProtonVPN API
|
|
// Official source: github.com/ProtonMail/protoncore_android/.../ResponseCodes.kt
|
|
// See API_REFERENCE.md for full documentation.
|
|
const (
|
|
CodeSuccess = constants.APICodeSuccess
|
|
CodeWrongPassword = 8002 // PASSWORD_WRONG: Incorrect password
|
|
CodeWrongPasswordFormat = 8004 // Password format is incorrect (observed)
|
|
CodeCaptchaRequired = 9001 // HUMAN_VERIFICATION_REQUIRED: CAPTCHA needed
|
|
Code2FARequiredForVPN = 9100 // VPN-specific: certificate endpoint requires 2FA session (not in official docs)
|
|
CodeAccountDeleted = 10002 // ACCOUNT_DELETED: Account has been deleted
|
|
CodeAccountDisabled = 10003 // ACCOUNT_DISABLED: Account has been disabled
|
|
CodeMailboxPasswordError = 10013 // Legacy 2-password mode / invalid refresh token (context-dependent)
|
|
)
|
|
|
|
// Error represents an authentication error with ProtonVPN-specific error code
|
|
type Error struct {
|
|
Code int
|
|
Message string
|
|
}
|
|
|
|
// Error implements the error interface
|
|
func (e Error) Error() string {
|
|
return e.Message
|
|
}
|
|
|
|
// NewError creates a new authentication error from an API response code
|
|
func NewError(code int) error {
|
|
message := getErrorMessage(code)
|
|
return Error{
|
|
Code: code,
|
|
Message: message,
|
|
}
|
|
}
|
|
|
|
// getErrorMessage returns a human-readable error message for a given error code
|
|
func getErrorMessage(code int) string {
|
|
switch code {
|
|
case CodeWrongPassword:
|
|
return "incorrect username or password"
|
|
case CodeWrongPasswordFormat:
|
|
return "password format is incorrect"
|
|
case CodeCaptchaRequired:
|
|
return "CAPTCHA verification required"
|
|
case Code2FARequiredForVPN:
|
|
return "2FA required for VPN operations - your session was authenticated without 2FA (device trust). Use -clear-session to force re-authentication with 2FA"
|
|
case CodeAccountDeleted:
|
|
return "account has been deleted"
|
|
case CodeAccountDisabled:
|
|
return "account has been disabled"
|
|
case CodeMailboxPasswordError:
|
|
return "account uses legacy 2-password mode - please switch to single-password mode at account.proton.me"
|
|
default:
|
|
return fmt.Sprintf("authentication failed with code: %d", code)
|
|
}
|
|
}
|
|
|
|
// IsAccountError checks if the error is an account status error (deleted or disabled)
|
|
func IsAccountError(err error) bool {
|
|
var authErr Error
|
|
if !errors.As(err, &authErr) {
|
|
return false
|
|
}
|
|
return authErr.Code == CodeAccountDeleted || authErr.Code == CodeAccountDisabled
|
|
}
|
|
|
|
// IsCaptchaError checks if the error requires CAPTCHA verification
|
|
func IsCaptchaError(err error) bool {
|
|
var authErr Error
|
|
if !errors.As(err, &authErr) {
|
|
return false
|
|
}
|
|
return authErr.Code == CodeCaptchaRequired
|
|
}
|