Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(pluto): pluto will save link secret as a storable key. #108

Merged
merged 1 commit into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading