Account: implements the /v2/verify/init endpoint (#35678)
This commit is contained in:
@@ -16,6 +16,7 @@ source_set("endpoints") {
|
||||
"service_token.h",
|
||||
"verify_complete.h",
|
||||
"verify_delete.h",
|
||||
"verify_init.h",
|
||||
"verify_resend.h",
|
||||
]
|
||||
|
||||
@@ -37,6 +38,7 @@ generated_types("generated_api_types") {
|
||||
"service_token_bodies.idl",
|
||||
"verify_complete_bodies.idl",
|
||||
"verify_delete_bodies.idl",
|
||||
"verify_init_bodies.idl",
|
||||
"verify_resend_bodies.idl",
|
||||
]
|
||||
|
||||
@@ -59,6 +61,7 @@ source_set("unit_tests") {
|
||||
"service_token_unittest.cc",
|
||||
"verify_complete_unittest.cc",
|
||||
"verify_delete_unittest.cc",
|
||||
"verify_init_unittest.cc",
|
||||
"verify_resend_unittest.cc",
|
||||
]
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/* Copyright (c) 2026 The Brave Authors. All rights reserved.
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef BRAVE_COMPONENTS_BRAVE_ACCOUNT_ENDPOINTS_VERIFY_INIT_H_
|
||||
#define BRAVE_COMPONENTS_BRAVE_ACCOUNT_ENDPOINTS_VERIFY_INIT_H_
|
||||
|
||||
#include "brave/components/brave_account/endpoint_client/brave_endpoint.h"
|
||||
#include "brave/components/brave_account/endpoint_client/request_types.h"
|
||||
#include "brave/components/brave_account/endpoint_client/response.h"
|
||||
#include "brave/components/brave_account/endpoints/error_body.h"
|
||||
#include "brave/components/brave_account/endpoints/verify_init_bodies.h"
|
||||
|
||||
namespace brave_account::endpoints {
|
||||
|
||||
using VerifyInit = endpoint_client::BraveEndpoint<
|
||||
"accounts.bsg",
|
||||
"/v2/verify/init",
|
||||
endpoint_client::POST<VerifyInitRequestBody>,
|
||||
endpoint_client::Response<VerifyInitSuccessBody, ErrorBody>>;
|
||||
|
||||
} // namespace brave_account::endpoints
|
||||
|
||||
#endif // BRAVE_COMPONENTS_BRAVE_ACCOUNT_ENDPOINTS_VERIFY_INIT_H_
|
||||
@@ -0,0 +1,18 @@
|
||||
/* Copyright (c) 2026 The Brave Authors. All rights reserved.
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Schema for the /v2/verify/init request and response.
|
||||
namespace endpoints {
|
||||
dictionary VerifyInitRequestBody {
|
||||
DOMString email;
|
||||
DOMString intent;
|
||||
DOMString locale;
|
||||
DOMString service;
|
||||
};
|
||||
|
||||
dictionary VerifyInitSuccessBody {
|
||||
DOMString verificationToken;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,126 @@
|
||||
/* Copyright (c) 2026 The Brave Authors. All rights reserved.
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "brave/components/brave_account/endpoints/verify_init.h"
|
||||
|
||||
#include "base/no_destructor.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "brave/components/brave_account/endpoints/endpoint_test.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "net/http/http_status_code.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace brave_account::endpoints {
|
||||
|
||||
bool operator==(const VerifyInit::Response::SuccessBody& lhs,
|
||||
const VerifyInit::Response::SuccessBody& rhs) {
|
||||
return lhs.verification_token == rhs.verification_token;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
using VerifyInitTestCase = EndpointTestCase<VerifyInit>;
|
||||
|
||||
const VerifyInitTestCase* Success() {
|
||||
static const base::NoDestructor<VerifyInitTestCase> kSuccess(
|
||||
{.test_name = "success",
|
||||
.http_status_code = net::HTTP_OK,
|
||||
.raw_response_body = R"({ "verificationToken": "eyJhbGciOiJFUz" })",
|
||||
.expected_response = {
|
||||
.net_error = net::OK, .status_code = net::HTTP_OK, .body = [] {
|
||||
VerifyInit::Response::SuccessBody body;
|
||||
body.verification_token = "eyJhbGciOiJFUz";
|
||||
return body;
|
||||
}()}});
|
||||
|
||||
return kSuccess.get();
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
// application/json errors:
|
||||
// - HTTP 400:
|
||||
// - { "code": null, "error": "Bad Request", "status": 400 }
|
||||
// - { "code": 13001, "error": "too many pending verification requests for email", "status": 400 }
|
||||
// - { "code": 13003, "error": "intent not allowed", "status": 400 }
|
||||
// - { "code": 13004, "error": "account already exists", "status": 400 }
|
||||
// - { "code": 13005, "error": "account does not exist", "status": 400 }
|
||||
// - { "code": 13006, "error": "email domain is not supported", "status": 400 }
|
||||
// - { "code": 13007, "error": "failed to send email due to invalid format", "status": 400 }
|
||||
// - HTTP 401:
|
||||
// - { "code": null, "error": "Unauthorized", "status": 401 }
|
||||
// - HTTP 403:
|
||||
// - { "code": 14007, "error": "invalid token audience", "status": 403 }
|
||||
// - HTTP 5XX:
|
||||
// - { "code": null, "error": "Internal Server Error", "status": <5xx> }
|
||||
// clang-format on
|
||||
const VerifyInitTestCase* ApplicationJsonErrorCodeIsNull() {
|
||||
static const base::NoDestructor<VerifyInitTestCase>
|
||||
kApplicationJsonErrorCodeIsNull(
|
||||
{.test_name = "application_json_error_code_is_null",
|
||||
.http_status_code = net::HTTP_BAD_REQUEST,
|
||||
.raw_response_body =
|
||||
R"({ "code": null,
|
||||
"error": "Bad Request",
|
||||
"status": 400 })",
|
||||
.expected_response = {.net_error = net::OK,
|
||||
.status_code = net::HTTP_BAD_REQUEST,
|
||||
.body = base::unexpected([] {
|
||||
VerifyInit::Response::ErrorBody body;
|
||||
body.code = base::Value();
|
||||
return body;
|
||||
}())}});
|
||||
return kApplicationJsonErrorCodeIsNull.get();
|
||||
}
|
||||
|
||||
const VerifyInitTestCase* ApplicationJsonErrorCodeIsNotNull() {
|
||||
static const base::NoDestructor<VerifyInitTestCase>
|
||||
kApplicationJsonErrorCodeIsNotNull(
|
||||
{.test_name = "application_json_error_code_is_not_null",
|
||||
.http_status_code = net::HTTP_FORBIDDEN,
|
||||
.raw_response_body =
|
||||
R"({ "code": 14007,
|
||||
"error": "invalid token audience",
|
||||
"status": 403 })",
|
||||
.expected_response = {.net_error = net::OK,
|
||||
.status_code = net::HTTP_FORBIDDEN,
|
||||
.body = base::unexpected([] {
|
||||
VerifyInit::Response::ErrorBody body;
|
||||
body.code = base::Value(14007);
|
||||
return body;
|
||||
}())}});
|
||||
return kApplicationJsonErrorCodeIsNotNull.get();
|
||||
}
|
||||
|
||||
// non-application/json errors:
|
||||
// - HTTP 5XX:
|
||||
// - plain text errors returned by AWS/load balancer
|
||||
const VerifyInitTestCase* NonApplicationJsonError() {
|
||||
static const base::NoDestructor<VerifyInitTestCase> kNonApplicationJsonError(
|
||||
{.test_name = "non_application_json_error",
|
||||
.http_status_code = net::HTTP_INTERNAL_SERVER_ERROR,
|
||||
.raw_response_body = "non-application/json error",
|
||||
.expected_response = {.net_error = net::OK,
|
||||
.status_code = net::HTTP_INTERNAL_SERVER_ERROR,
|
||||
.body = std::nullopt}});
|
||||
return kNonApplicationJsonError.get();
|
||||
}
|
||||
|
||||
using VerifyInitTest = EndpointTest<VerifyInit>;
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_P(VerifyInitTest, HandlesReplies) {
|
||||
RunTestCase();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(VerifyInitTestCases,
|
||||
VerifyInitTest,
|
||||
testing::Values(Success(),
|
||||
ApplicationJsonErrorCodeIsNull(),
|
||||
ApplicationJsonErrorCodeIsNotNull(),
|
||||
NonApplicationJsonError()),
|
||||
VerifyInitTest::kNameGenerator);
|
||||
|
||||
} // namespace brave_account::endpoints
|
||||
Reference in New Issue
Block a user