mirror of
https://github.com/bitwarden/ios.git
synced 2026-02-04 02:14:09 -06:00
BIT-104: Accounts Register Request (#23)
This commit is contained in:
parent
888dfd6941
commit
a1c85ffeed
@ -0,0 +1,57 @@
|
||||
import Foundation
|
||||
import Networking
|
||||
|
||||
// MARK: - CreateAccountRequestModel
|
||||
|
||||
/// The data to include in the body of a `CreateAccountRequest`.
|
||||
///
|
||||
struct CreateAccountRequestModel: Equatable {
|
||||
// MARK: Properties
|
||||
|
||||
/// The captcha response used in validating a user for this request.
|
||||
let captchaResponse: String? = nil
|
||||
|
||||
/// The user's email address.
|
||||
let email: String
|
||||
|
||||
/// The type of kdf for this request.
|
||||
let kdf: KdfType? = nil
|
||||
|
||||
/// The number of kdf iterations performed in this request.
|
||||
let kdfIterations: Int? = nil
|
||||
|
||||
/// The kdf memory allocated for the computed password hash.
|
||||
let kdfMemory: Int? = nil
|
||||
|
||||
/// The number of threads upon which the kdf iterations are performed.
|
||||
let kdfParallelism: Int? = nil
|
||||
|
||||
/// The key used for this request.
|
||||
let key: String? = nil
|
||||
|
||||
/// The keys used for this request.
|
||||
let keys: KeysRequestModel? = nil
|
||||
|
||||
/// The master password hash used to authenticate a user.
|
||||
let masterPasswordHash: String // swiftlint:disable:this inclusive_language
|
||||
|
||||
/// The master password hint.
|
||||
let masterPasswordHint: String? = nil // swiftlint:disable:this inclusive_language
|
||||
|
||||
/// The user's name.
|
||||
let name: String? = nil
|
||||
|
||||
/// The organization's user ID.
|
||||
let organizationUserId: String? = nil
|
||||
|
||||
/// The token used when making this request.
|
||||
let token: String? = nil
|
||||
}
|
||||
|
||||
// MARK: JSONRequestBody
|
||||
|
||||
extension CreateAccountRequestModel: JSONRequestBody {
|
||||
static var encoder: JSONEncoder {
|
||||
JSONEncoder()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
import Foundation
|
||||
import Networking
|
||||
|
||||
// MARK: - CreateAccountResponseModel
|
||||
|
||||
/// The response returned from the API upon creating an account.
|
||||
///
|
||||
struct CreateAccountResponseModel: JSONResponse {
|
||||
static var decoder = JSONDecoder()
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
/// The captcha bypass token returned in this response.
|
||||
var captchaBypassToken: String?
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
import XCTest
|
||||
|
||||
@testable import BitwardenShared
|
||||
|
||||
// MARK: - CreateAccountResponseModelTests
|
||||
|
||||
class CreateAccountResponseModelTests: BitwardenTestCase {
|
||||
/// Tests that a response is initialized correctly.
|
||||
func test_init() {
|
||||
let subject = CreateAccountResponseModel(captchaBypassToken: "captchaBypassToken")
|
||||
XCTAssertEqual(subject.captchaBypassToken, "captchaBypassToken")
|
||||
}
|
||||
|
||||
/// Tests the successful decoding of a JSON response.
|
||||
func test_decode_success() throws {
|
||||
let json = APITestData.createAccountResponse.data
|
||||
let decoder = JSONDecoder()
|
||||
let subject = try decoder.decode(CreateAccountResponseModel.self, from: json)
|
||||
XCTAssertEqual(subject.captchaBypassToken, "captchaBypassToken")
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
extension APITestData {
|
||||
static let createAccountRequest = loadFromBundle(resource: "Request", extension: "json")
|
||||
static let createAccountResponse = loadFromBundle(resource: "Success", extension: "json")
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "name",
|
||||
"email": "email",
|
||||
"masterPasswordHash": "masterPasswordHash",
|
||||
"masterPasswordHint": "masterPasswordHint",
|
||||
"captchaResponse": "captchaResponse",
|
||||
"key": "key",
|
||||
"keys": {
|
||||
"publicKey": "publicKey",
|
||||
"encryptedPrivateKey": "encryptedPrivateKey"
|
||||
},
|
||||
"token": "token",
|
||||
"organizationUserId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
|
||||
"kdf": 0,
|
||||
"kdfIterations": 0,
|
||||
"kdfMemory": 0,
|
||||
"kdfParallelism": 0,
|
||||
"referenceData": {
|
||||
"additionalProp1": "string",
|
||||
"additionalProp2": "string",
|
||||
"additionalProp3": "string"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
{
|
||||
"object": "object",
|
||||
"captchaBypassToken": "captchaBypassToken"
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
// MARK: - KdfType
|
||||
|
||||
/// The type of key derivation function.
|
||||
///
|
||||
enum KdfType: Int, Codable, Equatable {
|
||||
/// The PBKDF2 SHA256 type.
|
||||
case pbkdf2sha256 = 0
|
||||
|
||||
/// The Argon2id type.
|
||||
case argon2id = 1
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
// MARK: - KeysRequestModel
|
||||
|
||||
/// A model for keys used in the `CreateAccountRequest`.
|
||||
///
|
||||
struct KeysRequestModel: Codable, Equatable {
|
||||
// MARK: Properties
|
||||
|
||||
/// The public key used in a `CreateAccountRequest`.
|
||||
var publicKey: String?
|
||||
|
||||
/// The encrypted private key used in a `CreateAccountRequest`.
|
||||
let encryptedPrivateKey: String
|
||||
}
|
||||
@ -1,5 +1,22 @@
|
||||
// MARK: - AccountAPIService
|
||||
|
||||
/// A protocol for an API service used to make account requests.
|
||||
///
|
||||
protocol AccountAPIService {}
|
||||
protocol AccountAPIService {
|
||||
/// Creates an API call for when the user submits an account creation form.
|
||||
///
|
||||
/// - Parameter body: The body to be included in the request.
|
||||
///
|
||||
/// - Returns data returned from the `CreateAccountRequest`.
|
||||
///
|
||||
func createNewAccount(body: CreateAccountRequestModel) async throws -> CreateAccountResponseModel
|
||||
}
|
||||
|
||||
extension APIService: AccountAPIService {}
|
||||
// MARK: - APIService
|
||||
|
||||
extension APIService: AccountAPIService {
|
||||
func createNewAccount(body: CreateAccountRequestModel) async throws -> CreateAccountResponseModel {
|
||||
let request = CreateAccountRequest(body: body)
|
||||
return try await apiService.send(request)
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
import XCTest
|
||||
|
||||
@testable import BitwardenShared
|
||||
|
||||
// MARK: - AccountAPIServiceTests
|
||||
|
||||
class AccountAPIServiceTests: BitwardenTestCase {
|
||||
// MARK: Properties
|
||||
|
||||
var client: MockHTTPClient!
|
||||
var subject: APIService!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
client = MockHTTPClient()
|
||||
subject = APIService(client: client)
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
super.tearDown()
|
||||
client = nil
|
||||
subject = nil
|
||||
}
|
||||
|
||||
// MARK: Account creation
|
||||
|
||||
/// `createNewAccount(email:masterPasswordHash)` throws an error if the request fails.
|
||||
func test_create_account_httpFailure() async {
|
||||
client.result = .httpFailure()
|
||||
|
||||
await assertAsyncThrows {
|
||||
_ = try await subject.createNewAccount(
|
||||
body: CreateAccountRequestModel(
|
||||
email: "example@email.com",
|
||||
masterPasswordHash: "1234"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// `createNewAccount(email:masterPasswordHash)` throws a decoding error if the response is not the expected type.
|
||||
func test_create_account_failure() async throws {
|
||||
let resultData = APITestData(data: Data("this should fail".utf8))
|
||||
client.result = .httpSuccess(testData: resultData)
|
||||
|
||||
await assertAsyncThrows {
|
||||
_ = try await subject.createNewAccount(
|
||||
body: CreateAccountRequestModel(
|
||||
email: "example@email.com",
|
||||
masterPasswordHash: "1234"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// `createNewAccount(email:masterPasswordHash)` returns the correct value from the API with a successful request.
|
||||
func test_create_account_success() async throws {
|
||||
let resultData = APITestData.createAccountResponse
|
||||
client.result = .httpSuccess(testData: resultData)
|
||||
|
||||
let successfulResponse = try await subject.createNewAccount(
|
||||
body: CreateAccountRequestModel(
|
||||
email: "example@email.com",
|
||||
masterPasswordHash: "1234"
|
||||
)
|
||||
)
|
||||
|
||||
let request = try XCTUnwrap(client.requests.first)
|
||||
XCTAssertEqual(request.method, .post)
|
||||
XCTAssertEqual(request.url.relativePath, "/api/accounts/register")
|
||||
XCTAssertEqual(successfulResponse.captchaBypassToken, "captchaBypassToken")
|
||||
XCTAssertNotNil(request.body)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
import Foundation
|
||||
import Networking
|
||||
|
||||
// MARK: - CreateAccountRequest
|
||||
|
||||
/// The API request sent when submitting an account creation form.
|
||||
///
|
||||
struct CreateAccountRequest: Request {
|
||||
typealias Response = CreateAccountResponseModel
|
||||
typealias Body = CreateAccountRequestModel
|
||||
|
||||
/// The body of this request.
|
||||
var body: CreateAccountRequestModel?
|
||||
|
||||
/// The HTTP method for this request.
|
||||
let method: HTTPMethod = .post
|
||||
|
||||
/// The URL path for this request.
|
||||
var path: String = "/accounts/register"
|
||||
|
||||
/// Creates a new `CreateAccountRequest` instance.
|
||||
///
|
||||
/// - Parameter body: The body of the request.
|
||||
///
|
||||
init(body: CreateAccountRequestModel) {
|
||||
self.body = body
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
import XCTest
|
||||
|
||||
@testable import BitwardenShared
|
||||
|
||||
// MARK: - CreateAccountRequestTests
|
||||
|
||||
class CreateAccountRequestTests: BitwardenTestCase {
|
||||
/// Validate that the method is correct.
|
||||
func test_method() {
|
||||
let subject = CreateAccountRequest(
|
||||
body: CreateAccountRequestModel(
|
||||
email: "email@example.com",
|
||||
masterPasswordHash: "1234"
|
||||
)
|
||||
)
|
||||
XCTAssertEqual(subject.method, .post)
|
||||
}
|
||||
|
||||
/// Validate that the path is correct.
|
||||
func test_path() {
|
||||
let subject = CreateAccountRequest(
|
||||
body: CreateAccountRequestModel(
|
||||
email: "email@example.com",
|
||||
masterPasswordHash: "1234"
|
||||
)
|
||||
)
|
||||
XCTAssertEqual(subject.path, "/accounts/register")
|
||||
}
|
||||
|
||||
/// Validate that the body is not nil.
|
||||
func test_body() {
|
||||
let subject = CreateAccountRequest(
|
||||
body: CreateAccountRequestModel(
|
||||
email: "email@example.com",
|
||||
masterPasswordHash: "1234"
|
||||
)
|
||||
)
|
||||
XCTAssertNotNil(subject.body)
|
||||
}
|
||||
|
||||
// MARK: Init
|
||||
|
||||
/// Validate that the value provided to the init method is correct.
|
||||
func test_init_body() {
|
||||
let subject = CreateAccountRequest(
|
||||
body: CreateAccountRequestModel(
|
||||
email: "email@example.com",
|
||||
masterPasswordHash: "1234"
|
||||
)
|
||||
)
|
||||
XCTAssertEqual(subject.body?.email, "email@example.com")
|
||||
XCTAssertEqual(subject.body?.masterPasswordHash, "1234")
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user