{"id":27398947,"url":"https://github.com/imputnet/cup2","last_synced_at":"2026-05-02T03:06:26.830Z","repository":{"id":287629991,"uuid":"965288228","full_name":"imputnet/cup2","owner":"imputnet","description":"TypeScript implementation of the Chromium/Omaha Client Update Protocol","archived":false,"fork":false,"pushed_at":"2025-04-13T10:02:25.000Z","size":37,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-14T02:16:32.514Z","etag":null,"topics":["chromium","cup","omaha"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/imputnet.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},"funding":{"liberapay":"imput","custom":"https://donate.stripe.com/3cs2cc6ew1Qda4wbII"}},"created_at":"2025-04-12T20:32:31.000Z","updated_at":"2025-04-13T10:02:28.000Z","dependencies_parsed_at":"2025-04-13T10:49:38.353Z","dependency_job_id":null,"html_url":"https://github.com/imputnet/cup2","commit_stats":null,"previous_names":["dumbmoron/cup2","imputnet/cup2"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imputnet%2Fcup2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imputnet%2Fcup2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imputnet%2Fcup2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imputnet%2Fcup2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/imputnet","download_url":"https://codeload.github.com/imputnet/cup2/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248809058,"owners_count":21164896,"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":["chromium","cup","omaha"],"created_at":"2025-04-14T02:16:39.488Z","updated_at":"2026-05-02T03:06:26.789Z","avatar_url":"https://github.com/imputnet.png","language":"TypeScript","funding_links":["https://liberapay.com/imput","https://donate.stripe.com/3cs2cc6ew1Qda4wbII"],"categories":[],"sub_categories":[],"readme":"# @imput/cup2\n\nClient/server implementation of the\n[Chromium/Omaha CUP-ECDSA protocol](https://github.com/google/omaha/blob/c0fcf45e4c46ddf2e1e7972f4405fb4ec7b4d079/doc/ClientUpdateProtocolEcdsa.md)\nin Typescript.\n\n## Installation\n\n- Deno: `deno add @imput/cup2`\n- Node.js: `npx jsr add @imput/cup2`\n\n## Examples\n\n### client\n\n```ts\nimport { CupClient } from '@imput/cup2';\n\nconst keyId = /* your key ID goes here */;\nconst keyBytes = new Uint8Array([\n    /* your EC pubkey bytes go here, or you can load it from a file */\n]);\n\n// This is the side of the requestor of resources,\n// which is usually a browser reaching out to some API.\nconst publicKey = await crypto.subtle.importKey(\n    'spki', keyBytes,\n    { name: 'ECDSA', namedCurve: 'P-256' },\n    false, ['verify'],\n);\n\nconst client = new CupClient(keyId, publicKey);\n\nconst raw_request = new Request('http://clients2.google.com/time/1/current');\nconst { request, ticket } = await client.wrap(raw_request);\n\n// make the request after adding cup parameters\nconst response = await fetch(request);\n\n// verify() throws a CupError if the signature is not valid\nawait client.verify(response, ticket);\n\n// we can now consume the response\nconsole.log(await response.text());\n```\n\n### server\n\n```ts\nimport { CupServer } from '@imput/cup2';\n\nconst keys: Record\u003cnumber, CryptoKey\u003e = {\n    /* keys should be periodically rotated,\n       but we still need to support older\n       clients. this is why you are able to\n       insert multiple keys here. load them\n       from a file or something, this is entirely\n       up to you\n    */\n};\n\nconst cup = new CupServer(keys);\n\nDeno.serve(async (request: Request) =\u003e {\n    // this library assumes all your incoming requests use CUP.\n    // if this is not the case, you need to check for presence\n    // of cup2key in request.url.searchParams and decide whether\n    // you want to use CUP or not\n\n    // this is separated from the signing process\n    // so that we can do some preliminary checks and not\n    // waste processing time if the request does not meet the\n    // preconditions.\n    const ticket = await cup.makeTicket(request);\n    // hold on to this ticket, do some work ...\n    // ...\n    // we have a response!\n    const response = new Response();\n    // sign and return\n    // TODO: cup.* methods throw a CupError if something\n    // is wrong -- you probably want to check for that.\n    return cup.sign(response, ticket);\n});\n```\n\nmore:\n\n- [mod_test.ts](mod_test.ts)\n- [client_test.ts](client_test.ts)\n\n## License\n\nAGPL-3.0, see [LICENSE](LICENSE).\n\nFor other licensing options, you can reach us at meow [@] imput.net.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimputnet%2Fcup2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fimputnet%2Fcup2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimputnet%2Fcup2/lists"}