mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 23:21:08 +02:00
Mirror of github.com/Memo-2023/mana-monorepo
Extends the browser-side vault client with five new methods that
mirror the server-side Phase 9 routes, plus a new
`awaiting-recovery-code` state that pauses the unlock mid-flow
when the server is in zero-knowledge mode.
VaultUnlockState gains a fourth variant
---------------------------------------
| { status: 'awaiting-recovery-code' }
This is the state the client sits in between calling unlock()
(which received a recovery blob from GET /key) and the user typing
their recovery code into the UI. The settings page status badge
got updated to render this case as "🔑 Recovery-Code erforderlich".
New closure state inside createVaultClient
------------------------------------------
- pendingRecoveryBlob: stash for the recovery wrap returned by
GET /key in zero-knowledge mode. unlockWithRecoveryCode reads
from here so the second round of input doesn't need a re-fetch.
- cachedUnwrappedMkBytes: kept ONLY when the vault was unlocked
via the recovery code path AND the user might want to disable
zero-knowledge later (which needs to hand the MK back to the
server for KEK re-wrapping). The standard unlock path leaves
this null because the server already has the KEK wrap. Wiped
on lock(), on disable success, and on any state transition
that destroys the master key.
Modified existing methods
-------------------------
- unlock(): branches on the response shape. If the server returns
a recovery blob (zero-knowledge mode), stash it via
awaitRecoveryCode() and return state='awaiting-recovery-code'.
Otherwise unwrap as before. Same fork applies to the /init
fallback path.
- rotate(): if the server somehow returned a ZK shape (it should
never — rotate is forbidden in ZK mode server-side), bail with
a server error instead of silently misinterpreting bytes.
- lock(): also clears pendingRecoveryBlob + wipes
cachedUnwrappedMkBytes.
New methods (all wired into the returned VaultClient)
-----------------------------------------------------
- setupRecoveryCode(): generates a fresh 32-byte recovery secret,
derives the wrap key, re-fetches the active master key in
extractable form, seals it, posts to /recovery-wrap, returns
the formatted recovery code for the UI to display. Wipes both
raw byte references after the seal. Caller is responsible for
clearing the formatted string from memory once the user has
confirmed they backed it up.
- clearRecoveryCode(): DELETE /recovery-wrap. Server enforces the
"not while ZK is active" rule.
- enableZeroKnowledge(): POST /zero-knowledge { enable: true }.
Maps RECOVERY_WRAP_MISSING server response to a clear "set up
a recovery code first" client error.
- disableZeroKnowledge(): POST /zero-knowledge { enable: false,
masterKey: base64 }. Reads the cached MK bytes, base64-encodes,
sends. Wipes the cache after success.
- unlockWithRecoveryCode(code): completes the flow that started
in unlock(). Parses the user-typed code (RecoveryCodeFormatError
bubbles up if the shape is wrong), derives the wrap key, runs a
single inline AES-GCM decrypt on the stashed blob (yields both
the raw bytes for the cache AND a non-extractable runtime key
for the provider), wipes raw bytes, transitions to 'unlocked'.
Generic error message on failure ("wrong recovery code or
corrupted vault") so an attacker can't distinguish wrong-code
from tampered-blob. Stays in 'awaiting-recovery-code' on
failure so the user can retry without a re-fetch.
Drive-by stale test fix
-----------------------
aes.test.ts had an assertion from Phase 1 that `tasks` and `events`
return null because they were on enabled:false. Phase 7.1 flipped
both tables on, so the assertion has been failing since that
commit. Replaced the test with a stable negative case
(non-existent table name) that doesn't shift with each rollout
phase.
Test results: 78/78 crypto tests pass after the fix.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
||
|---|---|---|
| .changeset | ||
| .claude | ||
| .github | ||
| .husky | ||
| apps | ||
| docker | ||
| docs | ||
| games | ||
| load-tests | ||
| NewAppIdeas/Roblox Reimagined | ||
| packages | ||
| patches | ||
| scripts | ||
| services | ||
| tests/e2e | ||
| .dockerignore | ||
| .editorconfig | ||
| .env.development | ||
| .env.macmini.example | ||
| .gitignore | ||
| .npmrc | ||
| .nvmrc | ||
| .prettierignore | ||
| .prettierrc.json | ||
| CLAUDE.md | ||
| cloudflared-config.yml | ||
| docker-compose.dev.yml | ||
| docker-compose.macmini.yml | ||
| eslint.config.mjs | ||
| gift-codes-2026-02-14.txt | ||
| lint-staged.config.js | ||
| mac-mini-setup.sh | ||
| package.json | ||
| playwright.config.ts | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| test-chat-auth.sh | ||
| TROUBLESHOOTING.md | ||
| turbo.json | ||
| vitest.config.ts | ||
Mana Monorepo
Monorepo containing all Mana projects — a self-hosted multi-app ecosystem with shared packages and unified tooling.
Projects
| Project | Description | Apps |
|---|---|---|
| mana | Multi-app ecosystem platform | Expo mobile, SvelteKit web |
| chat | AI chat application | NestJS backend, Expo mobile, SvelteKit web, Astro landing |
| todo | Task management | NestJS backend, SvelteKit web, Astro landing |
| calendar | Calendar & scheduling | NestJS backend, SvelteKit web, Astro landing |
| clock | Pomodoro & time tracking | NestJS backend, SvelteKit web, Astro landing |
| contacts | Contact management | NestJS backend, SvelteKit web |
| picture | AI image generation | NestJS backend, Expo mobile, SvelteKit web, Astro landing |
| cards | Card/deck management | NestJS backend, Expo mobile, SvelteKit web |
| zitare | Daily inspiration quotes | NestJS backend, Expo mobile, SvelteKit web, Astro landing |
| mukke | Music player | NestJS backend, SvelteKit web |
| planta | Plant care tracker | NestJS backend, SvelteKit web |
| storage | Cloud storage | NestJS backend, SvelteKit web |
| questions | Q&A with web search | SvelteKit web |
| skilltree | Skill tree visualization | NestJS backend, SvelteKit web |
| nutriphi | Nutrition tracking | NestJS backend, SvelteKit web |
| citycorners | City guide | NestJS backend, SvelteKit web, Astro landing |
| presi | Presentation tool | NestJS backend, SvelteKit web |
| photos | Photo management | NestJS backend, SvelteKit web |
Getting Started
Prerequisites
- Node.js 20+
- pnpm 9.15.0+
- Docker (for PostgreSQL, Redis, MinIO)
Installation
pnpm install
Development
# Start infrastructure (PostgreSQL, Redis, MinIO)
pnpm docker:up
# Start any app with auto DB setup
pnpm dev:chat:full
pnpm dev:todo:full
pnpm dev:calendar:full
pnpm dev:contacts:full
# Build & quality
pnpm run build
pnpm run type-check
pnpm run format
See CLAUDE.md for comprehensive development documentation.
Architecture
mana-monorepo/
├── apps/ # Product applications
├── services/ # Microservices (auth, search, LLM, bots)
├── packages/ # Shared packages
├── docker/ # Docker configuration
└── scripts/ # Development & deployment scripts
Tooling
- Package Manager: pnpm 9.15.0
- Build System: Turborepo
- Formatting: Prettier (tabs, single quotes, 100 char width)
- Hosting: Mac Mini (self-hosted) via Docker + Cloudflare Tunnel
- Analytics: Umami (stats.mana.how)
License
Private - All rights reserved