-
Notifications
You must be signed in to change notification settings - Fork 0
feat: スマホアプリ + E2E暗号化リアルタイムクラウド同期(Capacitor + Cloudflare relay) #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 16 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
e1abbe8
refactor(sync): chrome.storage.sync 直叩きを transport 抽象へ括り出す(挙動不変)
1llum1n4t1s 18ac127
feat(relay): 同期リレーの足場(B1) — Worker + VaultDO + D1 スキーマ
1llum1n4t1s 012f636
feat(relay): 客側 RelayTransport + vault 暗号モジュール(B2)
1llum1n4t1s b6cb195
chore(relay): petarin-sync D1 を作成し wrangler.toml に紐付け + ローカル e2e 整備
1llum1n4t1s c4f31ba
chore(relay): CF へデプロイし実機 e2e で検証(7 PASS) + SALT 投入
1llum1n4t1s 1edc857
feat(relay): CORS を返して拡張SW/モバイルWebViewから cross-origin で叩けるように
1llum1n4t1s 90efded
feat(sync): 拡張クライアントの cloud モード配線(B3 基盤)
1llum1n4t1s be66154
feat(manage): 同期パネルを排他3モード化 + クラウドのペアリングUI(B3)
1llum1n4t1s d189a0f
feat(mobile): chrome.storage シム + モバイル同期パスの e2e 証明(9 PASS)
1llum1n4t1s 1941544
feat(mobile): Capacitor アプリの骨組み(同期エンジン再利用・ペアリングUI・Android CI)
1llum1n4t1s bf1898a
chore(mobile): dev サーバを HTTPS+LAN 公開化(実機 iPhone/Android テスト用)
1llum1n4t1s 5dfb5c4
feat(sync): ペアリングにQRコード表示を追加(拡張デスク・モバイル両対応)
1llum1n4t1s 22bb6ea
chore(mobile): dev サーバで allowedHosts=true(トンネル経由の実機アクセスを許可)
1llum1n4t1s aa20195
feat(mobile): アプリ内QRカメラスキャナで“撮って即参加”(getUserMedia + jsQR)
1llum1n4t1s faf4be8
feat(mobile): 無課金スタンドアローンの付箋CRUD(作成/編集/削除/グループ/ゴミ箱)
1llum1n4t1s 88b87e1
fix(sync): WS 意図的切断時の無駄再接続 + catchup の seq 前進 + シム seed 直列化(Gemini レビ…
1llum1n4t1s 7cb8688
fix(relay): 鍵検証前保存/クエリ署名漏れ/seq競合/SALT/Upgrade を修正(PR#8 レビュー対応)
1llum1n4t1s b03ece4
fix(sync): クエリ署名/復号失敗時throw/fetchタイムアウト/transportスナップショット/group共有(PR#…
1llum1n4t1s 9d8e428
fix(mobile): scope=all/ペアリング再表示/解除時OFF/WS切替/reconcile追走/IAP本番封じ/aria/…
1llum1n4t1s fb47911
fix(sync): バックエンド切替時に shadow をクリアして誤削除を防ぐ(PR#8 レビュー対応)
1llum1n4t1s 0d64086
chore(relay): 本番 go-live — custom domain + workers_dev=false + rateli…
1llum1n4t1s e92c177
docs(privacy): クラウド同期(E2E暗号化・ゴミ箱本文送信)をプライバシーポリシーに明記
1llum1n4t1s File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| # ぺたりん モバイル: Android ビルド(Capacitor)。 | ||
| # web を Vite でビルド → cap add android(毎回生成・android/ は gitignore)→ cap sync → Gradle で debug APK。 | ||
| # 署名(release)は未設定=当面 debug APK を artifact 化。release 署名は keystore を Secrets に入れてから足す。 | ||
| name: mobile-android | ||
|
|
||
| on: | ||
| workflow_dispatch: {} | ||
| push: | ||
| tags: | ||
| - "mobile-v*" | ||
|
|
||
| jobs: | ||
| build: | ||
| runs-on: ubuntu-latest | ||
| defaults: | ||
| run: | ||
| working-directory: mobile | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 22 | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
|
|
||
| - name: Enable corepack (pnpm) | ||
| run: corepack enable | ||
|
|
||
| - uses: actions/setup-java@v4 | ||
| with: | ||
| distribution: temurin | ||
| java-version: "17" | ||
|
|
||
| - name: Install deps | ||
| run: pnpm install --ignore-workspace --config.dangerouslyAllowAllBuilds=true | ||
|
|
||
| - name: Build web (Vite) | ||
| run: pnpm build | ||
|
|
||
| - name: Add Android platform | ||
| run: pnpm exec cap add android | ||
|
|
||
| - name: Capacitor sync | ||
| run: pnpm exec cap sync android | ||
|
|
||
| - name: Gradle assembleDebug | ||
| working-directory: mobile/android | ||
| run: ./gradlew assembleDebug --no-daemon | ||
|
|
||
| - name: Upload APK | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: petarin-debug-apk | ||
| path: mobile/android/app/build/outputs/apk/debug/*.apk | ||
| if-no-files-found: error | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| node_modules/ | ||
| .wrangler/ | ||
| .wrangler-state/ | ||
| dist/ | ||
| *.log | ||
| .dev.vars |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| # petarin-relay | ||
|
|
||
| ぺたりんの「クラウド同期モード」用 Cloudflare Workers リレー。**任意・既定 OFF**。 | ||
| 拡張本体は `chrome.storage.local` が真実の源のまま。relay を使うのはクラウド同期を ON にした人だけ。 | ||
|
|
||
| ## 方式: notify-then-pull(store-and-forward) | ||
|
|
||
| vault(同期グループ)ごとに 1 つの `VaultDO`(Durable Object)が次を担う: | ||
|
|
||
| 1. **暗号文ストアの窓口** — 本体は D1(`petarin-sync`)。 | ||
| 2. **per-vault の seq 採番** — catchup(差分取り込み)の基準。 | ||
| 3. **Hibernatable WebSocket の fan-out ハブ** — 変更ピンを他端末へ broadcast。 | ||
|
|
||
| ``` | ||
| PC編集 → PUT /push(暗号文を D1 へ) → DO が {t:changed,d,seq} を WS broadcast | ||
| → 他端末が GET /pull?d=… で該当ドメインだけ取得 → 端末側で復号+既存マージ | ||
| ``` | ||
|
|
||
| ferry-relay の「2 peer 生パススルー」とは別物(あちらは同時オンライン前提のファイル転送用)。 | ||
|
|
||
| ## プライバシー(E2E) | ||
|
|
||
| - サーバーは**暗号文しか受け取らない**。本文は端末側 `vaultKey`(AES-GCM)で暗号化済み。 | ||
| - **ドメイン名も端末側で HMAC ハッシュ化**して送るため、サーバーは「どのサイトか」も知らない。 | ||
| - 認証は**自己完結ペアリング鍵**: vault は ECDSA P-256 鍵ペアを持ち、QR/コードで端末間に秘密鍵を渡す。 | ||
| 公開鍵は初回 first-write-wins で `VaultDO` に登録。以降は**署名で検証**(秘密はサーバーに無い)。 | ||
|
|
||
| ## プロトコル | ||
|
|
||
| vaultId はルーティングのみに使い、`SHA-256(vaultId + SALT)` でハッシュ化してから `idFromName`(漏洩時の横入り防止)。 | ||
|
|
||
| | 経路 | 認証の渡し方 | 内容 | | ||
| | --- | --- | --- | | ||
| | `GET /health` | なし | 疎通確認("OK") | | ||
| | `GET /sync?vault=…`(WS upgrade) | クエリ `ts/sig/pubkey` | ハイバネ WS を確立 | | ||
| | `PUT /push` | ヘッダ `X-Vault-*` | body `{d,c,n}` を D1 upsert→seq 採番→broadcast→`{seq}` | | ||
| | `GET /pull?d=…` | ヘッダ `X-Vault-*` | `{d,c,n,seq}`(無ければ 404) | | ||
| | `GET /catchup?since=…` | ヘッダ `X-Vault-*` | `{changes:[{d,seq}], seq}` | | ||
|
|
||
| 署名対象の正規文字列(端末側と一致させる): `vaultId\nts\nmethod\npath\nsha256hex(body)`。 | ||
| ヘッダ: `X-Vault-Id` / `X-Vault-Ts`(unix ms・±5分) / `X-Vault-Sig`(ECDSA P-256 SHA-256, raw r‖s, base64url) / 初回のみ `X-Vault-Pubkey`(SPKI base64url)。WS はこれらをクエリ `vault/ts/sig/pubkey` で渡す。 | ||
|
|
||
| ## セットアップ / デプロイ | ||
|
|
||
| ```bash | ||
| pnpm -C infra/cloudflare/relay install | ||
| pnpm -C infra/cloudflare/relay typecheck # tsc --noEmit | ||
|
|
||
| # D1 を作成し、出力 database_id を wrangler.toml に貼る | ||
| pnpm dlx wrangler d1 create petarin-sync | ||
| pnpm -C infra/cloudflare/relay d1:migrate:local # ローカルにスキーマ適用 | ||
| pnpm -C infra/cloudflare/relay dev # wrangler dev でローカル起動 | ||
|
|
||
| # 本番化(明示 GO 後) | ||
| openssl rand -hex 32 | pnpm dlx wrangler secret put SALT | ||
| pnpm -C infra/cloudflare/relay d1:migrate:remote | ||
| pnpm -C infra/cloudflare/relay deploy # Custom Domain は wrangler.toml で確定してから | ||
| ``` | ||
|
|
||
| Workers Paid($5/月・Ferry / RealTimeTranslator と共有)必須(Durable Objects のため)。 | ||
| 個人規模なら従量はほぼ枠内(アイドルはハイバネで duration 課金 0)。 | ||
|
|
||
| ## まだ無いもの(B の続き) | ||
|
|
||
| - 客側 `RelayTransport`(拡張の `setSyncTransport` に差す。HTTP + E2E 暗復号 + ドメイン HMAC)。 | ||
| - ペアリング UI(QR 生成/読取 + コード貼り付け)と manage の同期パネルのモード選択(排他 3 モード)。 | ||
| - background.js の WS 接続保持・変更ピン受信→該当ドメインだけ reconcile・前面復帰 catchup。 | ||
| - モバイル background 時の即時性(catchup のみ / Web Push 併用)はスマホアプリ設計後に決定。 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| -- ぺたりん 同期リレーの暗号文ストア(D1: petarin-sync)。 | ||
| -- サーバーは暗号文しか持たない: ciphertext/nonce は端末側 vaultKey で AES-GCM 暗号化済み、 | ||
| -- domain_hash は端末側で HMAC ハッシュ化済み(サーバーは「どのサイトか」も知らない)。 | ||
| -- vault_id はハッシュ化済み DO id 文字列(生 vaultId は保存しない)。 | ||
|
|
||
| CREATE TABLE IF NOT EXISTS notes ( | ||
| vault_id TEXT NOT NULL, -- ハッシュ化済み vault 識別子(= DO id 文字列) | ||
| domain_hash TEXT NOT NULL, -- HMAC(vaultKey, domain) の hex | ||
| ciphertext TEXT NOT NULL, -- AES-GCM 暗号文(base64url) | ||
| nonce TEXT NOT NULL, -- AES-GCM nonce/IV(base64url) | ||
| seq INTEGER NOT NULL, -- per-vault 単調増加(catchup の since 比較に使う) | ||
| updated_at INTEGER NOT NULL, -- サーバー受領時刻(ms) | ||
| PRIMARY KEY (vault_id, domain_hash) | ||
| ); | ||
|
|
||
| -- catchup(seq > since)と per-vault 走査用。 | ||
| CREATE INDEX IF NOT EXISTS idx_notes_vault_seq ON notes (vault_id, seq); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| { | ||
| "name": "petarin-relay", | ||
| "private": true, | ||
| "type": "module", | ||
| "scripts": { | ||
| "dev": "wrangler dev", | ||
| "deploy": "wrangler deploy", | ||
| "typecheck": "tsc --noEmit", | ||
| "d1:migrate:local": "wrangler d1 migrations apply petarin-sync --local", | ||
| "d1:migrate:remote": "wrangler d1 migrations apply petarin-sync --remote" | ||
| }, | ||
| "devDependencies": { | ||
| "@cloudflare/workers-types": "^4.20260526.1", | ||
| "typescript": "^5.6.0", | ||
| "wrangler": "^4.94.0" | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.