oydid 0.4.3 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/oydid/basic.rb +204 -26
  4. data/lib/oydid/didcomm.rb +25 -6
  5. data/lib/oydid/log.rb +15 -7
  6. data/lib/oydid/vc.rb +264 -0
  7. data/lib/oydid.rb +286 -111
  8. data/spec/input/basic/sample_b16_dec.doc +1 -0
  9. data/spec/input/basic/{sample_enc.doc → sample_b16_enc.doc} +0 -0
  10. data/spec/input/basic/sample_b17_edec.doc +1 -0
  11. data/spec/input/basic/{sample_hash.doc → sample_b17_enc.doc} +0 -0
  12. data/spec/input/basic/sample_b32_dec.doc +1 -0
  13. data/spec/{output/basic/sample_dec.doc → input/basic/sample_b32_enc.doc} +0 -0
  14. data/spec/input/basic/{sample_dec.doc → sample_b58_dec.doc} +0 -0
  15. data/spec/input/basic/sample_b58_enc.doc +1 -0
  16. data/spec/input/basic/sample_b64_dec.doc +1 -0
  17. data/spec/input/basic/sample_b64_enc.doc +1 -0
  18. data/spec/input/basic/sample_blake2b-16_b16_hash.doc +1 -0
  19. data/spec/input/basic/sample_blake2b-32_b32_hash.doc +1 -0
  20. data/spec/input/basic/sample_blake2b-64_b58_hash.doc +1 -0
  21. data/spec/input/basic/sample_invalid2_readkey.doc +1 -1
  22. data/spec/input/basic/sample_invalid3_readkey.doc +1 -1
  23. data/spec/input/basic/sample_readkey.doc +1 -1
  24. data/spec/input/basic/sample_sha2-256_b58_hash.doc +1 -0
  25. data/spec/input/basic/sample_sha2-512_b58_hash.doc +1 -0
  26. data/spec/input/basic/sample_sha3-224_b64_hash.doc +1 -0
  27. data/spec/output/basic/sample_b16_dec.doc +1 -0
  28. data/spec/output/basic/sample_b16_enc.doc +1 -0
  29. data/spec/output/basic/sample_b17_edec.doc +2 -0
  30. data/spec/output/basic/sample_b17_enc.doc +1 -0
  31. data/spec/output/basic/sample_b32_dec.doc +1 -0
  32. data/spec/output/basic/sample_b32_enc.doc +1 -0
  33. data/spec/output/basic/sample_b58_dec.doc +1 -0
  34. data/spec/output/basic/{sample_enc.doc → sample_b58_enc.doc} +0 -0
  35. data/spec/output/basic/sample_b64_dec.doc +1 -0
  36. data/spec/output/basic/sample_b64_enc.doc +1 -0
  37. data/spec/output/basic/sample_blake2b-16_b16_hash.doc +1 -0
  38. data/spec/output/basic/sample_blake2b-32_b32_hash.doc +1 -0
  39. data/spec/output/basic/sample_blake2b-64_b58_hash.doc +1 -0
  40. data/spec/output/basic/{sample_hash.doc → sample_sha2-256_b58_hash.doc} +0 -0
  41. data/spec/output/basic/sample_sha2-512_b58_hash.doc +1 -0
  42. data/spec/output/basic/sample_sha3-224_b64_hash.doc +1 -0
  43. data/spec/oydid_spec.rb +95 -13
  44. metadata +72 -19
