The credential is initialized here:
|
fn build_vc_(pk: &JWK, twitter_handle: &str) -> Result<Credential> { |
|
// Credential { |
|
// context: Contexts::Object(vec![Context::URI(URI::String("https://www.w3.org/2018/credentials/v1".to_string())), Context::URI(URI::String("https://schema.org/".to_string())), Context::Object()]) |
|
// } |
|
Ok(serde_json::from_value(json!({ |
|
"@context": [ |
|
"https://www.w3.org/2018/credentials/v1", |
|
"https://schema.org/", |
|
{ |
|
"TwitterVerification": { |
|
|
|
}, |
|
"TwitterVerificationPublicTweet": { |
|
// "handle": "https://schema.org/Text", |
|
// "timestamp": "https://schema.org/DateTime", |
|
// "tweetId": "https://schema.org/Text" |
|
} |
|
} |
|
], |
|
// "id": "urn:uuid:61974235-3f95-4f44-9f20-7c163bab8764", |
|
"type": ["VerifiableCredential", "TwitterVerification"], |
|
"credentialSubject": { |
|
"id": format!("did:pkh:tz:{}", &hash_public_key(pk)?), |
|
"sameAs": "https://twitter.com/".to_string() + twitter_handle |
|
}, |
|
"issuer": "did:web:tzprofiles.me" |
|
}))?) |
|
} |
It has the tweet verification put in here:
|
let mut evidence_map = HashMap::new(); |
|
evidence_map.insert( |
|
"handle".to_string(), |
|
serde_json::Value::String(twitter_handle), |
|
); |
|
evidence_map.insert( |
|
"timestamp".to_string(), |
|
serde_json::Value::String(Utc::now().to_string()), |
|
); |
|
evidence_map.insert("tweetId".to_string(), serde_json::Value::String(tweet_id)); |
|
let evidence = Evidence { |
|
id: None, |
|
type_: vec!["TwitterVerificationPublicTweet".to_string()], |
|
property_set: Some(evidence_map), |
|
}; |
|
vc.evidence = Some(OneOrMany::One(evidence)); |
I think this would result in a credential (before signing) like this:
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://schema.org/",
{
"TwitterVerification": {},
"TwitterVerificationPublicTweet": {}
}
],
"id": "urn:uuid:04d65b86-e5ae-497f-aeff-ba7a3c0ac046",
"type": [
"VerifiableCredential",
"TwitterVerification"
],
"credentialSubject": {
"id": "did:pkh:tz:example",
"sameAs": "https://twitter.com/example"
},
"issuer": "did:web:tzprofiles.me",
"evidence": {
"type": "TwitterVerificationPublicTweet",
"handle": "example",
"timestamp": 1619642577000,
"tweetId": "1234567890"
}
}
Putting that through JSON-LD Playground results in the following N-Quads:
<did:pkh:tz:example> <http://schema.org/sameAs> <https://twitter.com/example> .
<urn:uuid:04d65b86-e5ae-497f-aeff-ba7a3c0ac046> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/TwitterVerification> .
<urn:uuid:04d65b86-e5ae-497f-aeff-ba7a3c0ac046> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .
<urn:uuid:04d65b86-e5ae-497f-aeff-ba7a3c0ac046> <https://www.w3.org/2018/credentials#credentialSubject> <did:pkh:tz:example> .
<urn:uuid:04d65b86-e5ae-497f-aeff-ba7a3c0ac046> <https://www.w3.org/2018/credentials#evidence> _:b0 .
<urn:uuid:04d65b86-e5ae-497f-aeff-ba7a3c0ac046> <https://www.w3.org/2018/credentials#issuer> <did:web:tzprofiles.me> .
_:b0 <http://schema.org/handle> "example" .
_:b0 <http://schema.org/timestamp> "1619642577000"^^<http://www.w3.org/2001/XMLSchema#integer> .
_:b0 <http://schema.org/tweetId> "1234567890" .
_:b0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/TwitterVerificationPublicTweet> .
Table view:
![2021-04-28-164630_949x598_scrot](https://user-images.githubusercontent.com/95347/116470347-50fc8880-a841-11eb-8fd0-1fd727b9e36d.png)
This shows several URIs under schema.org
, such as http://schema.org/tweetId
, which are not meaningful.
These occur because the schema.org
JSON-LD context file sets @vocab
("default vocabulary) which means undefined terms automatically get prefixed. This is good for preserving information which would otherwise not be included in the signing input, and maybe other reasons, but its use here results in bad URIs (404s on schema.org, unclear semantics) which could reduce interoperability. For this reason I would recommend not using "https://schema.org/"
in context arrays, unless you are sure of the effect.
Removing https://schema.org/
from the credential's context results in an error because the terms previously defined become undefined. The only one we are using that comes from schema.org
is sameAs
. That term can be defined on its own:
"sameAs": "http://schema.org/sameAs"
Next there are the new Twitter verification related terms. We should decide what these terms will expand to. The way schema.org
does it is to basically give each term its own page. Other namespaces have a single main URI under which the terms use fragments. These don't have to be resolvable as JSON-LD files for verification, but they should be, and they should also work as web pages so that people can look at them and reference them. I will assume below that we would use separate pages under tzprofiles.com
. For examples of JSON-LD context files you can find several in ssi
: https://github.com/spruceid/ssi/tree/main/contexts/
The terms needing definition are TwitterVerification
, TwitterVerificationPublicTweet
, handle
, timestamp
, tweetId
. A simple way to proceed would be to define all these:
"TwitterVerification": "https://tzprofiles.com/TwitterVerification",
"TwitterVerificationPublicTweet": "https://tzprofiles.com/TwitterVerificationPublicTweet",
"handle": "https://tzprofiles.com/handle",
"timestamp": "https://tzprofiles.com/timestamp",
"tweetId": "https://tzprofiles.com/tweetId"
This may be improved by changing timestamp to be an XML Datetime string which is a more common way to represent a timestamp in JSON-LD:
"timestamp": {
"@id": "https://tzprofiles.com/timestamp",
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
}
But I'm not sure if that interferes with other usage that may require the timestamp to be an number.
Another improvement would be to scope the term definitions by the type. e.g. define handle
, timestamp
and tweetId
under TwitterVerificationPublicTweet
:
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
{
"sameAs": "http://schema.org/sameAs",
"TwitterVerification": "https://tzprofiles.com/TwitterVerification",
"TwitterVerificationPublicTweet": {
"@id": "https://tzprofiles.com/TwitterVerificationPublicTweet",
"@context": {
"@version": 1.1,
"@protected": true,
"handle": "https://tzprofiles.com/handle",
"timestamp": {
"@id": "https://tzprofiles.com/timestamp",
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
},
"tweetId": "https://tzprofiles.com/tweetId"
}
}
}
],
"id": "urn:uuid:04d65b86-e5ae-497f-aeff-ba7a3c0ac046",
"type": [
"VerifiableCredential",
"TwitterVerification"
],
"credentialSubject": {
"id": "did:pkh:tz:example",
"sameAs": "https://twitter.com/example"
},
"issuer": "did:web:tzprofiles.me",
"evidence": {
"type": "TwitterVerificationPublicTweet",
"handle": "example",
"timestamp": "2021-04-28T21:13:07Z",
"tweetId": "1234567890"
}
}
There may be better semantics possible for these terms; I'm not sure.
Resulting N-Quads:
<did:pkh:tz:example> <http://schema.org/sameAs> "https://twitter.com/example" .
<urn:uuid:04d65b86-e5ae-497f-aeff-ba7a3c0ac046> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://tzprofiles.com/TwitterVerification> .
<urn:uuid:04d65b86-e5ae-497f-aeff-ba7a3c0ac046> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .
<urn:uuid:04d65b86-e5ae-497f-aeff-ba7a3c0ac046> <https://www.w3.org/2018/credentials#credentialSubject> <did:pkh:tz:example> .
<urn:uuid:04d65b86-e5ae-497f-aeff-ba7a3c0ac046> <https://www.w3.org/2018/credentials#evidence> _:b0 .
<urn:uuid:04d65b86-e5ae-497f-aeff-ba7a3c0ac046> <https://www.w3.org/2018/credentials#issuer> <did:web:tzprofiles.me> .
_:b0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://tzprofiles.com/TwitterVerificationPublicTweet> .
_:b0 <https://tzprofiles.com/handle> "example" .
_:b0 <https://tzprofiles.com/timestamp> "2021-04-28T21:13:07Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
_:b0 <https://tzprofiles.com/tweetId> "1234567890" .
Table view:
![2021-04-28-172021_951x592_scrot](https://user-images.githubusercontent.com/95347/116474073-09c4c680-a846-11eb-822e-e87e248d5dcd.png)