blob: bb1dfcfb95e241bd4169b71bd57141eae9eab7c7 [file] [log] [blame]
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
import Foundation
import TeaclaveClientSDK.CTeaclaveClientSDK
public enum TeaclaveClientError: Error {
case userLoginError
case userRegisterError
case setCredentialError
case registerFunctionError
case createTaskError
case invokeTaskError
case getTaskResultError
case registerInputFileError
case registerOutputFileError
case assignDataError
case approveTaskError
}
public struct RegisterFunctionRequest: Encodable {
public let request: String = "register_function_request"
public let name: String
public let description: String
public let executor_type: String
public let `public`: Bool = true
public let payload: [Int]
public let arguments: Set<String>
public let inputs: [[String: String]]
public let outputs: [[String: String]]
public init(name: String, description: String, executor_type: String, payload: [Int], arguments: Set<String>, inputs: [[String: String]], outputs: [[String: String]]) {
self.name = name
self.description = description
self.executor_type = executor_type
self.payload = payload
self.arguments = arguments
self.inputs = inputs
self.outputs = outputs
}
}
public struct RegisterFunctionResponse: Codable {
public let function_id: String
public init(function_id: String) {
self.function_id = function_id
}
}
public struct OwnerList: Encodable {
public let data_name: String
public let uids: [String]
public init(data_name: String, uids: [String]) {
self.data_name = data_name
self.uids = uids
}
}
public struct CreateTaskRequest: Encodable {
public let request: String = "register_create_task"
public let function_id: String
public let function_arguments: String
public let executor: String
public let inputs_ownership: [OwnerList]
public let outputs_ownership: [OwnerList]
public init(function_id: String, function_arguments: String, executor: String, inputs_ownership: [OwnerList], outputs_ownership: [OwnerList]) {
self.function_id = function_id
self.function_arguments = function_arguments
self.executor = executor
self.inputs_ownership = inputs_ownership
self.outputs_ownership = outputs_ownership
}
}
public struct CreateTaskResponse: Codable {
public let task_id: String
public init(task_id: String) {
self.task_id = task_id
}
}
public struct CryptoInfo: Codable {
public let schema: String
public let key: [Int]
public let iv: [Int]
public init(schema: String, key: [Int], iv: [Int]) {
self.schema = schema
self.key = key
self.iv = iv
}
}
public struct RegisterInputFileRequest: Encodable {
public let request: String = "register_input_file"
public let url: String
public let cmac: [Int]
public let crypto_info: CryptoInfo
public init(url: String, cmac: [Int], crypto_info: CryptoInfo) {
self.url = url
self.cmac = cmac
self.crypto_info = crypto_info
}
}
public struct RegisterInputFileResponse: Codable {
public let data_id: String
public init(data_id: String) {
self.data_id = data_id
}
}
public struct RegisterOutputFileRequest: Encodable {
public let request: String = "register_output_file"
public let url: String
public let cmac: [Int]
public let crypto_info: CryptoInfo
public init(url: String, cmac: [Int], crypto_info: CryptoInfo) {
self.url = url
self.cmac = cmac
self.crypto_info = crypto_info
}
}
public struct RegisterOutputFileResponse: Codable {
public let data_id: String
public init(data_id: String) {
self.data_id = data_id
}
}
public struct DataMap: Codable {
public let data_name: String
public let data_id: String
public init(data_name: String, data_id: String) {
self.data_name = data_name
self.data_id = data_id
}
}
public struct AssignDataRequest: Encodable {
public let request: String = "assign_data"
public let task_id: String
public let inputs: [DataMap]
public let outputs: [DataMap]
public init(task_id: String, inputs: [DataMap], outputs: [DataMap]) {
self.task_id = task_id
self.inputs = inputs
self.outputs = outputs
}
}
public struct ApproveTaskRequest: Encodable {
public let request: String = "approve_task"
public let task_id: String
public init(task_id: String) {
self.task_id = task_id
}
}
public class AuthenticationClient {
internal let cClient: OpaquePointer
public init?(address: String, enclave_info_path: String, as_root_ca_cert_path: String) {
let address_c_string = address.cString(using: .ascii)
let enclave_info_path_address_c_string = enclave_info_path.cString(using: .ascii)
let as_root_ca_cert_c_string = as_root_ca_cert_path.cString(using: .ascii)
let cClient = teaclave_connect_authentication_service(address_c_string, enclave_info_path_address_c_string, as_root_ca_cert_c_string)
guard let client = cClient else {
return nil
}
self.cClient = client
}
public func register(id: String, password: String) -> Result<Void, TeaclaveClientError> {
let id_c_string = id.cString(using: .ascii)
let password_c_string = password.cString(using: .ascii)
let ret = teaclave_user_register(cClient, id_c_string, password_c_string)
guard ret == 0 else {
return Result.failure(.userRegisterError)
}
return Result.success(())
}
public func login(id: String, password: String) -> Result<String, TeaclaveClientError> {
let id_c_string = id.cString(using: .ascii)
let password_c_string = password.cString(using: .ascii)
let token_c_string = UnsafeMutablePointer<CChar>.allocate(capacity: 1024)
let token_len = UnsafeMutablePointer<Int>.allocate(capacity: 1)
token_len.pointee = 1024
let ret = teaclave_user_login(cClient, id_c_string, password_c_string, token_c_string, token_len)
guard ret == 0 else {
token_c_string.deallocate()
token_len.deallocate()
return Result.failure(.userLoginError)
}
let token = String(cString: token_c_string)
token_c_string.deallocate()
token_len.deallocate()
return Result.success(token)
}
deinit {
teaclave_close_authentication_service(cClient)
}
}
public class FrontendClient {
internal let cClient: OpaquePointer
public init?(address: String, enclave_info_path: String, as_root_ca_cert_path: String) {
let address_c_string = address.cString(using: .ascii)
let enclave_info_path_address_c_string = enclave_info_path.cString(using: .ascii)
let as_root_ca_cert_c_string = as_root_ca_cert_path.cString(using: .ascii)
let cClient = teaclave_connect_frontend_service(address_c_string, enclave_info_path_address_c_string, as_root_ca_cert_c_string)
guard let client = cClient else {
return nil
}
self.cClient = client
}
deinit {
teaclave_close_frontend_service(cClient)
}
public func set_credential(id: String, token: String) -> Result<Void, TeaclaveClientError> {
let id_c_string = id.cString(using: .ascii)
let token_c_string = token.cString(using: .ascii)
let ret = teaclave_set_credential(cClient, id_c_string, token_c_string)
guard ret == 0 else {
return Result.failure(.setCredentialError)
}
return Result.success(())
}
public func register_function(with request: RegisterFunctionRequest) -> Result<RegisterFunctionResponse, TeaclaveClientError> {
let data = try! JSONEncoder().encode(request)
let json_string = String(data: data, encoding: .ascii)!
let request_c_string = json_string.cString(using: .ascii)
let response_c_string = UnsafeMutablePointer<CChar>.allocate(capacity: 1024)
let response_len = UnsafeMutablePointer<Int>.allocate(capacity: 1)
response_len.pointee = 1024
let ret = teaclave_register_function_serialized(cClient, request_c_string, response_c_string, response_len)
guard ret == 0 else {
return Result.failure(.registerFunctionError)
}
let response_string = String(cString: response_c_string)
let response = try! JSONDecoder().decode(RegisterFunctionResponse.self, from: response_string.data(using: .ascii)!)
return Result.success(response)
}
public func create_task(with request: CreateTaskRequest) -> Result<CreateTaskResponse, TeaclaveClientError> {
let data = try! JSONEncoder().encode(request)
let json_string = String(data: data, encoding: .ascii)!
let request_c_string = json_string.cString(using: .ascii)
let response_c_string = UnsafeMutablePointer<CChar>.allocate(capacity: 10240)
let response_len = UnsafeMutablePointer<Int>.allocate(capacity: 1)
response_len.pointee = 10240
let ret = teaclave_create_task_serialized(cClient, request_c_string, response_c_string, response_len)
guard ret == 0 else {
return Result.failure(.createTaskError)
}
let response_string = String(cString: response_c_string)
let response = try! JSONDecoder().decode(CreateTaskResponse.self, from: response_string.data(using: .ascii)!)
return Result.success(response)
}
public func register_input_file(with request: RegisterInputFileRequest) -> Result<RegisterInputFileResponse, TeaclaveClientError> {
let data = try! JSONEncoder().encode(request)
let json_string = String(data: data, encoding: .ascii)!
let request_c_string = json_string.cString(using: .ascii)
let response_c_string = UnsafeMutablePointer<CChar>.allocate(capacity: 10240)
let response_len = UnsafeMutablePointer<Int>.allocate(capacity: 1)
response_len.pointee = 10240
let ret = teaclave_register_input_file_serialized(cClient, request_c_string, response_c_string, response_len)
guard ret == 0 else {
return Result.failure(.registerInputFileError)
}
let response_string = String(cString: response_c_string)
let response = try! JSONDecoder().decode(RegisterInputFileResponse.self, from: response_string.data(using: .ascii)!)
return Result.success(response)
}
public func register_output_file(with request: RegisterOutputFileRequest) -> Result<RegisterOutputFileResponse, TeaclaveClientError> {
let data = try! JSONEncoder().encode(request)
let json_string = String(data: data, encoding: .ascii)!
let request_c_string = json_string.cString(using: .ascii)
let response_c_string = UnsafeMutablePointer<CChar>.allocate(capacity: 10240)
let response_len = UnsafeMutablePointer<Int>.allocate(capacity: 1)
response_len.pointee = 10240
let ret = teaclave_register_output_file_serialized(cClient, request_c_string, response_c_string, response_len)
guard ret == 0 else {
return Result.failure(.registerOutputFileError)
}
let response_string = String(cString: response_c_string)
let response = try! JSONDecoder().decode(RegisterOutputFileResponse.self, from: response_string.data(using: .ascii)!)
return Result.success(response)
}
public func assign_data(with request: AssignDataRequest) -> Result<Void, TeaclaveClientError> {
let data = try! JSONEncoder().encode(request)
let json_string = String(data: data, encoding: .ascii)!
let request_c_string = json_string.cString(using: .ascii)
let response_c_string = UnsafeMutablePointer<CChar>.allocate(capacity: 10240)
let response_len = UnsafeMutablePointer<Int>.allocate(capacity: 1)
response_len.pointee = 10240
let ret = teaclave_assign_data_serialized(cClient, request_c_string, response_c_string, response_len)
guard ret == 0 else {
return Result.failure(.assignDataError)
}
return Result.success(())
}
public func invoke_task(task_id: String) -> Result<Void, TeaclaveClientError> {
let task_id_c_string = task_id.cString(using: .ascii)
let ret = teaclave_invoke_task(cClient, task_id_c_string)
guard ret == 0 else {
return Result.failure(.invokeTaskError)
}
return Result.success(())
}
public func approve_task(task_id: String) -> Result<Void, TeaclaveClientError> {
let request = ApproveTaskRequest(task_id: task_id)
let data = try! JSONEncoder().encode(request)
let json_string = String(data: data, encoding: .ascii)!
let request_c_string = json_string.cString(using: .ascii)
let response_c_string = UnsafeMutablePointer<CChar>.allocate(capacity: 10240)
let response_len = UnsafeMutablePointer<Int>.allocate(capacity: 1)
response_len.pointee = 10240
let ret = teaclave_approve_task_serialized(cClient, request_c_string, response_c_string, response_len)
guard ret == 0 else {
return Result.failure(.approveTaskError)
}
return Result.success(())
}
public func get_task_result(task_id: String) -> Result<String, TeaclaveClientError> {
let task_id_c_string = task_id.cString(using: .ascii)
let response_c_string = UnsafeMutablePointer<CChar>.allocate(capacity: 10240)
let response_len = UnsafeMutablePointer<Int>.allocate(capacity: 1)
response_len.pointee = 10240
let ret = teaclave_get_task_result(cClient, task_id_c_string, response_c_string, response_len)
guard ret == 0 else {
return Result.failure(.getTaskResultError)
}
return Result.success(String(cString: response_c_string))
}
}