Skip to content

Commit

Permalink
feat(pluto): pluto will save link secret as a storable key.
Browse files Browse the repository at this point in the history
BREAKING CHANGE: This makes changes on pluto interface.
  • Loading branch information
goncalo-frade-iohk committed Dec 16, 2023
1 parent f4a4a80 commit 5d25580
Show file tree
Hide file tree
Showing 26 changed files with 273 additions and 116 deletions.
13 changes: 13 additions & 0 deletions AtalaPrismSDK/Apollo/Sources/ApolloImpl+KeyRestoration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ extension ApolloImpl: KeyRestoration {
identifier.hasSuffix("pub")
}

public func isKeyData(identifier: String, data: Data) throws -> Bool {
identifier.hasSuffix("key")
}

public func restorePrivateKey(_ key: StorableKey) throws -> PrivateKey {
switch key.restorationIdentifier {
case "secp256k1+priv":
Expand Down Expand Up @@ -38,4 +42,13 @@ extension ApolloImpl: KeyRestoration {
throw ApolloError.restoratonFailedNoIdentifierOrInvalid
}
}

public func restoreKey(_ key: StorableKey) async throws -> Key {
switch key.restorationIdentifier {
case "linkSecret+key":
return try LinkSecret(data: key.storableData)
default:
throw ApolloError.restoratonFailedNoIdentifierOrInvalid
}
}
}
4 changes: 2 additions & 2 deletions AtalaPrismSDK/Apollo/Sources/ApolloImpl+Public.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ returns random mnemonics nerver returns invalid mnemonics
}
}

public func createNewLinkSecret() throws -> String {
try CreateLinkSecretOperation().create()
public func createNewLinkSecret() throws -> Key {
try LinkSecret()
}
}
47 changes: 47 additions & 0 deletions AtalaPrismSDK/Apollo/Sources/Model/LinkSecret.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import AnoncredsSwift
import Domain
import Foundation

struct LinkSecret: Key {
let keyType = "LinkSecret"
let keySpecifications = [String : String]()
let raw: Data
var size: Int { raw.count }

let anoncred: AnoncredsSwift.LinkSecret

init(string: String) throws {
self.anoncred = try AnoncredsSwift.LinkSecret.newFromValue(valueString: string)
guard let strData = string.data(using: .utf8) else {
throw CommonError.invalidCoding(message: "Could not encode LinkSecret in Data")
}
self.raw = strData
}

init(data: Data) throws {
guard let str = String(data: data, encoding: .utf8) else {
throw CommonError.invalidCoding(message: "Could not encode LinkSecret in String")
}
self.anoncred = try AnoncredsSwift.LinkSecret.newFromValue(valueString: str)
self.raw = data
}

init() throws {
let anoncred = Prover().createLinkSecret()
self.anoncred = anoncred
guard let strData = try anoncred.getValue().data(using: .utf8) else {
throw CommonError.invalidCoding(message: "Could not encode LinkSecret in Data")
}
self.raw = strData
}
}

extension LinkSecret: KeychainStorableKey {
var restorationIdentifier: String { "linkSecret+key" }
var storableData: Data { raw }
var index: Int? { nil }
var type: Domain.KeychainStorableKeyProperties.KeyAlgorithm { .rawKey }
var keyClass: Domain.KeychainStorableKeyProperties.KeyType { .privateKey }
var accessiblity: Domain.KeychainStorableKeyProperties.Accessability? { .firstUnlock(deviceOnly: true) }
var synchronizable: Bool { false }
}

This file was deleted.

5 changes: 4 additions & 1 deletion AtalaPrismSDK/Domain/Sources/BBs/Apollo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,8 @@ public protocol Apollo {
/// - Returns: The decompressed public key
func uncompressedPublicKey(compressedData: Data) -> PublicKey

func createNewLinkSecret() throws -> String
/// createNewLinkSecret creates a link secret.
///
/// - Returns: A key that represents the link secret
func createNewLinkSecret() throws -> Key
}
4 changes: 2 additions & 2 deletions AtalaPrismSDK/Domain/Sources/BBs/Pluto.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public protocol Pluto {
credential: StorableCredential
) -> AnyPublisher<Void, Error>

func storeLinkSecret(secret: String) -> AnyPublisher<Void, Error>
func storeLinkSecret(secret: StorableKey) -> AnyPublisher<Void, Error>

