diff --git a/apps/browser/.gitignore b/apps/browser/.gitignore
index 077bd14..46a4faa 100644
--- a/apps/browser/.gitignore
+++ b/apps/browser/.gitignore
@@ -10,3 +10,7 @@ release
# Compiled scripts (TypeScript sources in scripts-src/)
scripts/*.js
+
+# Environment variables (contains sensitive data)
+.env.local
+.env.*.local
diff --git a/apps/browser/CODESIGN_SETUP.md b/apps/browser/CODESIGN_SETUP.md
new file mode 100644
index 0000000..772bf08
--- /dev/null
+++ b/apps/browser/CODESIGN_SETUP.md
@@ -0,0 +1,212 @@
+# Code Signing and Notarization Setup Guide
+
+This document explains how to set up code signing and notarization for distributing aka-browser on macOS.
+
+## 1. Create Developer ID Application Certificate
+
+### 1-1. Generate CSR (Certificate Signing Request)
+
+1. Open **Keychain Access** app
+2. Menu: **Keychain Access > Certificate Assistant > Request a Certificate from a Certificate Authority...**
+3. Enter the following information:
+ - User Email Address: Your Apple Developer account email
+ - Common Name: Your name
+ - CA Email Address: Leave empty
+ - Select **"Saved to disk"**
+ - Check **"Let me specify key pair information"**
+4. Choose save location (e.g., `~/Desktop/CertificateSigningRequest.certSigningRequest`)
+5. Key Size: **2048 bits**, Algorithm: **RSA**
+6. Click **Continue**
+
+### 1-2. Issue Certificate from Apple Developer Website
+
+1. Visit https://developer.apple.com/account/resources/certificates/list
+2. Click **"+"** button
+3. Select **"Developer ID Application"** (for distribution outside Mac App Store)
+4. Click **Continue**
+5. Upload the CSR file created above
+6. Click **Continue**
+7. Download certificate (`.cer` file)
+8. **Double-click** the downloaded file to install it in Keychain
+
+### 1-3. Verify Certificate
+
+Verify the certificate is installed by running this command in Terminal:
+
+```bash
+security find-identity -v -p codesigning
+```
+
+You should see output like:
+```
+1) XXXXXX "Developer ID Application: Your Name (TEAM_ID)"
+```
+
+## 2. Generate App-Specific Password
+
+An App-Specific Password is required for notarization.
+
+1. Visit https://appleid.apple.com/account/manage
+2. **Sign in** (Two-factor authentication required)
+3. Click **App-Specific Passwords** in the **Security** section
+4. Click **"+"** button
+5. Enter a name (e.g., "aka-browser notarization")
+6. Copy the generated password (e.g., `abcd-efgh-ijkl-mnop`)
+7. **Save it securely** (you won't be able to see it again)
+
+## 3. Find Your Team ID
+
+1. Visit https://developer.apple.com/account
+2. Find your **Team ID** in the **Membership Details** section (e.g., `AB12CD34EF`)
+
+## 4. Set Environment Variables
+
+### 4-1. Method 1: .env File (Recommended)
+
+Create a `.env.local` file in the project root:
+
+```bash
+# /Users/hm/Documents/GitHub/aka-browser/apps/browser/.env.local
[email protected]
+APPLE_APP_SPECIFIC_PASSWORD=abcd-efgh-ijkl-mnop
+APPLE_TEAM_ID=AB12CD34EF
+```
+
+**Warning**: Add `.env.local` to `.gitignore` to prevent committing it to Git!
+
+### 4-2. Method 2: System Environment Variables
+
+Add to `~/.zshrc` or `~/.bash_profile`:
+
+```bash
+export APPLE_ID="[email protected]"
+export APPLE_APP_SPECIFIC_PASSWORD="abcd-efgh-ijkl-mnop"
+export APPLE_TEAM_ID="AB12CD34EF"
+```
+
+After saving:
+```bash
+source ~/.zshrc
+```
+
+### 4-3. Method 3: Specify During Build
+
+```bash
+APPLE_ID="[email protected]" \
+APPLE_APP_SPECIFIC_PASSWORD="abcd-efgh-ijkl-mnop" \
+APPLE_TEAM_ID="AB12CD34EF" \
+pnpm run package
+```
+
+## 5. Build and Notarize
+
+### 5-1. Install Dependencies
+
+```bash
+cd /Users/hm/Documents/GitHub/aka-browser/apps/browser
+pnpm install
+```
+
+### 5-2. Compile Build Scripts
+
+```bash
+pnpm run build:scripts
+```
+
+### 5-3. Build and Notarize App
+
+```bash
+pnpm run package
+```
+
+Build process:
+1. ✅ Build app
+2. ✅ EVS signing (Widevine CDM)
+3. ✅ Code signing (Developer ID Application)
+4. ✅ Notarization (upload to Apple servers)
+5. ✅ DMG creation
+
+### 5-4. Verify Notarization
+
+After the build completes, verify notarization status with:
+
+```bash
+spctl -a -vv -t install release/mac-arm64/aka-browser.app
+```
+
+Successful output:
+```
+release/mac-arm64/aka-browser.app: accepted
+source=Notarized Developer ID
+```
+
+## 6. Troubleshooting
+
+### Cannot Find Certificate
+
+```
+Error: Cannot find identity matching "Developer ID Application"
+```
+
+**Solution**:
+1. Verify the certificate is installed in Keychain
+2. Check if the certificate has expired
+3. Run `security find-identity -v -p codesigning` to verify
+
+### Notarization Failed
+
+```
+Error: Notarization failed
+```
+
+**Solution**:
+1. Verify Apple ID, App-Specific Password, and Team ID are correct
+2. Ensure two-factor authentication is enabled
+3. Check if App-Specific Password is valid (it may have expired)
+
+### Check Notarization Logs
+
+```bash
+xcrun notarytool log --apple-id "[email protected]" \
+ --password "abcd-efgh-ijkl-mnop" \
+ --team-id "AB12CD34EF" \
+
+```
+
+## 7. Distribution
+
+Notarized DMG files are created in the `release/` directory:
+
+- `release/aka-browser-0.1.0-arm64.dmg` (Apple Silicon)
+- `release/aka-browser-0.1.0-x64.dmg` (Intel)
+- `release/aka-browser-0.1.0-universal.dmg` (Universal)
+
+You can upload these files to the internet for distribution. Users won't see the "damaged" message when downloading and installing.
+
+## 8. Security Precautions
+
+- ❌ **NEVER commit to Git**:
+ - App-Specific Password
+ - `.env.local` file
+ - Certificate files (`.p12`, `.cer`)
+
+- ✅ **Store securely**:
+ - Use password managers like 1Password or Bitwarden
+ - Use encrypted channels when sharing with team members
+
+## 9. CI/CD Setup (GitHub Actions)
+
+Add the following variables to GitHub Secrets:
+
+- `APPLE_ID`
+- `APPLE_APP_SPECIFIC_PASSWORD`
+- `APPLE_TEAM_ID`
+- `CSC_LINK` (certificate `.p12` file encoded in base64)
+- `CSC_KEY_PASSWORD` (certificate password)
+
+For detailed setup, refer to the electron-builder documentation:
+https://www.electron.build/code-signing
+
+---
+
+**Questions**: Please create an issue if you encounter any problems.
diff --git a/apps/browser/CODESIGN_START.md b/apps/browser/CODESIGN_START.md
new file mode 100644
index 0000000..48eae34
--- /dev/null
+++ b/apps/browser/CODESIGN_START.md
@@ -0,0 +1,106 @@
+# Quick Start Guide
+
+## 🚀 Get Started Now
+
+### 1. Issue Developer ID Application Certificate
+
+**Takes 5 minutes**
+
+1. https://developer.apple.com/account/resources/certificates/list
+2. Click "+" button → Select "Developer ID Application"
+3. Upload CSR file (generate using method below)
+4. Download and double-click to install
+
+**How to generate CSR:**
+```
+Keychain Access app → Menu → Keychain Access → Certificate Assistant → Request a Certificate from a Certificate Authority...
+→ Enter email → Select "Saved to disk" → Save
+```
+
+### 2. Generate App-Specific Password
+
+**Takes 2 minutes**
+
+1. https://appleid.apple.com/account/manage
+2. Security → App-Specific Passwords → "+" button
+3. Enter name (e.g., "aka-browser") → Generate
+4. **Copy password** (you won't be able to see it again!)
+
+### 3. Find Your Team ID
+
+**Takes 1 minute**
+
+1. https://developer.apple.com/account
+2. Membership Details → Copy Team ID (e.g., `AB12CD34EF`)
+
+### 4. Set Environment Variables
+
+Create a `.env.local` file in the project root:
+
+```bash
+# /Users/hm/Documents/GitHub/aka-browser/apps/browser/.env.local
[email protected]
+APPLE_APP_SPECIFIC_PASSWORD=abcd-efgh-ijkl-mnop
+APPLE_TEAM_ID=AB12CD34EF
+```
+
+**Or** run directly in terminal:
+
+```bash
+export APPLE_ID="[email protected]"
+export APPLE_APP_SPECIFIC_PASSWORD="abcd-efgh-ijkl-mnop"
+export APPLE_TEAM_ID="AB12CD34EF"
+```
+
+### 5. Build and Notarize
+
+```bash
+cd /Users/hm/Documents/GitHub/aka-browser/apps/browser
+pnpm run package
+```
+
+**Build process (approx. 5-10 minutes):**
+1. ✅ Build app
+2. ✅ EVS signing (Widevine)
+3. ✅ Code signing
+4. ✅ Notarization (upload to Apple servers)
+5. ✅ DMG creation
+
+### 6. Done!
+
+Generated file: `release/aka-browser-0.1.0-arm64.dmg`
+
+You can now upload this file to the internet for distribution.
+Users won't see the **"damaged"** message when downloading! ✨
+
+---
+
+## 🔍 Verify Notarization
+
+```bash
+spctl -a -vv -t install release/mac-arm64/aka-browser.app
+```
+
+On success:
+```
+accepted
+source=Notarized Developer ID
+```
+
+---
+
+## ❓ Troubleshooting
+
+### Cannot Find Certificate
+```bash
+security find-identity -v -p codesigning
+```
+→ Check if "Developer ID Application" certificate exists
+
+### Notarization Failed
+- Verify Apple ID, Password, and Team ID are correct
+- Ensure two-factor authentication is enabled
+
+---
+
+**For detailed instructions**: See `CODESIGN_SETUP.md`
diff --git a/apps/browser/package.json b/apps/browser/package.json
index 9ca6384..2179953 100644
--- a/apps/browser/package.json
+++ b/apps/browser/package.json
@@ -32,6 +32,7 @@
"author": "hmmhmmhm",
"license": "MIT",
"devDependencies": {
+ "@electron/notarize": "^2.5.0",
"@tailwindcss/vite": "^4.1.14",
"@types/node": "^20.11.0",
"@types/react": "^19.2.2",
@@ -39,6 +40,7 @@
"@vitejs/plugin-react": "^5.0.4",
"concurrently": "^8.2.2",
"cross-env": "^10.1.0",
+ "dotenv": "^17.2.3",
"electron": "github:castlabs/electron-releases#v38.0.0+wvcus",
"electron-builder": "^26.0.12",
"tailwindcss": "^4.1.14",
@@ -66,11 +68,15 @@
"!node_modules/**/*"
],
"afterPack": "scripts/evs-sign.js",
+ "afterSign": "scripts/notarize.js",
"mac": {
"target": [
{
"target": "dmg",
- "arch": ["x64", "arm64"]
+ "arch": [
+ "x64",
+ "arm64"
+ ]
}
],
"category": "public.app-category.developer-tools",
@@ -78,8 +84,7 @@
"hardenedRuntime": true,
"gatekeeperAssess": false,
"entitlements": "build/entitlements.mac.plist",
- "entitlementsInherit": "build/entitlements.mac.plist",
- "identity": null
+ "entitlementsInherit": "build/entitlements.mac.plist"
},
"win": {
"target": "nsis",
diff --git a/apps/browser/scripts-src/notarize.ts b/apps/browser/scripts-src/notarize.ts
new file mode 100644
index 0000000..eaa5fa9
--- /dev/null
+++ b/apps/browser/scripts-src/notarize.ts
@@ -0,0 +1,44 @@
+import { notarize } from '@electron/notarize';
+import * as path from 'path';
+import * as dotenv from 'dotenv';
+
+// Load .env.local file
+dotenv.config({ path: path.join(__dirname, '..', '.env.local') });
+
+export default async function notarizing(context: any) {
+ const { electronPlatformName, appOutDir } = context;
+
+ // Only notarize on macOS
+ if (electronPlatformName !== 'darwin') {
+ return;
+ }
+
+ // Check environment variables
+ const appleId = process.env.APPLE_ID;
+ const appleIdPassword = process.env.APPLE_APP_SPECIFIC_PASSWORD;
+ const teamId = process.env.APPLE_TEAM_ID;
+
+ if (!appleId || !appleIdPassword || !teamId) {
+ console.warn('⚠️ Skipping notarization. Please set environment variables:');
+ console.warn(' APPLE_ID, APPLE_APP_SPECIFIC_PASSWORD, APPLE_TEAM_ID');
+ return;
+ }
+
+ const appName = context.packager.appInfo.productFilename;
+ const appPath = path.join(appOutDir, `${appName}.app`);
+
+ console.log(`🔐 Starting notarization: ${appPath}`);
+
+ try {
+ await notarize({
+ appPath,
+ appleId,
+ appleIdPassword,
+ teamId,
+ });
+ console.log('✅ Notarization completed!');
+ } catch (error) {
+ console.error('❌ Notarization failed:', error);
+ throw error;
+ }
+}
diff --git a/apps/browser/scripts/notarize.d.ts b/apps/browser/scripts/notarize.d.ts
new file mode 100644
index 0000000..c04f366
--- /dev/null
+++ b/apps/browser/scripts/notarize.d.ts
@@ -0,0 +1 @@
+export default function notarizing(context: any): Promise;
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 55d8485..cb27c4f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -30,6 +30,9 @@ importers:
specifier: ^18.3.1
version: 18.3.1([email protected])
devDependencies:
+ '@electron/notarize':
+ specifier: ^2.5.0
+ version: 2.5.0
'@tailwindcss/vite':
specifier: ^4.1.14
version: 4.1.14([email protected](@types/[email protected])([email protected])([email protected]))
@@ -51,6 +54,9 @@ importers:
cross-env:
specifier: ^10.1.0
version: 10.1.0
+ dotenv:
+ specifier: ^17.2.3
+ version: 17.2.3
electron:
specifier: github:castlabs/electron-releases#v38.0.0+wvcus
version: https://codeload.github.com/castlabs/electron-releases/tar.gz/678b5c7761825c5af936f5c67a9101f3fc6ab750
@@ -1095,6 +1101,10 @@ packages:
resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==}
engines: {node: '>=12'}
+ [email protected]:
+ resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
+ engines: {node: '>=12'}
+
[email protected]:
resolution: {integrity: sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==}
engines: {node: '>=10'}
@@ -2455,7 +2465,7 @@ snapshots:
'@babel/parser': 7.28.4
'@babel/template': 7.27.2
'@babel/types': 7.28.4
- debug: 4.4.1
+ debug: 4.4.3
transitivePeerDependencies:
- supports-color
@@ -3513,6 +3523,8 @@ snapshots:
[email protected]: {}
+ [email protected]: {}
+
[email protected]: {}
[email protected]: