-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(agent): implement issue credential protocol
Fixes ATL-2499
- Loading branch information
1 parent
c9cbad4
commit 5f48513
Showing
21 changed files
with
899 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,6 +71,7 @@ opt_in_rules: | |
- xct_specific_matcher | ||
- yoda_condition | ||
excluded: | ||
- .build | ||
- build | ||
- Pods | ||
- protobuf | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import Foundation | ||
|
||
public struct Base64Utils { | ||
public init() {} | ||
|
||
public func encode(_ data: Data) -> String { | ||
String(data.base64EncodedString() | ||
.replacingOccurrences(of: "/", with: "_") | ||
.replacingOccurrences(of: "+", with: "-") | ||
.trimingTrailing(while: CharacterSet(charactersIn: "="))) | ||
} | ||
|
||
public func decode(_ src: String) -> Data? { | ||
let expectedLength = (src.count + 3) / 4 * 4 | ||
let base64Encoded = src | ||
.replacingOccurrences(of: "_", with: "/") | ||
.replacingOccurrences(of: "-", with: "+") | ||
.appending(String(repeating: .init("="), count: expectedLength)) | ||
return Data(base64Encoded: base64Encoded) | ||
} | ||
} | ||
|
||
public extension Data { | ||
func base64UrlEncodedString() -> String { | ||
Base64Utils().encode(self) | ||
} | ||
|
||
init?(fromBase64URL: String) { | ||
guard let data = Base64Utils().decode(fromBase64URL) else { | ||
return nil | ||
} | ||
self = data | ||
} | ||
} | ||
|
||
private extension String { | ||
func trimingTrailing(while characterSet: CharacterSet) -> String { | ||
guard | ||
let index = lastIndex(where: { !CharacterSet(charactersIn: String($0)).isSubset(of: characterSet) }) | ||
else { return self } | ||
|
||
return String(self[...index]) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
Pluto/Sources/Resources/PrismPluto.xcdatamodeld/.xccurrentversion
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>_XCCurrentVersionName</key> | ||
<string>PrismPluto.xcdatamodel</string> | ||
</dict> | ||
</plist> |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
PrismAgent/Sources/Helpers/AttachmentDescriptor+Builder.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import Core | ||
import Domain | ||
import Foundation | ||
|
||
extension AttachmentDescriptor { | ||
static func build<T: Encodable>( | ||
id: String = UUID().uuidString, | ||
payload: T, | ||
mediaType: String? = "application/json" | ||
) throws -> AttachmentDescriptor { | ||
let encoded = try JSONEncoder().encode(payload).base64UrlEncodedString() | ||
return AttachmentDescriptor( | ||
id: id, | ||
mediaType: mediaType, | ||
data: AttachmentBase64(base64: encoded) | ||
) | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
PrismAgent/Sources/Protocols/IssueCredential/CredentialPreview.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import Domain | ||
import Foundation | ||
|
||
// https://github.com/hyperledger/aries-rfcs/tree/main/features/0453-issue-credential-v2#preview-credential | ||
public struct CredentialPreview: Codable, Equatable { | ||
public struct Attribute: Codable, Equatable { | ||
public let name: String | ||
public let value: String | ||
public let mimeType: String? | ||
} | ||
|
||
public let type: String | ||
public let attributes: [Attribute] | ||
|
||
public init(attributes: [Attribute]) { | ||
self.type = ProtocolTypes.didcommCredentialPreview.rawValue | ||
self.attributes = attributes | ||
} | ||
} | ||
|
||
struct CredentialFormat: Codable, Equatable { | ||
// know Format: | ||
// https://github.com/hyperledger/aries-rfcs/tree/main/features/0453-issue-credential-v2#propose-attachment-registry | ||
// - dif/[email protected] | ||
// - aries/[email protected] | ||
// - hlindy/[email protected] | ||
// | ||
let attachId: String | ||
let format: String | ||
} |
134 changes: 134 additions & 0 deletions
134
PrismAgent/Sources/Protocols/IssueCredential/IssueCredential.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import Domain | ||
import Foundation | ||
|
||
// ALL parameters are DIDCOMMV2 format and naming conventions and follows the protocol | ||
// https://github.com/hyperledger/aries-rfcs/tree/main/features/0453-issue-credential-v2 | ||
public struct IssueCredential { | ||
struct Body: Codable, Equatable { | ||
let goalCode: String? | ||
let comment: String? | ||
let replacementId: String? | ||
let moreAvailable: String? | ||
let formats: [CredentialFormat] | ||
|
||
init( | ||
goalCode: String? = nil, | ||
comment: String? = nil, | ||
replacementId: String? = nil, | ||
moreAvailable: String? = nil, | ||
formats: [CredentialFormat] | ||
) { | ||
self.goalCode = goalCode | ||
self.comment = comment | ||
self.replacementId = replacementId | ||
self.moreAvailable = moreAvailable | ||
self.formats = formats | ||
} | ||
} | ||
|
||
public let id: String | ||
public let type = ProtocolTypes.didcommIssueCredential.rawValue | ||
let body: Body | ||
let attachments: [AttachmentDescriptor] | ||
public let thid: String? | ||
public let from: DID | ||
// swiftlint:disable identifier_name | ||
public let to: DID | ||
// swiftlint:enable identifier_name | ||
|
||
init( | ||
id: String = UUID().uuidString, | ||
body: Body, | ||
attachments: [AttachmentDescriptor], | ||
thid: String?, | ||
from: DID, | ||
// swiftlint:disable identifier_name | ||
to: DID | ||
// swiftlint:enable identifier_name | ||
) { | ||
self.id = id | ||
self.body = body | ||
self.attachments = attachments | ||
self.thid = thid | ||
self.from = from | ||
self.to = to | ||
} | ||
|
||
public init(fromMessage: Message) throws { | ||
guard | ||
fromMessage.piuri == ProtocolTypes.didcommIssueCredential.rawValue, | ||
let fromDID = fromMessage.from, | ||
let toDID = fromMessage.to | ||
else { throw PrismAgentError.invalidIssueCredentialMessageError } | ||
|
||
let body = try JSONDecoder().decode(Body.self, from: fromMessage.body) | ||
self.init( | ||
id: fromMessage.id, | ||
body: body, | ||
attachments: fromMessage.attachments, | ||
thid: fromMessage.thid, | ||
from: fromDID, | ||
to: toDID | ||
) | ||
} | ||
|
||
public func makeMessage() throws -> Message { | ||
.init( | ||
id: id, | ||
piuri: type, | ||
from: from, | ||
to: to, | ||
body: try JSONEncoder().encode(body), | ||
attachments: attachments, | ||
thid: thid | ||
) | ||
} | ||
|
||
public static func makeIssueFromRequestCredential(msg: Message) throws -> IssueCredential { | ||
let request = try RequestCredential(fromMessage: msg) | ||
|
||
return IssueCredential( | ||
body: Body( | ||
goalCode: request.body.goalCode, | ||
comment: request.body.comment, | ||
formats: request.body.formats | ||
), | ||
attachments: request.attachments, | ||
thid: msg.id, | ||
from: request.to, | ||
to: request.from) | ||
} | ||
|
||
static func build<T: Encodable>( | ||
fromDID: DID, | ||
toDID: DID, | ||
thid: String?, | ||
credentialPreview: CredentialPreview, | ||
credentials: [String: T] = [:] | ||
) throws -> IssueCredential { | ||
let aux = try credentials.map { key, value in | ||
let attachment = try AttachmentDescriptor.build(payload: value) | ||
let format = CredentialFormat(attachId: attachment.id, format: key) | ||
return (format, attachment) | ||
} | ||
return IssueCredential( | ||
body: Body( | ||
formats: aux.map { $0.0 } | ||
), | ||
attachments: aux.map { $0.1 }, | ||
thid: thid, | ||
from: fromDID, | ||
to: toDID | ||
) | ||
} | ||
} | ||
|
||
extension IssueCredential: Equatable { | ||
public static func == (lhs: IssueCredential, rhs: IssueCredential) -> Bool { | ||
lhs.id == rhs.id && | ||
lhs.type == rhs.type && | ||
lhs.from == rhs.from && | ||
lhs.to == rhs.to && | ||
lhs.body == rhs.body | ||
} | ||
} |
Oops, something went wrong.