{"id":50751434,"url":"https://github.com/payneteasy/key-pair-factory","last_synced_at":"2026-06-11T01:30:36.633Z","repository":{"id":362392450,"uuid":"1257577074","full_name":"payneteasy/key-pair-factory","owner":"payneteasy","description":"Native cross-platform desktop app that generates an RSA-4096 key pair (PKCS#8, optional PKCS#1) for the Payneteasy API — a local, no-terminal replacement for the OpenSSL CLI","archived":false,"fork":false,"pushed_at":"2026-06-04T04:01:54.000Z","size":3257,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-04T04:09:08.742Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/payneteasy.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-02T20:13:02.000Z","updated_at":"2026-06-04T04:00:21.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/payneteasy/key-pair-factory","commit_stats":null,"previous_names":["payneteasy/key-pair-factory"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/payneteasy/key-pair-factory","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/payneteasy%2Fkey-pair-factory","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/payneteasy%2Fkey-pair-factory/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/payneteasy%2Fkey-pair-factory/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/payneteasy%2Fkey-pair-factory/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/payneteasy","download_url":"https://codeload.github.com/payneteasy/key-pair-factory/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/payneteasy%2Fkey-pair-factory/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34178819,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-10T02:00:07.152Z","response_time":89,"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":[],"created_at":"2026-06-11T01:30:34.807Z","updated_at":"2026-06-11T01:30:36.615Z","avatar_url":"https://github.com/payneteasy.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Payneteasy API Key Pair Factory (Tauri 2 + React + Rust)\n\nNative cross-platform desktop app that generates an RSA-4096 key pair (PKCS#8,\noptional PKCS#1) for the Payneteasy API — a local, no-terminal replacement for\nthe OpenSSL CLI.\n\n📲 **[Download on the Mac App Store](https://apps.apple.com/us/app/payneteasy-api-keypair-factory/id6775522326?mt=12)**\n\n## Download\n\nPre-built installers are attached to every [GitHub release][releases]. Latest\n(**1.0.1**):\n\n| Platform | File |\n|---|---|\n| macOS | [`Payneteasy.API.Key.Pair.Factory_1.0.1_universal.dmg`](https://github.com/payneteasy/key-pair-factory/releases/download/1.0.1/Payneteasy.API.Key.Pair.Factory_1.0.1_universal.dmg) |\n| Windows (installer) | [`Payneteasy.API.Key.Pair.Factory_1.0.1_x64-setup.exe`](https://github.com/payneteasy/key-pair-factory/releases/download/1.0.1/Payneteasy.API.Key.Pair.Factory_1.0.1_x64-setup.exe) |\n| Windows (MSI) | [`Payneteasy.API.Key.Pair.Factory_1.0.1_x64_en-US.msi`](https://github.com/payneteasy/key-pair-factory/releases/download/1.0.1/Payneteasy.API.Key.Pair.Factory_1.0.1_x64_en-US.msi) |\n| Windows (portable) | [`Payneteasy.API.Key.Pair.Factory_1.0.1.portable.exe`](https://github.com/payneteasy/key-pair-factory/releases/download/1.0.1/Payneteasy.API.Key.Pair.Factory_1.0.1.portable.exe) |\n| Linux (AppImage) | [`Payneteasy.API.Key.Pair.Factory_1.0.1_amd64.AppImage`](https://github.com/payneteasy/key-pair-factory/releases/download/1.0.1/Payneteasy.API.Key.Pair.Factory_1.0.1_amd64.AppImage) |\n| Linux (.deb) | [`Payneteasy.API.Key.Pair.Factory_1.0.1_amd64.deb`](https://github.com/payneteasy/key-pair-factory/releases/download/1.0.1/Payneteasy.API.Key.Pair.Factory_1.0.1_amd64.deb) |\n| Linux (.rpm) | [`Payneteasy.API.Key.Pair.Factory-1.0.1-1.x86_64.rpm`](https://github.com/payneteasy/key-pair-factory/releases/download/1.0.1/Payneteasy.API.Key.Pair.Factory-1.0.1-1.x86_64.rpm) |\n| Linux (Flatpak) | [`Payneteasy.API.Key.Pair.Factory_1.0.1.flatpak`](https://github.com/payneteasy/key-pair-factory/releases/download/1.0.1/Payneteasy.API.Key.Pair.Factory_1.0.1.flatpak) |\n| Linux (binary) | [`Payneteasy.API.Key.Pair.Factory_1.0.1.linux.x64.bin`](https://github.com/payneteasy/key-pair-factory/releases/download/1.0.1/Payneteasy.API.Key.Pair.Factory_1.0.1.linux.x64.bin) |\n\n[releases]: https://github.com/payneteasy/key-pair-factory/releases/latest\n\n## What it's for\n\nThe Payneteasy API supports an **OAuth RSA-SHA256** request-authentication method\nthat requires merchants to provide an RSA public key. The official\n[documentation][doc] walks you through generating the key pair by hand with\n`openssl`:\n\n```bash\n# generate the PKCS#8 private key (RSA-4096)\nopenssl genpkey -algorithm RSA -out private_key_pkcs_8.pem -pkeyopt rsa_keygen_bits:4096\n# derive the public key to send to support\nopenssl rsa -pubout -in private_key_pkcs_8.pem -out public_key.pem\n# convert to a PKCS#1 container for the doc's request builders\nopenssl rsa -traditional -in private_key_pkcs_8.pem -out private_key_pkcs_1.pem\n```\n\nThis app does exactly that — same algorithm, same key size, same PEM formats —\nwithout a terminal or an OpenSSL install. Everything runs locally; the private\nkey never leaves your machine. Hand the generated `public_key.pem` to your\nPayneteasy account manager and keep the private key for signing requests.\n\n[doc]: https://doc.payneteasy.com/integration/general_api_usage/request_authentication_methods/oauth.html#oauth-rsa-sha256\n\n## Screenshots\n\n| Welcome | Configure | Done |\n|---|---|---|\n| ![Welcome screen](docs/screenshots/01-welcome.png) | ![Configure screen](docs/screenshots/02-configure.png) | ![Done screen](docs/screenshots/03-done.png) |\n\n## Stack\n\n| Layer | Choice |\n|---|---|\n| Shell | Tauri 2.x (native window, no Electron) |\n| Frontend | React 18 + TypeScript (Vite) |\n| Backend | Rust — all crypto + filesystem work |\n| Crypto | `rsa`, `pkcs8` (PBES2 / AES-256-CBC), `pkcs1`, `rand` (`OsRng`), `zeroize` |\n| Plugins | `dialog`, `opener`, `clipboard-manager`, `store` |\n\n## Layout\n\n```\n├── src/                    # React frontend\n│   ├── App.tsx             # 4-step wizard state machine + chrome\n│   ├── ipc.ts              # typed wrappers around Tauri commands + plugins\n│   ├── util.ts             # slug helper, shared types\n│   ├── components/         # Stepper, KeyDisplay, icons\n│   ├── screens/            # Welcome, Configure, Generate, Done\n│   └── styles.css          # copied verbatim from the prototype\n└── src-tauri/\n    ├── src/\n    │   ├── lib.rs          # Builder, command registration\n    │   ├── keygen.rs       # RSA generation, PEM encoding, + unit tests\n    │   ├── filesystem.rs   # atomic 0o600 writes, cleanup guard\n    │   └── error.rs        # KeyGenError → { kind, message }\n    ├── capabilities/       # plugin permission grants\n    ├── icons/              # app icons (.png / .icns / .ico)\n    └── tauri.conf.json\n```\n\n## Develop\n\n```bash\nnpm install\nnpm run tauri dev          # launches the desktop app with HMR\n```\n\n## Build installers\n\n```bash\nnpm run tauri build        # .dmg/.app (macOS), .msi (Windows), .deb/.rpm/.AppImage (Linux)\n```\n\n## Test\n\n```bash\nnpm run build                       # typecheck + bundle the frontend\ncd src-tauri \u0026\u0026 cargo test --lib    # crypto golden tests (PEM headers, bit length, encrypted round-trip)\n\n# Rust lint (same checks as CI; toolchain pinned in src-tauri/rust-toolchain.toml)\ncd src-tauri \u0026\u0026 cargo fmt --all -- --check\ncd src-tauri \u0026\u0026 cargo clippy --all-targets --locked -- -D warnings\n```\n\n## Crypto contract\n\n- RSA via `OsRng`; default **4096** bits (2048 / 3072 available in Advanced mode).\n- Private container: **PKCS#8** PEM (`LF`). With a password → PKCS#8 **encrypted**\n  (PBES2 + AES-256-CBC + HMAC-SHA-256).\n- Optional companion: **PKCS#1** PEM (always unencrypted — for the doc request builders).\n- Public key: **SPKI** PEM.\n- Files: `{slug}{_prod?}_private.pem`, `{slug}{_prod?}_public.pem`,\n  `{slug}{_prod?}_private_pkcs1.pem` — written atomically (temp → rename) with\n  `0o600` permissions on Unix. Secret PEM buffers are zeroized after use.\n- Fully offline — no network calls except the external \"Read documentation\" link.\n\n## Notes / intentional choices\n\n- The window uses `decorations: false` and renders the prototype's own framed\n  card (title bar + theme toggle) so the app matches the handoff screenshots\n  one-to-one. Resize/drag is wired through the title bar's drag region.\n- Theme (light/dark) and detail mode (beginner/advanced) persist via\n  `tauri-plugin-store`; first run defaults to the OS colour scheme.\n- **Hardening TODO:** `app.security.csp` is currently `null` for dev convenience.\n  For production, lock it to `default-src 'self'` and bundle the Geist fonts\n  locally (replace the Google Fonts `@import` in `styles.css`) so the strict CSP\n  needs no external `style-src`/`font-src`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpayneteasy%2Fkey-pair-factory","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpayneteasy%2Fkey-pair-factory","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpayneteasy%2Fkey-pair-factory/lists"}