// // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only // import Foundation public extension OWSRequestFactory { private enum UsernameApiPaths { static let reserveUsername = "v1/accounts/username_hash/reserve" static let confirmReservedUsername = "v1/accounts/username_hash/confirm" static let deleteUsername = "v1/accounts/username_hash" static func aciLookup(forUsernameHash usernameHash: String) -> String { "v1/accounts/username_hash/\(usernameHash)" } static let setUsernameLink = "v1/accounts/username_link" } /// Attempt to reserve one of the given username hashes. If successful, /// will return the reserved hash. /// /// A successful reservation is valid for 5 minutes. static func reserveUsernameRequest( usernameHashes: [String], ) -> TSRequest { let url = URL(string: UsernameApiPaths.reserveUsername)! let params: [String: Any] = [ "usernameHashes": usernameHashes, ] return TSRequest( url: url, method: HTTPMethod.put.methodName, parameters: params, ) } /// Confirm a previously-reserved username hash. /// /// - Parameter reservedUsernameHash /// The hash string from a hashed username returned by a prior call to /// reserve a desired nickname. /// - Parameter reservedUsernameZKProof /// The zkproof string from a hashed username returned by a prior call to /// reserve a desired nickname. /// - Parameter encryptedUsernameForLink /// An encrypted form of the reserved username to be used in a username /// link. static func confirmReservedUsernameRequest( reservedUsernameHash hashString: String, reservedUsernameZKProof proofString: String, encryptedUsernameForLink: Data, ) -> TSRequest { let url = URL(string: UsernameApiPaths.confirmReservedUsername)! let params: [String: String] = [ "usernameHash": hashString, "zkProof": proofString, "encryptedUsername": encryptedUsernameForLink.asBase64Url, ] return TSRequest( url: url, method: HTTPMethod.put.methodName, parameters: params, ) } /// Delete the user's server-stored username hash. static func deleteExistingUsernameRequest() -> TSRequest { let url = URL(string: UsernameApiPaths.deleteUsername)! return TSRequest( url: url, method: HTTPMethod.delete.methodName, parameters: nil, ) } /// Look up the ACI for the given username hash. static func lookupAciUsernameRequest( usernameHashToLookup usernameHash: String, ) -> TSRequest { let url = URL(string: UsernameApiPaths.aciLookup( forUsernameHash: usernameHash, ))! var request = TSRequest( url: url, method: HTTPMethod.get.methodName, parameters: nil, ) request.auth = .anonymous return request } /// Store the given encrypted username for use in the authenticated user's /// username link. Optionally requests that the service not rotate the /// handle for this username link. /// /// - SeeAlso /// ``Usernames.UsernameLink`` and ``UsernameLinkManager``. static func setUsernameLinkRequest( encryptedUsername: Data, keepLinkHandle: Bool, ) -> TSRequest { let url = URL(string: UsernameApiPaths.setUsernameLink)! let params: [String: Any] = [ "usernameLinkEncryptedValue": encryptedUsername.asBase64Url, "keepLinkHandle": keepLinkHandle, ] let request = TSRequest( url: url, method: HTTPMethod.put.methodName, parameters: params, ) return request } }