{"id":40923831,"url":"https://github.com/robertdfrench/wmap","last_synced_at":"2026-01-22T03:37:59.850Z","repository":{"id":39841830,"uuid":"494667661","full_name":"robertdfrench/wmap","owner":"robertdfrench","description":"Web-based Message Authentication Protocol","archived":false,"fork":false,"pushed_at":"2025-05-13T14:32:28.000Z","size":450,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"trunk","last_synced_at":"2025-05-13T15:48:59.516Z","etag":null,"topics":["message-authentication","ssh-key"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/robertdfrench.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null}},"created_at":"2022-05-21T03:14:36.000Z","updated_at":"2025-05-13T14:29:15.000Z","dependencies_parsed_at":"2025-05-13T15:37:13.950Z","dependency_job_id":"c4f4694e-0048-4462-99da-77e1e81c20bd","html_url":"https://github.com/robertdfrench/wmap","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/robertdfrench/wmap","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robertdfrench%2Fwmap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robertdfrench%2Fwmap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robertdfrench%2Fwmap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robertdfrench%2Fwmap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/robertdfrench","download_url":"https://codeload.github.com/robertdfrench/wmap/tar.gz/refs/heads/trunk","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robertdfrench%2Fwmap/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28653171,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-22T01:17:37.254Z","status":"online","status_checked_at":"2026-01-22T02:00:07.137Z","response_time":144,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["message-authentication","ssh-key"],"created_at":"2026-01-22T03:37:59.462Z","updated_at":"2026-01-22T03:37:59.845Z","avatar_url":"https://github.com/robertdfrench.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WMAP\n*The Web-based Message Authentication Protocol*\n\nWMAP lets you validate messages against your friends' SSH pubkeys.\nSince your GitHub keys are stored in a [known\nlocation](https://github.com/robertdfrench.keys), signing documents with\nthese keys makes it easy for your friends to verify their integrity (and\nthe integrity of the documents!).\n\nThis repository contains a reference implementation for a protocol which\ncan be used for moderately trustworthy internet communication. Many such\nprotocols already exist, the goal of this one is to see what can be done\nwith tools that software engineers are likely to already have lying\naround: `git`, `ssh`, etc.\n\nHere's how it works at a high level:\n\n```mermaid\nsequenceDiagram\n    Alice-\u003e\u003eGitHub: Upload SSH Pubkey\n    Alice-\u003e\u003eAlice: Sign a Message\n    Alice-\u003e\u003eBob: Send Message to Bob\n    Bob-\u003e\u003eGitHub: Fetch Alice's Pubkey\n    Bob-\u003e\u003eBob: Verify Message Came from Alice\n```\n\n## Tutorial\nFirst, clone this repository!\n\n### Signing a Document\nIn the repo, run `./wmap sign \u003cusername\u003e \u003ckey\u003e \u003cfile\u003e`. These arguments\nare:\n- `\u003cusername\u003e`: Your GitHub username.\n- `\u003ckey\u003e`: Path to your SSH private key.\n- `\u003cfile\u003e`: Path to the file you want to sign.\n\nNow you've got a signed version of `\u003cfile\u003e` called `\u003cfile\u003e.wmap`, which\nyou can send to your friends!\n\n### Verifying a Message\nTo verify a signed document, you only need the `.wmap` file created in the previous step.\n\n```bash\n./wmap verify \u003cfile\u003e.wmap\n```\n\nwhere `\u003cfile\u003e.wmap` is the path to the signed WMAP file.  If the\nverification is successful, the command will complete without any\noutput. If the verification fails, the script will exit with a non-zero\nstatus.\n\n### Extracting a Document from a Verified Message\nIf you've received a WMAP message from a friend, they probably want you\nto read the message inside. To extract this message, use the `extract`\ncommand:\n\n```bash\n./wmap extract \u003cfile\u003e.wmap\n```\n\nThis will print the body of `\u003cfile\u003e.wmap` to stdout.\n\nKeep in mind that this command will fail if the wmap file cannot be\nverified.  If you need to extract it anyways, you can do this:\n\n```bash\n./wmap extract --skip-validation \u003cfile\u003e.wmap\n```\n\n## Protocol Details\nWMAP is a simple protocol based on SSH signatures. The command which\ncreates these signatures ([`ssh-keygen(1)`][1]) is intentionally\ngeneric, and WMAP is an opinionated refinement of that. By bundling the\nmessage data, a canonical author name, and the signature into a single\nfile, WMAP makes it easier to transfer and validate documents signed\nwith ssh keys.\n\n\n### Message Structure\nThe central idea behind WMAP is that every GitHub user's SSH public keys\nare available at `https://github.com/\u003cusername\u003e.keys`. This means that\nany message signed with one of the corresponding private keys can be\nverified by anyone who knows the author's GitHub username. As such, WMAP\nmessages need the following three fields:\n\n- profile: the author's GitHub username\n- body: a Base64-encoded representation of the input message\n- signature: a Base64-encoded representation of the author's SSH\n  signature of the original input message (not a signature of the\n  Base64-encoded `body` field).\n\nIt will look something like this:\n\n```json\n{\n    \"profile\": \"robertdfrench\",\n    \"body\": \"aGVsbG8K\",\n    \"signature\": \"LS0tLS1CRUd...\"\n}\n```\n\nAnyone with access to github.com can retrieve the author's public keys\nand verify the message signature against them. *This does mean that if a\nGitHub user removes a public key, messages signed with that key will no\nlonger be valid.*\n\n\n### Signing\nMessages are signed using the `ssh-keygen(1)` command, specifically the\n`-Y sign` flag. This signing operation takes an input file (the message\nto be signed), a private key, and a \"namespace\" -- an identifier to\ndistinguish custom signing applications.\n\nFor an input file called `message.txt`, ssh-keygen will produce a\nsignature file called `message.txt.sig`. WMAP requires that base64-encoded\nversions of these files be bundled into a single document (according to\nthe [Message Structure](#message-structure) defined above).\n\n```mermaid\nflowchart TD\n    M(WMAP JSON Message)\n    S(message.txt.sig)\n    B(message.txt)\n    U[GitHub\u003cbr/\u003eUSERNAME]\n    P(SSH Private Key)\n    K{ssh-keygen -Y sign}\n    P --\u003e K\n    B --\u003e K\n    K --\u003e S\n    S --\u003e|Encode Signature| M\n    B --\u003e|Encode Body| M\n    U --\u003eM\n```\n\n#### Namespaces\n`ssh-keygen(1)` requires every signing operation to use a *namespace* in\norder to avoid confusing signatures created for differing use cases. The\n[manual entry][1] suggest using the namespace string\n\"NAMESPACE@YOUR.DOMAIN\" for custom purposes, so WMAP messages use the\nnamespace string \"wmap@wmap.dev\".\n\n\n### Authentication\nBy including the username and signature alongside the message, WMAP\nbundles everything necessary for authentication in one place. The\nauthentication process works as follows:\n\n1. The base-64 representations of the message and its signature are\n   extracted and stored on disk. \n2. The author's SSH public keys, as listed on GitHub, are transformed\n   into an [Allowed Signers][2] file.\n3. The `ssh-keygen(1)` command (specifically the `-Y verify` subcommand)\n   is used to verify the message and its signature against the Allowed\n   Signers file.\n\n```mermaid\nflowchart TD\n    M(WMAP JSON Message) --\u003e|Decode Signature| S(message.txt.sig)\n    M --\u003e|Decode Body| B(message.txt)\n    M --\u003e|Download Pubkeys\u003cbr/\u003e for USERNAME| G(pubkeys.txt)\n    G --\u003e|Convert to\u003cbr/\u003eAllowed Signers| A[(allowed_signers.txt)]\n    B --\u003eK{ssh-keygen -Y verify}\n    S --\u003eK\n    A --\u003eK\n    K --\u003e|success| Y[Message was definitely authored by USERNAME.]\n    K --\u003e|error| N[Message may not have been authored by USERNAME.]\n```\n\n#### Allowed Signers\nAn [Allowed Signers][2] file is a list of named SSH Public Keys against\nwhich a message and a signature can be authenticated. For the purposes\nof WMAP, such files have the following format:\n\n    \u003cGitHub Username\u003e namespaces=\"wmap@wmap.dev\" ssh-rsa AAAAX1...\n    \u003cGitHub Username\u003e namespaces=\"wmap@wmap.dev\" ssh-ed25519 AAAB4...\n    ...\n\nThe wmap client constructs these files on the fly before each\nauthentication operation, so that the latest keys are always pulled from\nGitHub.\n\n`ssh-keygen(1)` requires a file of this format in order to perform\nverification with the `-Y verify` subcommand. WMAP-flavored Allowed\nSigners files could be produced with something along the lines of this\nshell script:\n\n```sh\nGH_USERNAME=\"robertdfrench\"\ncurl --silent \"https://github.com/${GH_USERNAME}.keys\" \\\n    | sed 's/^/namespaces=\"wmap@wmap.dev\" /' \\\n    | sed \"s/^/${GH_USERNAME} /\" \\\n    \u003e allowed_signers.txt\n```\n\n\u003c!-- REFERENCES --\u003e\n[1]: https://www.man7.org/linux/man-pages/man1/ssh-keygen.1.html\n[2]: https://www.man7.org/linux/man-pages/man1/ssh-keygen.1.html#ALLOWED_SIGNERS\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobertdfrench%2Fwmap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frobertdfrench%2Fwmap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobertdfrench%2Fwmap/lists"}