{"id":13929231,"url":"https://github.com/wiktor-k/openpgp-proofs","last_synced_at":"2025-10-16T01:04:11.312Z","repository":{"id":40742690,"uuid":"197375813","full_name":"wiktor-k/openpgp-proofs","owner":"wiktor-k","description":"Like Keybase but distributed","archived":false,"fork":false,"pushed_at":"2023-08-29T17:38:08.000Z","size":44,"stargazers_count":54,"open_issues_count":3,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-10-12T03:25:42.309Z","etag":null,"topics":["keybase","openpgp","proofs"],"latest_commit_sha":null,"homepage":"https://metacode.biz/openpgp/proofs","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wiktor-k.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-17T11:25:11.000Z","updated_at":"2024-09-29T09:38:36.000Z","dependencies_parsed_at":"2024-10-28T09:14:20.878Z","dependency_job_id":"7afe309f-f7f3-4470-994b-bda4e93f6748","html_url":"https://github.com/wiktor-k/openpgp-proofs","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wiktor-k%2Fopenpgp-proofs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wiktor-k%2Fopenpgp-proofs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wiktor-k%2Fopenpgp-proofs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wiktor-k%2Fopenpgp-proofs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wiktor-k","download_url":"https://codeload.github.com/wiktor-k/openpgp-proofs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244721387,"owners_count":20498939,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["keybase","openpgp","proofs"],"created_at":"2024-08-07T18:02:11.982Z","updated_at":"2025-10-16T01:04:11.203Z","avatar_url":"https://github.com/wiktor-k.png","language":"JavaScript","funding_links":[],"categories":["others"],"sub_categories":[],"readme":"# OpenPGP Proofs\n\nThis document describes a method of adding social proofs to OpenPGP keys in a way that can be independently verified by clients. This is similar to Keybase but decentralized.\n\nAn example:\n\n```\n$ gpg --export 653909a2f0e37c106f5faf546c8857e0d8e8f074 | node index.js\nKey : openpgp4fpr:653909a2f0e37c106f5faf546c8857e0d8e8f074\nUser: Wiktor Kwapisiewicz \u003c\u003e\n\n  ✓ dns:metacode.biz\n    URL: https://metacode.biz\n    Proof: dns:metacode.biz?type=TXT\n\n  ✓ github:wiktor-k\n    URL: https://github.com/wiktor-k\n    Proof: https://gist.github.com/wiktor-k/389d589dd19250e1f9a42bc3d5d40c16\n\n  ✓ reddit:wiktor-k\n    URL: https://www.reddit.com/user/wiktor-k\n    Proof: https://www.reddit.com/user/wiktor-k/comments/bo5oih/test/\n\n  ✓ hackernews:wiktor-k\n    URL: https://news.ycombinator.com/user?id=wiktor-k\n    Proof: https://news.ycombinator.com/user?id=wiktor-k\n\nIf this is a person you were looking for you can locally sign the key:\n  gpg --quick-lsign 653909a2f0e37c106f5faf546c8857e0d8e8f074\n```\n\nSee also online version at https://metacode.biz/openpgp/key#0x653909A2F0E37C106F5FAF546C8857E0D8E8F074\n\n## Technical details\n\nProofs are URIs to documents hosted on third-party sites (such as https://gist.github.com/wiktor-k/389d589dd19250e1f9a42bc3d5d40c16) that can be used by proof-validating clients to check if the key owner has access to given social account.\n\n(Inspect proofs from command line by using `gpg --list-options show-notations --list-sigs D8E8F074 | grep proof`).\n\nProof URIs are converted to URLs that are used to fetch JSON documents. These documents contain back-link data pointing to an OpenPGP key.\n\nOne additional document: `proofs.json` is needed for validators to properly handle proof URIs.\n\nAn example, given this proof URI:\n\nhttps://gist.github.com/wiktor-k/389d589dd19250e1f9a42bc3d5d40c16\n\nIt is matched to first entry in `proofs.json`, this regular expression:\n\n`\"^https://gist.github.com/([A-Za-z0-9_-]+)/([0-9a-f]+)$\"`\n\nCapturing groups are assigned names, in this case first group is a `USERNAME` and the second `PROOFID`.\n\nThese groups can be used to construct other elements, such as profile URL:\n\n`\"https://github.com/{USERNAME}\"`\n\nOr proof URL, that points to the JSON representation of the proof document:\n\n`\"https://api.github.com/gists/{PROOFID}\"`\n\nThe proof document is then fetched with appropriate headers and a number of checks, also defined in `proofs.json` is performed.\n\nChecks always extract a piece of data from the JSON document by recursively extracing objects by keys.\n\nFor example the first check extracts `owner` object and then, from that object `login` key (`[\"owner\", \"login\"]`). This is compared to a *claim*, that in this case is `USERNAME` that has been extracted from the URL.\n\nIf all checks succeed then the proof is considered validated.\n\n## For users\n\nProof documents can be added using platform specific editors only at the moment (for example GitHub gists). After the gist has been created a notation needs to be added to OpenPGP key that points to the proof document:\n\n```\n$ gpg --edit-key F470E50DCB1AD5F1E64E08644A63613A4D6E4094\nsec  rsa1024/4A63613A4D6E4094\n     created: 2013-10-18  expires: never       usage: SCEA\n     trust: unknown       validity: full\nssb  rsa1024/E084F7446C202C97\n     created: 2013-10-18  expires: never       usage: SEA\n[  full  ] (1). Test McTestington \u003ctest@example.com\u003e\n\ngpg\u003e\n```\n\nUse `notation` subcommand and enter `proof@metacode.biz=` and the proof URI.\n\nFor example:\n\n```\ngpg\u003e notation\nEnter the notation: proof@metacode.biz=https://news.ycombinator.com/user?id=wiktor-k\nNo notations on user ID \"Test McTestington \u003ctest@example.com\u003e\"\nAdding notation: proof@metacode.biz=https://news.ycombinator.com/user?id=wiktor-k\n```\n\nSend the key to keyservers if you want others to be able to verify your proofs (this is not strictly needed).\n\n## For proof validators\n\nProof validation logic is designed to be as simple as possible. Proofs are extracted from OpenPGP self-signature notations using `proof@metacode.biz` key and then matched to the data in `proofs.json` file.\n\nJavaScript implementation of this process is in `verifier.ts` file. Additional implementations are planned.\n\n## For service providers\n\nIf you host a service and would like to add the ability for users to prove that they control that account there are only two steps:\n\n1. Expose user data (either profile info or a comment) in a JSON format that can be read by all sites (that is with appropriate CORS header: `Access-Control-Allow-Origin: *`). The document should include user name.\n\n2. Add an entry to `proofs.json` describing how to extract data (username and key fingerprint) from that document.\n\n## FAQ\n\n1. Q: Why the notation name is `proof@metacode.biz`? Should I replace it with my own e-mail / domain?\n\nA: Nope. This e-mail-like string is actually notation key. RFC 4880 specifies [this kind of format](https://tools.ietf.org/html/rfc4880#section-5.2.3.16) as a way to namespace custom notations. You need to create notations under the domain that you own to avoid conflicts. I used my own domain for this protocol. Ideally the notation key would be just `proof`. Using this kind of keys (without `@` namespacing) is only allowed for IETF-approved extensions though (I did not approach them).\n\n2. Q: Why aren't proof documents cleartext signed like in Keybase?\n\nA: The link to the proof document is already signed with your own key when you add the signature notation. Even if the social site published a different document at that link the fingerprint will never match. Actually the signature is stronger than with Keybase as it requires your primary (master) key with Certify capability while cleartext signatures that Keybase uses require only Signing keys. (This could be important if you store your master keys offline).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwiktor-k%2Fopenpgp-proofs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwiktor-k%2Fopenpgp-proofs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwiktor-k%2Fopenpgp-proofs/lists"}