{"id":15447887,"url":"https://github.com/hazae41/echalote","last_synced_at":"2025-04-13T09:33:07.844Z","repository":{"id":64837769,"uuid":"561719169","full_name":"hazae41/echalote","owner":"hazae41","description":"Zero-copy Tor protocol for the web 🏎️ (JS + WebAssembly)","archived":false,"fork":false,"pushed_at":"2024-09-06T15:28:13.000Z","size":23864,"stargazers_count":27,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-27T01:04:20.346Z","etag":null,"topics":["aes","browser","ed25519","gzip","http","rsa","rust","tls","tor","typescript","webassembly","webcrypto"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hazae41.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":["hazae41"],"patreon":"hazae41"}},"created_at":"2022-11-04T10:35:14.000Z","updated_at":"2025-02-22T11:18:21.000Z","dependencies_parsed_at":"2024-10-01T20:21:08.187Z","dependency_job_id":"68857830-728d-45cb-9a69-a461affc820a","html_url":"https://github.com/hazae41/echalote","commit_stats":{"total_commits":256,"total_committers":1,"mean_commits":256.0,"dds":0.0,"last_synced_commit":"3e51facf7032fa6065be80fd46b6b31ad9d797c6"},"previous_names":[],"tags_count":136,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazae41%2Fechalote","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazae41%2Fechalote/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazae41%2Fechalote/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazae41%2Fechalote/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hazae41","download_url":"https://codeload.github.com/hazae41/echalote/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248557828,"owners_count":21124167,"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":["aes","browser","ed25519","gzip","http","rsa","rust","tls","tor","typescript","webassembly","webcrypto"],"created_at":"2024-10-01T20:20:50.591Z","updated_at":"2025-04-13T09:33:07.823Z","avatar_url":"https://github.com/hazae41.png","language":"TypeScript","funding_links":["https://github.com/sponsors/hazae41","https://patreon.com/hazae41"],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/4405263/219942970-2b5fb519-7bbe-491a-a12b-6b71040febe4.png\" /\u003e\n\u003c/div\u003e\n\n```bash\nnpm i @hazae41/echalote\n```\n\n[**Node Package 📦**](https://www.npmjs.com/package/@hazae41/echalote) • [**Online Demo 🌐**](https://echalote-example-next.vercel.app) • [**Next.js CodeSandbox 🪣**](https://codesandbox.io/p/github/hazae41/echalote-example-next)\n\n## Use at your own risk\n\nThis is experimental software in early development\n\n1. It has security issues\n2. Things change quickly\n\n## Features\n\n### Current features\n- 100% TypeScript and ESM\n- Zero-copy reading and writing\n- Works in the browser\n- All cryptography use either WebCrypto or reproducible WebAssembly ports of Rust implementations\n- Unsafe Tor protocol (with Ed25519, ntor, kdf-tor)\n- Meek (HTTP) transport (without domain-fronting)\n- Snowflake (WebRTC/WebSocket) transport (without domain-fronting)\n- Unsafe TLS using [Cadenas](https://github.com/hazae41/cadenas)\n- HTTP and WebSocket messaging using [Fleche](https://github.com/hazae41/fleche)\n\n### [Upcoming features](https://github.com/sponsors/hazae41)\n- Better security\n\n## Usage\n\n```typescript\nimport { createWebSocketSnowflakeStream, TorClientDuplex, Consensus } from \"@hazae41/echalote\"\nimport { Ciphers, TlsClientDuplex } from \"@hazae41/cadenas\"\n\nconst tcp = await createWebSocketSnowflakeStream(\"wss://snowflake.bamsoftware.com/\")\nconst tor = new TorClientDuplex()\n\ntcp.outer.readable.pipeTo(tor.inner.writable).catch(() =\u003e {})\ntor.inner.readable.pipeTo(tcp.outer.writable).catch(() =\u003e {})\n\nawait tor.waitOrThrow()\n\nusing circuit = await tor.createOrThrow()\nconst consensus = await Consensus.fetchOrThrow(circuit)\n\nconst middles = consensus.microdescs.filter(it =\u003e true\n  \u0026\u0026 it.flags.includes(\"Fast\")\n  \u0026\u0026 it.flags.includes(\"Stable\")\n  \u0026\u0026 it.flags.includes(\"V2Dir\"))\n\nconst exits = consensus.microdescs.filter(it =\u003e true\n  \u0026\u0026 it.flags.includes(\"Fast\")\n  \u0026\u0026 it.flags.includes(\"Stable\")\n  \u0026\u0026 it.flags.includes(\"Exit\")\n  \u0026\u0026 !it.flags.includes(\"BadExit\"))\n\nconst middle = middles[Math.floor(Math.random() * middles.length)]\nconst middle2 = await Consensus.Microdesc.fetchOrThrow(circuit, middle)\nawait circuit.extendOrThrow(middle2, AbortSignal.timeout(5000))\n\nconst exit = exits[Math.floor(Math.random() * middles.length)]\nconst exit2 = await Consensus.Microdesc.fetchOrThrow(circuit, exit)\nawait circuit.extendOrThrow(exit2, AbortSignal.timeout(5000))\n\nconst ttcp = await circuit.openOrThrow(\"twitter.com\", 443)\n\nconst ciphers = [Ciphers.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384]\nconst ttls = new TlsClientDuplex({ host_name: url.hostname, ciphers })\n\nttcp.outer.readable.pipeTo(ttls.inner.writable).catch(() =\u003e { })\nttls.inner.readable.pipeTo(ttcp.outer.writable).catch(() =\u003e { })\n\nconst response = await fetch(\"https://twitter.com\", { stream: ttls.outer })\nconst text = await response.text()\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhazae41%2Fechalote","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhazae41%2Fechalote","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhazae41%2Fechalote/lists"}