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

TwitterVerification VerifiableCredential semantics #13

Closed
clehner opened this issue Apr 28, 2021 · 0 comments · Fixed by #17
Closed

TwitterVerification VerifiableCredential semantics #13

clehner opened this issue Apr 28, 2021 · 0 comments · Fixed by #17
Assignees

Comments

@clehner
Copy link
Contributor

clehner commented Apr 28, 2021

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
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

@sbihel sbihel self-assigned this Apr 29, 2021
sbihel added a commit that referenced this issue Apr 29, 2021
sbihel added a commit that referenced this issue Apr 29, 2021
sbihel added a commit that referenced this issue Apr 29, 2021
sbihel added a commit that referenced this issue May 4, 2021
sbihel added a commit that referenced this issue May 4, 2021
sbihel added a commit that referenced this issue May 6, 2021
@sbihel sbihel closed this as completed in #17 May 7, 2021
sbihel added a commit that referenced this issue May 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants