diff --git a/.github/workflows/release-wallet.yml b/.github/workflows/release-wallet.yml new file mode 100644 index 0000000..9ddf39d --- /dev/null +++ b/.github/workflows/release-wallet.yml @@ -0,0 +1,202 @@ +name: Release Desktop Wallet + +on: + push: + tags: + - 'wallet-v*' + workflow_dispatch: + inputs: + draft: + description: 'Create as draft release' + required: false + default: true + type: boolean + +env: + CARGO_TERM_COLOR: always + +permissions: + contents: write + +jobs: + build-tauri: + name: Build Wallet (${{ matrix.platform }}) + strategy: + fail-fast: false + matrix: + include: + - platform: macos-latest + target: aarch64-apple-darwin + artifact-suffix: macos-aarch64 + - platform: macos-latest + target: x86_64-apple-darwin + artifact-suffix: macos-x86_64 + - platform: windows-latest + target: x86_64-pc-windows-msvc + artifact-suffix: windows-x86_64 + + runs-on: ${{ matrix.platform }} + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install pnpm + run: npm install -g pnpm + + - name: Setup Rust + uses: dtolnay/rust-action@stable + with: + targets: ${{ matrix.target }} + + - name: Install dependencies (macOS) + if: matrix.platform == 'macos-latest' + run: | + brew install rocksdb + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + key: ${{ runner.os }}-${{ matrix.target }}-cargo-wallet-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.target }}-cargo-wallet- + + - name: Cache pnpm store + uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('apps/desktop-wallet/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install frontend dependencies + working-directory: apps/desktop-wallet + run: pnpm install + + - name: Build Tauri app + uses: tauri-apps/tauri-action@v0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # macOS code signing (optional - set these secrets in GitHub) + APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + # Tauri updater signing (optional - for auto-updates) + TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} + TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} + with: + projectPath: apps/desktop-wallet + tagName: wallet-v__VERSION__ + releaseName: 'Synor Wallet v__VERSION__' + releaseBody: | + ## Synor Desktop Wallet + + A secure desktop wallet for the Synor blockchain network with post-quantum cryptography support (Dilithium3). + + ### Installation + + **macOS:** + - Download the `.dmg` file for your architecture (Intel or Apple Silicon) + - Open the DMG and drag Synor Wallet to Applications + - First launch: Right-click → Open (to bypass Gatekeeper if not code-signed) + + **Windows:** + - Download the `.msi` installer + - Run the installer and follow the prompts + - Or download the `.exe` for portable installation + + ### Features + - 24-word BIP39 mnemonic generation + - Post-quantum Dilithium3 signatures + - OS keychain integration (macOS Keychain, Windows Credential Manager) + - System tray support + - Auto-updates (when signed) + + ### Security Note + Always verify the checksums of downloaded files. + releaseDraft: ${{ github.event.inputs.draft || true }} + prerelease: ${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') || contains(github.ref, 'rc') }} + args: --target ${{ matrix.target }} + + # Build Linux AppImage separately (needs different runner config) + build-linux: + name: Build Wallet (Linux) + runs-on: ubuntu-22.04 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install pnpm + run: npm install -g pnpm + + - name: Setup Rust + uses: dtolnay/rust-action@stable + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + libgtk-3-dev \ + libwebkit2gtk-4.0-dev \ + libappindicator3-dev \ + librsvg2-dev \ + patchelf \ + libclang-dev \ + llvm-dev + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + key: ${{ runner.os }}-cargo-wallet-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-wallet- + + - name: Cache pnpm store + uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('apps/desktop-wallet/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install frontend dependencies + working-directory: apps/desktop-wallet + run: pnpm install + + - name: Build Tauri app + uses: tauri-apps/tauri-action@v0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} + TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} + with: + projectPath: apps/desktop-wallet + tagName: wallet-v__VERSION__ + releaseName: 'Synor Wallet v__VERSION__' + releaseBody: '' + releaseDraft: ${{ github.event.inputs.draft || true }} + prerelease: ${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') || contains(github.ref, 'rc') }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 625808e..704a102 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,6 +37,10 @@ jobs: target: aarch64-apple-darwin artifact-name: synor-macos-aarch64 archive-ext: tar.gz + - os: windows-latest + target: x86_64-pc-windows-msvc + artifact-name: synor-windows-x86_64 + archive-ext: zip steps: - name: Checkout repository @@ -81,7 +85,8 @@ jobs: restore-keys: | ${{ runner.os }}-${{ matrix.target }}-cargo-target-release- - - name: Build release binaries + - name: Build release binaries (Unix) + if: runner.os != 'Windows' env: TARGET: ${{ matrix.target }} CROSS: ${{ matrix.cross }} @@ -93,7 +98,14 @@ jobs: fi cargo build --release --workspace --target "$TARGET" - - name: Prepare release archive + - name: Build release binaries (Windows) + if: runner.os == 'Windows' + env: + TARGET: ${{ matrix.target }} + run: cargo build --release --workspace --target "$env:TARGET" + + - name: Prepare release archive (Unix) + if: runner.os != 'Windows' env: TARGET: ${{ matrix.target }} ARTIFACT_NAME: ${{ matrix.artifact-name }} @@ -115,13 +127,44 @@ jobs: cd release tar czvf "../$ARTIFACT_NAME.tar.gz" * - - name: Upload release artifact + - name: Prepare release archive (Windows) + if: runner.os == 'Windows' + env: + TARGET: ${{ matrix.target }} + ARTIFACT_NAME: ${{ matrix.artifact-name }} + run: | + New-Item -ItemType Directory -Force -Path release + + # Copy binaries + Copy-Item "target/$env:TARGET/release/synord.exe" release/ -ErrorAction SilentlyContinue + Copy-Item "target/$env:TARGET/release/synor-cli.exe" release/ -ErrorAction SilentlyContinue + Copy-Item "target/$env:TARGET/release/synor-faucet.exe" release/ -ErrorAction SilentlyContinue + Copy-Item "target/$env:TARGET/release/synor-explorer.exe" release/ -ErrorAction SilentlyContinue + + # Copy documentation + Copy-Item README.md release/ -ErrorAction SilentlyContinue + Copy-Item LICENSE* release/ -ErrorAction SilentlyContinue + Copy-Item CHANGELOG.md release/ -ErrorAction SilentlyContinue + + # Create archive + Compress-Archive -Path release/* -DestinationPath "$env:ARTIFACT_NAME.zip" + + - name: Upload release artifact (Unix) + if: runner.os != 'Windows' uses: actions/upload-artifact@v4 with: name: ${{ matrix.artifact-name }} path: ${{ matrix.artifact-name }}.tar.gz retention-days: 1 + - name: Upload release artifact (Windows) + if: runner.os == 'Windows' + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.artifact-name }} + path: ${{ matrix.artifact-name }}.zip + retention-days: 1 + create-release: name: Create GitHub Release runs-on: ubuntu-latest @@ -187,7 +230,7 @@ jobs: echo "" >> CHANGELOG_BODY.md echo '```' >> CHANGELOG_BODY.md cd artifacts - find . -name "*.tar.gz" -exec sha256sum {} \; | sed 's|./[^/]*/||' >> ../CHANGELOG_BODY.md + find . \( -name "*.tar.gz" -o -name "*.zip" \) -exec sha256sum {} \; | sed 's|./[^/]*/||' >> ../CHANGELOG_BODY.md echo '```' >> CHANGELOG_BODY.md - name: Create GitHub Release @@ -199,6 +242,7 @@ jobs: prerelease: ${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') || contains(github.ref, 'rc') }} files: | artifacts/**/*.tar.gz + artifacts/**/*.zip env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Dockerfile b/Dockerfile index cfb8d48..e11ebaf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,6 +20,7 @@ WORKDIR /app # Copy manifests first (for better caching) COPY Cargo.toml Cargo.lock ./ +COPY src/ src/ COPY crates/ crates/ COPY apps/ apps/ COPY contracts/ contracts/ diff --git a/Dockerfile.explorer b/Dockerfile.explorer index 0454940..5ea03ff 100644 --- a/Dockerfile.explorer +++ b/Dockerfile.explorer @@ -19,6 +19,7 @@ WORKDIR /app # Copy manifests COPY Cargo.toml Cargo.lock ./ +COPY src/ src/ COPY crates/ crates/ COPY apps/ apps/ diff --git a/Dockerfile.faucet b/Dockerfile.faucet index 63a04ff..b6c8e4c 100644 --- a/Dockerfile.faucet +++ b/Dockerfile.faucet @@ -20,6 +20,7 @@ WORKDIR /app # Copy manifests first (for better caching) COPY Cargo.toml Cargo.lock ./ +COPY src/ src/ COPY crates/ crates/ COPY apps/ apps/ diff --git a/docs/CODE_SIGNING.md b/docs/CODE_SIGNING.md new file mode 100644 index 0000000..b68081e --- /dev/null +++ b/docs/CODE_SIGNING.md @@ -0,0 +1,171 @@ +# Code Signing Setup Guide + +This guide explains how to set up code signing for Synor desktop applications. + +## Why Code Sign? + +Code signing provides: +- **User trust**: No "unknown developer" warnings on macOS/Windows +- **Auto-updates**: Tauri's updater requires signed binaries +- **Security**: Users can verify the software hasn't been tampered with + +## macOS Code Signing + +### Prerequisites + +1. **Apple Developer Account** ($99/year): https://developer.apple.com/programs/enroll/ +2. **Developer ID Application Certificate**: For distributing outside the Mac App Store + +### Create Certificates + +1. Go to https://developer.apple.com/account/resources/certificates/list +2. Click "+" to create a new certificate +3. Select "Developer ID Application" +4. Follow the instructions to create a CSR from Keychain Access +5. Download and install the certificate + +### Export for CI/CD + +```bash +# Export certificate as .p12 from Keychain Access +# Then base64 encode it for GitHub secrets: +base64 -i certificate.p12 -o certificate_base64.txt +``` + +### GitHub Secrets Required + +| Secret | Description | How to Get | +|--------|-------------|------------| +| `APPLE_CERTIFICATE` | Base64-encoded .p12 certificate | Export from Keychain Access | +| `APPLE_CERTIFICATE_PASSWORD` | Password for .p12 | Set when exporting | +| `APPLE_SIGNING_IDENTITY` | Certificate name | e.g., "Developer ID Application: G1 Technologies (TEAMID)" | +| `APPLE_ID` | Your Apple ID email | Your developer account email | +| `APPLE_PASSWORD` | App-specific password | Generate at appleid.apple.com | +| `APPLE_TEAM_ID` | 10-character team ID | Find at developer.apple.com/account | + +### Generate App-Specific Password + +1. Go to https://appleid.apple.com/account/manage +2. Sign in with your Apple ID +3. Under "App-Specific Passwords", click "Generate Password" +4. Name it "Synor CI" and save the password + +### Notarization + +Apple requires notarization for apps distributed outside the App Store. The Tauri action handles this automatically when the secrets are set. + +## Windows Code Signing + +### Options + +1. **OV (Organization Validation) Certificate**: ~$200-500/year + - From providers like DigiCert, Sectigo, GlobalSign + - Requires business verification + +2. **EV (Extended Validation) Certificate**: ~$400-700/year + - Higher trust level, no SmartScreen warnings + - Requires hardware token (USB) + +### Purchase Certificate + +1. Choose a provider (DigiCert, Sectigo, GlobalSign, etc.) +2. Complete organization validation +3. Receive certificate file (.pfx) + +### GitHub Secrets Required + +| Secret | Description | +|--------|-------------| +| `WINDOWS_CERTIFICATE` | Base64-encoded .pfx certificate | +| `WINDOWS_CERTIFICATE_PASSWORD` | Password for .pfx | + +### Encode Certificate + +```powershell +[Convert]::ToBase64String([IO.File]::ReadAllBytes("certificate.pfx")) | Out-File certificate_base64.txt +``` + +## Tauri Auto-Update Signing + +### Generate Signing Keypair + +```bash +# Generate keypair (do this once, store securely) +cargo tauri signer generate -w ~/.tauri/synor-wallet.key +``` + +This outputs: +- Private key (save to `TAURI_SIGNING_PRIVATE_KEY` secret) +- Public key (already in `tauri.conf.json`) + +### GitHub Secrets Required + +| Secret | Description | +|--------|-------------| +| `TAURI_SIGNING_PRIVATE_KEY` | Private key from signer generate | +| `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` | Password if you set one | + +### Update tauri.conf.json + +The public key is already configured in `apps/desktop-wallet/src-tauri/tauri.conf.json`: + +```json +"updater": { + "endpoints": [ + "https://releases.synor.io/wallet/{{target}}/{{arch}}/{{current_version}}" + ], + "pubkey": "YOUR_PUBLIC_KEY_HERE" +} +``` + +## Setting Up GitHub Secrets + +1. Go to your repository on GitHub +2. Navigate to Settings → Secrets and variables → Actions +3. Click "New repository secret" for each secret + +## Testing Without Signing + +For development and testing, you can build without signing: + +```bash +cd apps/desktop-wallet +pnpm tauri:build +``` + +Users will see warnings, but the app will still work. + +## Verification + +### macOS + +```bash +# Check if app is signed +codesign -dv --verbose=4 "Synor Wallet.app" + +# Check if notarized +spctl -a -v "Synor Wallet.app" +``` + +### Windows + +```powershell +# Check signature +Get-AuthenticodeSignature "Synor Wallet.exe" +``` + +## Cost Summary + +| Item | Cost (Annual) | +|------|---------------| +| Apple Developer Program | $99 | +| Windows OV Certificate | $200-500 | +| Windows EV Certificate | $400-700 | + +**Minimum recommended**: Apple + Windows OV = ~$300-600/year + +## Resources + +- [Tauri Code Signing Guide](https://tauri.app/guides/building/code-signing/) +- [Apple Developer Documentation](https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution) +- [Microsoft Authenticode](https://docs.microsoft.com/en-us/windows/win32/seccrypto/authenticode)