data/lib/oydid/vc.rb ADDED
@@ -0,0 +1,264 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
4
+ class Oydid
5
+ def self.read_vc(identifier, options)
6
+ vc_location = ""
7
+ if !options[:location].nil?
8
+ vc_location = options[:location]
9
+ end
10
+ if vc_location.to_s == ""
11
+ vc_location = DEFAULT_LOCATION
12
+ end
13
+ vc_url = vc_location.sub(/(\/)+$/,'') + "/credentials/" + identifier
14
+
15
+ holder = options[:holder].to_s rescue nil
16
+ if holder.to_s == ""
17
+ msg = "missing holder information"
18
+ return [nil, msg]
19
+ exit
20
+ end
21
+
22
+ private_key = options[:doc_enc].to_s rescue nil
23
+ if private_key.to_s == ""
24
+ msg = "missing private document key information"
25
+ return [nil, msg]
26
+ exit
27
+ end
28
+
29
+ # authenticate against repository
30
+ init_url = vc_location + "/oydid/init"
31
+ sid = SecureRandom.hex(20).to_s
32
+ response = HTTParty.post(init_url,
33
+ headers: { 'Content-Type' => 'application/json' },
34
+ body: { "session_id": sid,
35
+ "public_key": Oydid.public_key(private_key, options).first }.to_json ).parsed_response rescue {}
36
+ if response["challenge"].nil?
37
+ msg = "missing challenge for repository authentication"
38
+ return [nil, msg]
39
+ exit
40
+ end
41
+ challenge = response["challenge"].to_s
42
+
43
+ # sign challenge and request token
44
+ token_url = vc_location + "/oydid/token"
45
+ response = HTTParty.post(token_url,
46
+ headers: { 'Content-Type' => 'application/json' },
47
+ body: { "session_id": sid,
48
+ "signed_challenge": Oydid.sign(challenge, private_key, options).first }.to_json).parsed_response rescue {}
49
+ access_token = response["access_token"].to_s rescue nil
50
+ if access_token.nil?
51
+ msg = "invalid repository authentication (access_token)"
52
+ return [nil, msg]
53
+ exit
54
+ end
55
+
56
+ retVal = HTTParty.get(vc_url,
57
+ headers: {'Authorization' => 'Bearer ' + access_token})
58
+ if retVal.code != 200
59
+ if retVal.code == 401
60
+ msg = "unauthorized (valid Bearer token required)"
61
+ else
62
+ msg = retVal.parsed_response("error").to_s rescue "invalid response from " + vc_url.to_s
63
+ end
64
+ return [nil, msg]
65
+ end
66
+ return [retVal.parsed_response, ""]
67
+ end
68
+
69
+ def self.create_vc(content, options)
70
+ vercred = {}
71
+ # set the context, which establishes the special terms used
72
+ vercred["@context"] = ["https://www.w3.org/2018/credentials/v1"]
73
+ vercred["type"] = ["VerifiableCredential"]
74
+ vercred["issuer"] = options[:issuer]
75
+ if options[:ts].nil?
76
+ vercred["issuanceDate"] = Time.now.utc.iso8601
77
+ else
78
+ vercred["issuanceDate"] = Time.at(options[:ts]).utc.iso8601
79
+ end
80
+ vercred["credentialSubject"] = {"id": options[:holder]}.merge(content)
81
+
82
+ proof = {}
83
+ proof["type"] = "Ed25519Signature2020"
84
+ proof["verificationMethod"] = options[:issuer].to_s
85
+ proof["proofPurpose"] = "assertionMethod"
86
+
87
+ # private_key = generate_private_key(options[:issuer_privateKey], "ed25519-priv", []).first
88
+ proof["proofValue"] = sign(content.to_json_c14n, options[:issuer_privateKey], []).first
89
+
90
+ vercred["proof"] = proof
91
+
92
+ # specify the identifier of the credential
93
+ vercred["identifier"] = hash(vercred.to_json)
94
+ return [vercred, ""]
95
+ end
96
+
97
+ def self.publish_vc(vc, options)
98
+ vc = vc.transform_keys(&:to_s)
99
+ identifier = vc["identifier"] rescue nil
100
+ if identifier.nil?
101
+ return [nil, "invalid format (missing identifier"]
102
+ exit
103
+ end
104
+
105
+ cs = vc["credentialSubject"].transform_keys(&:to_s) rescue nil
106
+ holder = cs["id"] rescue nil
107
+ if holder.nil?
108
+ return [nil, "invalid format (missing holder)"]
109
+ exit
110
+ end
111
+
112
+ vc_location = ""
113
+ if !options[:location].nil?
114
+ vc_location = options[:location]
115
+ end
116
+ if vc_location.to_s == ""
117
+ vc_location = DEFAULT_LOCATION
118
+ end
119
+ vc["identifier"] = vc_location.sub(/(\/)+$/,'') + "/credentials/" + identifier
120
+
121
+ # build object to post
122
+ vc_data = {
123
+ "identifier": identifier,
124
+ "vc": vc,
125
+ "holder": holder
126
+ }
127
+ vc_url = vc_location.sub(/(\/)+$/,'') + "/credentials"
128
+ retVal = HTTParty.post(vc_url,
129
+ headers: { 'Content-Type' => 'application/json' },
130
+ body: vc_data.to_json )
131
+ if retVal.code != 200
132
+ err_msg = retVal.parsed_response("error").to_s rescue "invalid response from " + vc_url.to_s
133
+ return [nil, err_msg]
134
+ end
135
+ return [vc["identifier"], ""]
136
+ end
137
+
138
+ def self.read_vp(identifier, options)
139
+ vp_location = ""
140
+ if !options[:location].nil?
141
+ vp_location = options[:location]
142
+ end
143
+ if vp_location.to_s == ""
144
+ vp_location = DEFAULT_LOCATION
145
+ end
146
+ vp_url = vp_location.sub(/(\/)+$/,'') + "/presentations/" + identifier
147
+ retVal = HTTParty.get(vp_url)
148
+ if retVal.code != 200
149
+ msg = retVal.parsed_response("error").to_s rescue "invalid response from " + vp_url.to_s
150
+ return [nil, msg]
151
+ end
152
+ return [retVal.parsed_response, ""]
153
+ end
154
+
155
+ def self.create_vp(content, options)
156
+ verpres = {}
157
+ # set the context, which establishes the special terms used
158
+ verpres["@context"] = ["https://www.w3.org/2018/credentials/v1"]
159
+ verpres["type"] = ["VerifiablePresentation"]
160
+ verpres["verifiableCredential"] = [content].flatten
161
+
162
+ proof = {}
163
+ proof["type"] = "Ed25519Signature2020"
164
+ if options[:ts].nil?
165
+ proof["created"] = Time.now.utc.iso8601
166
+ else
167
+ proof["created"] = Time.at(options[:ts]).utc.iso8601
168
+ end
169
+ proof["verificationMethod"] = options[:holder].to_s
170
+ proof["proofPurpose"] = "authentication"
171
+
172
+ # private_key = generate_private_key(options[:issuer_privateKey], "ed25519-priv", []).first
173
+ proof["proofValue"] = sign([content].flatten.to_json_c14n, options[:holder_privateKey], []).first
174
+ verpres["proof"] = proof
175
+
176
+ # specify the identifier of the credential
177
+ verpres["identifier"] = hash(verpres.to_json)
178
+ return [verpres, ""]
179
+ end
180
+
181
+ def self.publish_vp(vp, options)
182
+ vc = vp.transform_keys(&:to_s)
183
+ identifier = vp["identifier"] rescue nil
184
+ if identifier.nil?
185
+ return [nil, "invalid format (missing identifier"]
186
+ exit
187
+ end
188
+
189
+ proof = vp["proof"].transform_keys(&:to_s) rescue nil
190
+ holder = proof["verificationMethod"] rescue nil
191
+ if holder.nil?
192
+ return [nil, "invalid format (missing holder)"]
193
+ exit
194
+ end
195
+
196
+ vp_location = ""
197
+ if !options[:location].nil?
198
+ vp_location = options[:location]
199
+ end
200
+ if vp_location.to_s == ""
201
+ vp_location = DEFAULT_LOCATION
202
+ end
203
+ vp["identifier"] = vp_location.sub(/(\/)+$/,'') + "/presentations/" + identifier
204
+
205
+ # build object to post
206
+ vp_data = {
207
+ "identifier": identifier,
208
+ "vp": vp,
209
+ "holder": holder
210
+ }
211
+ vp_url = vp_location.sub(/(\/)+$/,'') + "/presentations"
212
+ retVal = HTTParty.post(vp_url,
213
+ headers: { 'Content-Type' => 'application/json' },
214
+ body: vp_data.to_json )
215
+ if retVal.code != 200
216
+ err_msg = retVal.parsed_response("error").to_s rescue "invalid response from " + vp_url.to_s
217
+ return [nil, err_msg]
218
+ end
219
+ return [vp["identifier"], ""]
220
+ end
221
+
222
+ def self.verify_vp(content, options)
223
+ retVal = {}
224
+ if content["identifier"].nil?
225
+ return [nil, "invalid VP (unknown identifier"]
226
+ exit
227
+ end
228
+ retVal[:identifier] = content["identifier"].to_s
229
+
230
+ proofValue = content["proof"]["proofValue"].to_s rescue nil
231
+ if proofValue.nil?
232
+ return [nil, "invalid VP (unknown proofValue"]
233
+ exit
234
+ end
235
+
236
+ vercred = content["verifiableCredential"].to_json_c14n rescue nil
237
+ if vercred.nil?
238
+ return [nil, "invalid VP (unknown verifiableCredential"]
239
+ exit
240
+ end
241
+
242
+ holder = content["proof"]["verificationMethod"].to_s rescue nil
243
+ if holder.nil?
244
+ return [nil, "invalid VP (unknown holder"]
245
+ exit
246
+ end
247
+ pubKey, msg = getPubKeyFromDID(holder)
248
+ if pubKey.nil?
249
+ return [nil, "cannot verify public key"]
250
+ exit
251
+ end
252
+ result, msg = verify(vercred, proofValue, pubKey)
253
+ if result.to_s == ""
254
+ return [nil, msg]
255
+ exit
256
+ end
257
+ if result
258
+ return [retVal, ""]
259
+ else
260
+ return [nil, "signature verification failed"]
261
+ end
262
+ end
263
+
264
+ end