/// Returns all stored PRISM DIDs, along with their associated key pair indices and aliases (if any).
/// - Returns: A publisher that emits an array of tuples representing the stored PRISM DIDs, along with their associated key pair indices and aliases (if any).
Expand Down Expand Up @@ -217,5 +217,5 @@ public protocol Pluto {
/// - Returns: A publisher that emits an array of stored verifiable credentials.
func getAllCredentials() -> AnyPublisher<[StorableCredential], Error>

func getLinkSecret() -> AnyPublisher<[String], Error>
func getLinkSecret() -> AnyPublisher<[StorableKey], Error>
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ public protocol KeyRestoration {
/// - Returns: A boolean value indicating whether the data represents a public key (true) or not (false).
func isPublicKeyData(identifier: String, data: Data) throws -> Bool

/// Determines if the given data corresponds to a key.
/// - Parameters:
/// - identifier: An optional string used to identify the key.
/// - data: The raw data potentially representing the key.
/// - Throws: If the verification process fails, this method throws an error.
/// - Returns: A boolean value indicating whether the data represents a key (true) or not (false).
func isKeyData(identifier: String, data: Data) throws -> Bool

/// Restores a private key from the given data.
/// - Parameters:
/// - identifier: An optional string used to identify the key.
Expand All @@ -33,4 +41,12 @@ public protocol KeyRestoration {
/// - Throws: If the restoration process fails, this method throws an error.
/// - Returns: The restored `PublicKey` instance.
func restorePublicKey(_ key: StorableKey) async throws -> PublicKey

/// Restores a key from the given data.
/// - Parameters:
/// - identifier: An optional string used to identify the key.
/// - data: The raw data representing the key.
/// - Throws: If the restoration process fails, this method throws an error.
/// - Returns: The restored `Key` instance.
func restoreKey(_ key: StorableKey) async throws -> Key
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Combine
import Domain
import Foundation

protocol LinkSecretProvider {
func getAll() -> AnyPublisher<[String], Error>
func getAll() -> AnyPublisher<[StorableKey], Error>
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Combine
import Domain
import Foundation

protocol LinkSecretStore {
func addLinkSecret(_ linkSecret: String) -> AnyPublisher<Void, Error>
func addLinkSecret(_ linkSecret: StorableKey) -> AnyPublisher<Void, Error>
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ extension CDDIDPrivateKeyDAO: DIDPrivateKeyProvider {
try $0.map {
(
DID(from: $0),
try $0.keys.map { try $0.parseToStorableKey(keychain: self.keychain) },
try $0.keys.map { try $0.parseToStorableKey(keychain: self.keyDao.keychain) },
$0.alias
)
}
Expand All @@ -24,7 +24,7 @@ extension CDDIDPrivateKeyDAO: DIDPrivateKeyProvider {
try $0.map {
(
DID(from: $0),
try $0.keys.map { try $0.parseToStorableKey(keychain: self.keychain) },
try $0.keys.map { try $0.parseToStorableKey(keychain: self.keyDao.keychain) },
$0.alias
)
}
Expand All @@ -41,7 +41,7 @@ extension CDDIDPrivateKeyDAO: DIDPrivateKeyProvider {
try $0.map {
(
DID(from: $0),
try $0.keys.map { try $0.parseToStorableKey(keychain: self.keychain) },
try $0.keys.map { try $0.parseToStorableKey(keychain: self.keyDao.keychain) },
$0.alias
)
}
Expand All @@ -52,7 +52,7 @@ extension CDDIDPrivateKeyDAO: DIDPrivateKeyProvider {
func getPrivateKeys(did: DID) -> AnyPublisher<[StorableKey]?, Error> {
fetchByIDsPublisher(did.string, context: readContext)
.tryMap {
try $0?.keys.map { try $0.parseToStorableKey(keychain: self.keychain) }
try $0?.keys.map { try $0.parseToStorableKey(keychain: self.keyDao.keychain) }
}
.eraseToAnyPublisher()
}
Expand All @@ -68,42 +68,3 @@ extension CDDIDPrivateKeyDAO: DIDPrivateKeyProvider {
.eraseToAnyPublisher()
}
}

extension CDKey {
func parseToStorableKey(keychain: KeychainProvider) throws -> StorableKey {
switch self {
case let keychainKey as CDKeychainKey:
guard
let algortihm = KeychainStorableKeyProperties.KeyAlgorithm(rawValue: keychainKey.algorithm),
let keyType = KeychainStorableKeyProperties.KeyType(rawValue: keychainKey.type)
else {
// TODO: Update this error
throw PlutoError.algorithmOrKeyTypeNotValid(algorithm: keychainKey.algorithm, keyType: keychainKey.type)
}
let keyData = try keychain.getKey(
service: keychainKey.service,
account: keychainKey.identifier,
tag: keychainKey.tag,
algorithm: algortihm,
type: keyType
)

return StorableKeyModel(
restorationIdentifier: keychainKey.restorationIdentifier,
storableData: keyData,
index: keychainKey.index?.intValue
)
case let databaseKey as CDDatabaseKey:
return StorableKeyModel(
restorationIdentifier: databaseKey.restorationIdentifier,
storableData: databaseKey.storableData,
index: databaseKey.index?.intValue
)
default:
throw UnknownError.somethingWentWrongError(
customMessage: "This should never happen it a key always have a type of CDKeychainKey or CDDatabaseKey",
underlyingErrors: nil
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ extension CDDIDPrivateKeyDAO: DIDPrivateKeyStore {
try storeKeychainKey(
did: did,
keychainKey: keychainKey,
service: self.keychainService,
service: self.keyDao.keychainService,
account: identifier,
keychain: self.keychain
keychain: self.keyDao.keychain
)
let cdkey = CDKeychainKey(entity: CDKeychainKey.entity(), insertInto: context)
cdkey.parseFromStorableKey(
keychainKey,
did: cdobj,
identifier: identifier,
service: self.keychainService
service: self.keyDao.keychainService
)
return cdkey as CDKey
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import Domain

struct CDDIDPrivateKeyDAO: CoreDataDAO {
typealias CoreDataObject = CDDIDPrivateKey
let keychain: KeychainStore & KeychainProvider
let keychainService: String
let keyDao: CDKeyDAO
let readContext: NSManagedObjectContext
let writeContext: NSManagedObjectContext
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Combine
import Foundation
import Domain

extension CDKeyDAO: LinkSecretProvider {
func getAll() -> AnyPublisher<[StorableKey], Error> {
fetchController(context: readContext)
.tryMap { try $0.map { try $0.parseToStorableKey(keychain: self.keychain) } }
.eraseToAnyPublisher()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import Combine
import CoreData
import Domain

extension CDKeyDAO: LinkSecretStore {
func addLinkSecret(_ linkSecret: StorableKey) -> AnyPublisher<Void, Error> {
updateOrCreate("linkSecret", context: writeContext) { cdobj, context in
switch linkSecret {
case let keychainKey as KeychainStorableKey:
try storeKeychainKey(
keychainKey: keychainKey,
service: self.keychainService,
account: "linkSecret",
keychain: self.keychain
)
let cdkey = CDKeychainKey(entity: CDKeychainKey.entity(), insertInto: context)
cdkey.parseFromStorableKey(
keychainKey,
identifier: "linkSecret",
service: self.keychainService
)
default:
let cdkey = CDDatabaseKey(entity: CDDatabaseKey.entity(), insertInto: context)
cdkey.parseFromStorableKey(
linkSecret,
identifier: "linkSecret"
)
}
}
.map { _ in }
.eraseToAnyPublisher()
}
}

private func storeKeychainKey(
keychainKey: KeychainStorableKey,
service: String,
account: String,
keychain: KeychainStore
) throws {
try keychain.addKey(
keychainKey,
service: service,
account: account
)
}

private extension CDDatabaseKey {
func parseFromStorableKey(
_ key: StorableKey,
identifier: String
) {
self.identifier = identifier
self.storableData = key.storableData
self.index = key.index.map { NSNumber(integerLiteral: $0) }
self.restorationIdentifier = key.restorationIdentifier
}
}

private extension CDKeychainKey {
func parseFromStorableKey(
_ key: KeychainStorableKey,
identifier: String,
service: String
) {
self.identifier = identifier
self.restorationIdentifier = key.restorationIdentifier
self.index = key.index.map { NSNumber(integerLiteral: $0) }
self.type = key.keyClass.rawValue
self.algorithm = key.type.rawValue
self.service = service
}
}
Loading

0 comments on commit 5d25580

Please sign in to comment.