mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-02-08 03:50:28 +00:00
Add a swift-client-api subdirectory containing a Swift source package and a Makefile.in that compiles it into the "ServalClient" Swift module using the Swift package manager. The Swift API contains the following classes: - ServalKeyring provides the operations: add, remove, set, list - AbstractId and its specialisation SubscriberId, already in near-final form, are data types for SID and the like - ServalRestfulClient (internal) uses an HTTP client to access the Serval DNA RESTful interface Improve the REST /keyring/set operation to only alter the DID or Name if the corresponding query parameter is supplied. Modify the internal keyring_set_did() function to only assign the DID or Name if the corresponding parameter is not a null pointer. The configure script ensures that the Swift build target version is 10.10 or later when compiling for Mac OS-X, so that the package manager will succeed. Add autoconf macros for the Swift package manager.
241 lines
11 KiB
Swift
241 lines
11 KiB
Swift
/*
|
|
Serval DNA Swift API
|
|
Copyright (C) 2016 Flinders University
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
import Foundation
|
|
|
|
public class ServalKeyring {
|
|
|
|
public struct Identity {
|
|
public let sid : SubscriberId
|
|
public let identity : SubscriberId
|
|
public let did : String?
|
|
public let name : String?
|
|
}
|
|
|
|
public static func listIdentities(client: ServalRestfulClient = ServalRestfulClient(),
|
|
pin: String? = nil,
|
|
completionHandler: @escaping ([Identity]?, Error?) -> Void)
|
|
-> ServalRestfulClient.Request
|
|
{
|
|
var param = [String: String]()
|
|
if pin != nil { param["pin"] = pin }
|
|
return client.createRequest(path: "restful/keyring/identities.json",
|
|
query: param) { (statusCode, json, error) in
|
|
if let error = error {
|
|
completionHandler(nil, error)
|
|
return
|
|
}
|
|
guard statusCode! == 200 else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.requestFailed(statusCode: statusCode!))
|
|
return
|
|
}
|
|
guard let json_top = json as? [String: Any] else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "root is not JSON object"))
|
|
return
|
|
}
|
|
var column_count = 0
|
|
var sid_index = -1
|
|
var identity_index = -1
|
|
var did_index = -1
|
|
var name_index = -1
|
|
guard let header = json_top["header"] as? [String] else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "missing 'header' element"))
|
|
return
|
|
}
|
|
for text in header {
|
|
if text == "sid" {
|
|
sid_index = column_count
|
|
}
|
|
else if text == "identity" {
|
|
identity_index = column_count
|
|
}
|
|
else if text == "did" {
|
|
did_index = column_count
|
|
}
|
|
else if text == "name" {
|
|
name_index = column_count
|
|
}
|
|
column_count += 1
|
|
}
|
|
guard sid_index != -1 else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "missing 'sid' column"))
|
|
return
|
|
}
|
|
guard identity_index != -1 else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "missing 'identity' column"))
|
|
return
|
|
}
|
|
guard let rows = json_top["rows"] as? [[Any]] else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "missing 'rows' element"))
|
|
return
|
|
}
|
|
var identities : [Identity] = []
|
|
for row in rows {
|
|
guard row.count == column_count else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "row has \(row.count) elements; should be \(column_count)"))
|
|
return
|
|
}
|
|
var opt_sid : SubscriberId?
|
|
var opt_identity : SubscriberId?
|
|
var did : String?
|
|
var name : String?
|
|
if sid_index != -1 {
|
|
guard let hex = row[sid_index] as? String else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "sid value is not String"))
|
|
return
|
|
}
|
|
opt_sid = SubscriberId(fromHex: hex)
|
|
guard opt_sid != nil else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "sid value is not hex: \(hex)"))
|
|
return
|
|
}
|
|
}
|
|
if identity_index != -1 {
|
|
guard let hex = row[identity_index] as? String else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "identity value is not String"))
|
|
return
|
|
}
|
|
opt_identity = SubscriberId(fromHex: hex)
|
|
guard opt_sid != nil else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "identity value is not hex: \(hex)"))
|
|
return
|
|
}
|
|
}
|
|
if did_index != -1 {
|
|
let value = row[did_index]
|
|
if value as? NSNull == nil {
|
|
guard let text = value as? String else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "did value is not String: \(value)"))
|
|
return
|
|
}
|
|
if !text.isEmpty {
|
|
did = text
|
|
}
|
|
}
|
|
}
|
|
if name_index != -1 {
|
|
let value = row[name_index]
|
|
if value as? NSNull == nil {
|
|
guard let text = value as? String else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "name value is not String: \(value)"))
|
|
return
|
|
}
|
|
if !text.isEmpty {
|
|
name = text
|
|
}
|
|
}
|
|
}
|
|
identities.append(Identity(sid: opt_sid!, identity: opt_identity!, did: did, name: name))
|
|
}
|
|
completionHandler(identities, nil)
|
|
}!
|
|
}
|
|
|
|
private static func singleIdentityRequest(client: ServalRestfulClient = ServalRestfulClient(),
|
|
path: String,
|
|
query: [String: String] = [:],
|
|
successStatusCodes: Set<Int> = [200],
|
|
completionHandler: @escaping (Identity?, Error?) -> Void)
|
|
-> ServalRestfulClient.Request
|
|
{
|
|
return client.createRequest(path: path, query: query) { (statusCode, json, error) in
|
|
if let error = error {
|
|
completionHandler(nil, error)
|
|
return
|
|
}
|
|
guard successStatusCodes.contains(statusCode!) else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.requestFailed(statusCode: statusCode!))
|
|
return
|
|
}
|
|
guard let json_top = json as? [String: Any] else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "root is not JSON object"))
|
|
return
|
|
}
|
|
guard let json_identity = json_top["identity"] as? [String: Any] else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "'identity' is not JSON object"))
|
|
return
|
|
}
|
|
guard let sid_hex = json_identity["sid"] as? String else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "'sid' is not String"))
|
|
return
|
|
}
|
|
guard let identity_hex = json_identity["identity"] as? String else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "'identity' is not String"))
|
|
return
|
|
}
|
|
guard let sid = SubscriberId(fromHex: sid_hex) else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "invalid 'sid': \(sid_hex)"))
|
|
return
|
|
}
|
|
guard let identity = SubscriberId(fromHex: identity_hex) else {
|
|
completionHandler(nil, ServalRestfulClient.Exception.invalidJson(reason: "invalid 'identity': \(identity_hex)"))
|
|
return
|
|
}
|
|
let did = json_identity["did"] as? String ?? ""
|
|
let name = json_identity["name"] as? String ?? ""
|
|
completionHandler(Identity(sid: sid, identity: identity, did: did, name: name), nil)
|
|
}!
|
|
}
|
|
|
|
public static func addIdentity(client: ServalRestfulClient = ServalRestfulClient(),
|
|
did: String? = nil,
|
|
name: String? = nil,
|
|
pin: String? = nil,
|
|
completionHandler: @escaping (Identity?, Error?) -> Void)
|
|
-> ServalRestfulClient.Request
|
|
{
|
|
var param = [String: String]()
|
|
if did != nil { param["did"] = did }
|
|
if name != nil { param["name"] = name }
|
|
if pin != nil { param["pin"] = pin }
|
|
return self.singleIdentityRequest(client: client,
|
|
path: "restful/keyring/add",
|
|
query: param,
|
|
successStatusCodes: [201],
|
|
completionHandler: completionHandler)
|
|
}
|
|
|
|
public static func removeIdentity(client: ServalRestfulClient = ServalRestfulClient(),
|
|
sid: SubscriberId,
|
|
pin: String? = nil,
|
|
completionHandler: @escaping (Identity?, Error?) -> Void)
|
|
-> ServalRestfulClient.Request
|
|
{
|
|
var param = [String: String]()
|
|
if pin != nil { param["pin"] = pin }
|
|
return self.singleIdentityRequest(client: client, path: "restful/keyring/\(sid.hexUpper)/remove", query: param, completionHandler: completionHandler)
|
|
}
|
|
|
|
public static func setIdentity(client: ServalRestfulClient = ServalRestfulClient(),
|
|
sid: SubscriberId,
|
|
did: String? = nil,
|
|
name: String? = nil,
|
|
pin: String? = nil,
|
|
completionHandler: @escaping (Identity?, Error?) -> Void)
|
|
-> ServalRestfulClient.Request
|
|
{
|
|
var param = [String: String]()
|
|
if did != nil { param["did"] = did }
|
|
if name != nil { param["name"] = name }
|
|
if pin != nil { param["pin"] = pin }
|
|
return self.singleIdentityRequest(client: client, path: "restful/keyring/\(sid.hexUpper)/set", query: param, completionHandler: completionHandler)
|
|
}
|
|
|
|
}
|