fix(BRIDGE-107): improved human verification UX

This commit is contained in:
Atanas Janeshliev
2024-11-06 16:02:05 +01:00
parent f1aef383b7
commit 7d9753e2da
7 changed files with 34 additions and 7 deletions

View File

@ -723,3 +723,13 @@ func (bridge *Bridge) PushDistinctObservabilityMetrics(errType observability.Dis
func (bridge *Bridge) ModifyObservabilityHeartbeatInterval(duration time.Duration) {
bridge.observabilityService.ModifyHeartbeatInterval(duration)
}
func (bridge *Bridge) ReportMessageWithContext(message string, messageCtx reporter.Context) {
if err := bridge.reporter.ReportMessageWithContext(message, messageCtx); err != nil {
logPkg.WithFields(logrus.Fields{
"err": err,
"sentryMessage": message,
"messageCtx": messageCtx,
}).Info("Error occurred when sending Report to Sentry")
}
}

View File

@ -30,7 +30,7 @@ using namespace bridgepp;
namespace {
QString const defaultKeychain = "defaultKeychain"; ///< The default keychain.
QString const HV_ERROR_TEMPLATE = "failed to create new API client: 422 POST https://mail-api.proton.me/auth/v4: CAPTCHA validation failed (Code=12087, Status=422)";
QString const HV_ERROR_TEMPLATE = "Human verification failed. Please try again.";
}

View File

@ -29,6 +29,7 @@ FocusScope {
property alias username: usernameTextField.text
property var wizard
property string hvLinkUrl: ""
property bool hvLinkClicked: false
signal loginAbort(string username, bool wasSignedOut)
@ -49,6 +50,7 @@ FocusScope {
}
passwordTextField.hidePassword();
secondPasswordTextField.hidePassword();
hvLinkClicked = false;
}
function resetViaHv() {
usernameTextField.enabled = false;
@ -56,6 +58,7 @@ FocusScope {
signInButton.loading = true;
secondPasswordButton.loading = false;
secondPasswordTextField.enabled = true;
hvLinkClicked = false;
totpLayout.reset();
}
@ -562,6 +565,7 @@ FocusScope {
cursorShape: Qt.PointingHandCursor
onClicked: {
Qt.openUrlExternally(hvLinkUrl);
hvLinkClicked = true;
}
}
}
@ -574,7 +578,8 @@ FocusScope {
id: hVContinueButton
Layout.fillWidth: true
colorScheme: wizard.colorScheme
text: qsTr("Continue")
text: qsTr("Ive completed the verification")
enabled: hvLinkClicked
function checkAndSignInHv() {
console.assert(stackLayout.currentIndex === Login.RootStack.HV || stackLayout.currentIndex === Login.RootStack.MailboxPassword, "Unexpected checkInAndSignInHv")

View File

@ -159,7 +159,10 @@ func (f *frontendCLI) loginAccount(c *ishell.Context) {
hvDetails, hvErr := hv.VerifyAndExtractHvRequest(err)
if hvErr != nil || hvDetails != nil {
if hvErr != nil {
f.printAndLogError("Cannot login", hvErr)
f.printAndLogError("Cannot login:", hv.ExtractionErrorMsg)
f.bridge.ReportMessageWithContext("Unable to extract HV request details", map[string]any{
"error": err.Error(),
})
return
}
f.promptHvURL(hvDetails)

View File

@ -465,7 +465,7 @@ func (s *Service) finishLogin() {
if apiErr := new(proton.APIError); errors.As(err, &apiErr) && apiErr.Code == proton.HumanValidationInvalidToken {
s.hvDetails = nil
_ = s.SendEvent(NewLoginError(LoginErrorType_HV_ERROR, err.Error()))
_ = s.SendEvent(NewLoginError(LoginErrorType_HV_ERROR, hv.VerificationFailedErrorMsg))
return
}
@ -643,7 +643,10 @@ func (s *Service) monitorParentPID() {
func (s *Service) handleHvRequest(err error) {
hvDet, hvErr := hv.VerifyAndExtractHvRequest(err)
if hvErr != nil {
_ = s.SendEvent(NewLoginError(LoginErrorType_HV_ERROR, hvErr.Error()))
_ = s.SendEvent(NewLoginError(LoginErrorType_HV_ERROR, hv.ExtractionErrorMsg))
s.bridge.ReportMessageWithContext("Unable to extract HV request details", map[string]any{
"error": err.Error(),
})
return
}

View File

@ -30,6 +30,7 @@ import (
"github.com/ProtonMail/proton-bridge/v3/internal/constants"
"github.com/ProtonMail/proton-bridge/v3/internal/events"
"github.com/ProtonMail/proton-bridge/v3/internal/frontend/theme"
"github.com/ProtonMail/proton-bridge/v3/internal/hv"
"github.com/ProtonMail/proton-bridge/v3/internal/kb"
"github.com/ProtonMail/proton-bridge/v3/internal/safe"
"github.com/ProtonMail/proton-bridge/v3/internal/service"
@ -468,7 +469,7 @@ func (s *Service) Login(_ context.Context, login *LoginRequest) (*emptypb.Empty,
case proton.HumanValidationInvalidToken:
s.hvDetails = nil
_ = s.SendEvent(NewLoginError(LoginErrorType_HV_ERROR, err.Error()))
_ = s.SendEvent(NewLoginError(LoginErrorType_HV_ERROR, hv.VerificationFailedErrorMsg))
default:
_ = s.SendEvent(NewLoginError(LoginErrorType_USERNAME_PASSWORD_ERROR, err.Error()))

View File

@ -21,6 +21,11 @@ import (
"github.com/ProtonMail/go-proton-api"
)
const (
ExtractionErrorMsg = "Human verification requested, but an issue occurred. Please try again."
VerificationFailedErrorMsg = "Human verification failed. Please try again."
)
// VerifyAndExtractHvRequest expects an error request as input
// determines whether the given error is a Proton human verification request; if it isn't then it returns -> nil, nil (no details, no error)
// if it is a HV req. then it tries to parse the json data and verify that the captcha method is included; if either fails -> nil, err
@ -34,7 +39,7 @@ func VerifyAndExtractHvRequest(err error) (*proton.APIHVDetails, error) {
if errors.As(err, &protonErr) && protonErr.IsHVError() {
hvDetails, hvErr := protonErr.GetHVDetails()
if hvErr != nil {
return nil, fmt.Errorf("received HV request, but can't decode HV details")
return nil, hvErr
}
return hvDetails, nil
}