Quasar Contact is a privacy-focused, real-time messaging application with end-to-end encryption. Built with Angular 18, Node.js, and Socket.IO — your conversations remain completely private with client-side encryption and zero plaintext logging.
Beta — core features are stable, but the crypto implementation hasn't been independently audited yet.
- End-to-end encryption — RSA-OAEP + AES-GCM hybrid encryption via Web Crypto API
- Zero-knowledge server — private keys never leave your browser, stored in AES-GCM encrypted IndexedDB
- Client-side key generation — RSA-OAEP 2048-bit key pairs with SHA-256 fingerprinting
- Encrypted local storage — Vault service with per-user IndexedDB databases
- CSRF protection — double-submit cookie pattern with cryptographically secure tokens
- JWT security — HttpOnly cookies with configurable expiry and refresh token rotation
- Advanced rate limiting — multiple rate limiters with brute-force protection
- Bot protection — Cloudflare Turnstile + multi-layer honeypot + 98+ blocked attack paths
- Auto-blacklisting — dynamic IP blocking for suspicious behavior
- Security headers — Helmet.js, strict CORS, parameterized queries via Prisma
- Session management — secure session handling with automatic cleanup
- Key management — private key fingerprinting, corruption detection, and rotation support
- Input validation — server-side validation and sanitization for all inputs
- Password security — bcrypt hashing, minimum requirements enforced
- Real-time delivery — Socket.IO with automatic reconnection (exponential backoff)
- Edit & delete — live message editing and deletion with WebSocket sync
- Typing indicators and read receipts
- Message grouping — automatic grouping by date with headers
- Offline queue — message delivery when users reconnect, with TTL management
- Emoji picker — theme-aware, mobile-optimized
- Image attachments — in-chat image sharing with server-side compression, stored as base64
- Smart scrolling — auto-scroll with "new messages" counter and scroll-to-bottom button
- Online/offline presence — real-time user status tracking
- Message states — visual distinction for encrypted, deleted, and unreadable messages
- System message icons — Material Design icons for consistency
- Visual Viewport API — real-time keyboard detection and layout adjustment
- iOS Safari compatible — proper handling of virtual keyboard, safe areas, and notches
- 60fps scrolling — optimized event handling with
requestAnimationFrame - Orientation-aware — seamless experience across device rotations
- Battery efficient — debounced resize and typing events,
dvhunits, CSS variable-based layout - Smart keyboard management — smooth virtual keyboard transitions without layout breaks
- Progressive Web App — installable on desktop and mobile
- Dark/light theme — system preference detection with manual override and localStorage persistence
- User search — find contacts quickly
- Responsive — mobile-first, works on all screen sizes
- Settings page — avatar picker (stock avatars), private key download as PEM backup, private key import from backup file with fingerprint verification
- Framework: Astro 4.0 (Static Site Generator)
- Pages: Home, About, FAQ, Legal, Author
- SEO: Built-in sitemap generation and meta optimization
- Performance: Optimized static builds with minimal JavaScript
- Styling: Modern CSS with responsive design
- Framework: Angular 18 (Standalone Components)
- UI Library: Angular Material
- State Management: RxJS BehaviorSubjects
- Encryption: Web Crypto API
- Real-Time: Socket.IO Client
- Styling: CSS3 with custom animations and CSS variables
- Architecture: Facade pattern with specialized services for chat functionality
- Mobile Optimization: Visual Viewport API, CSS
dvhunits, dynamic layout calculations
- Runtime: Node.js 22+
- Framework: Express.js
- WebSocket: Socket.IO
- Database: PostgreSQL with Prisma ORM
- Authentication: JWT (JSON Web Tokens)
- Security: Helmet, CORS, Rate Limiting
- Password Hashing: bcrypt
- Containerization: Docker (multi-stage build)
- Deployment: Railway / cloud platforms
- Build Tools: TypeScript
- Package Manager: npm workspaces
- Code Quality: ESLint, Prettier, Stylelint, Husky pre-commit hooks
- Linting: Comprehensive linting for Angular, Node.js, and Astro with strict unused variable checking
quasar-contact-app/
├── landing/ # Astro static site (home, about, FAQ, legal, author)
│ ├── public/ # Static assets
│ │ └── assets/images/
│ ├── src/
│ │ ├── components/ # Astro components
│ │ ├── layouts/ # Page layouts
│ │ ├── pages/ # Static pages
│ │ ├── scripts/ # Client-side scripts (cookie consent, image optimization)
│ │ └── styles/ # Global styles
│ └── astro.config.mjs
├── frontend/ # Angular application
│ └── src/
│ ├── app/
│ │ ├── core/
│ │ │ ├── auth/ # guards (auth, unauth, reset-password), interceptor
│ │ │ ├── models/
│ │ │ ├── services/ # auth, crypto, vault, websocket, csrf, chat-session, ...
│ │ │ └── utils/ # api-paths, avatar, date
│ │ ├── features/
│ │ │ ├── auth/ # login, register, forgot-password, reset-password
│ │ │ ├── chat/
│ │ │ │ ├── chat-list/
│ │ │ │ └── chat-room/
│ │ │ │ └── services/ # facade, message, scroll, typing, ui-state, lifecycle, mobile-layout
│ │ │ └── settings/
│ │ └── shared/
│ │ └── components/ # header, footer, emoji-picker, image-modal, image-attachment, loading-spinner, cache-info-banner
│ ├── assets/ # images, icons, fonts
│ └── environments/
├── backend/
│ ├── src/
│ │ ├── config/ # env, CORS, rate limits, security limits
│ │ ├── middleware/ # auth, CSRF, bot-blocker, bot-trap, honeypot, security-headers, logger
│ │ ├── routes/ # auth, users, messages, rooms, keys, upload, analytics
│ │ ├── sockets/ # Socket.IO event handlers
│ │ ├── services/ # database (Prisma), email (nodemailer)
│ │ ├── utils/ # encryption, cookie, password-reset, refresh-token, sanitization, security-logger
│ │ ├── app.ts # Express app setup
│ │ └── server.ts # Server entry point
│ └── prisma/
│ ├── schema.prisma # Database schema
│ └── migrations/
├── docs/
│ ├── LINTING.md
│ ├── COOKIE_STRATEGY.md
│ └── TESTING.md
├── public/ # Astro/landing build output (served at /)
├── dist/ # Angular frontend build output (served by backend at /app)
├── .husky/ # Git hooks
├── eslint.config.js
├── .prettierrc.js
├── .stylelintrc.js
├── .lintstagedrc.js
├── Dockerfile
├── nixpacks.toml
├── railway.json
├── Procfile
└── package.json
The chat room uses 8 specialized services orchestrated by a facade:
| Service | Responsibility |
|---|---|
ChatRoomFacadeService |
Main orchestrator — wires all services together |
ChatMessageService |
Message grouping, date headers, state |
ChatScrollService |
Auto-scroll, scroll position, "new messages" badge |
ChatTypingService |
Typing indicators, textarea auto-resize |
ChatUiStateService |
Edit mode, attachment state, loading flags |
ChatEventHandlerService |
Centralized Socket.IO event subscriptions |
ChatLifecycleService |
Init and cleanup on component enter/leave |
MobileChatLayoutService |
Viewport calculations, keyboard offset, safe area |
AuthService(auth.service.ts) — complete authentication lifecycle with HttpOnly JWT cookies, smart key management on login/register, CSRF integration, Cloudflare Turnstile bot protection, honeypot validationCryptoService(crypto.service.ts) — RSA-OAEP + AES-GCM hybrid E2E encryption, 2048-bit key generation, SHA-256 fingerprinting, chunk-based Base64 conversion to prevent stack overflow, error throttlingVaultService(vault.service.ts) — AES-GCM encrypted IndexedDB with per-user databases, reactive readiness state, ArrayBuffer serialization, read-only mode supportCsrfService(csrf.service.ts) — CSRF token lifecycle, localStorage persistence with in-memory fallbackHoneypotService(honeypot.service.ts) — invisible fields, timing validation, CSS-based field hiding, behavioral pattern analysisTurnstileService(turnstile.service.ts) — Cloudflare Turnstile widget with theme support, flexible sizing, width preservation, automatic re-render
WebSocketService(websocket.service.ts) — Socket.IO connection, exponential backoff, health monitoring with ping/pong, user presence tracking, NgZone integration for mobile performanceChatSessionService(chat-session.service.ts) — chat orchestration, E2E encryption pipeline, connection monitoring with fallback sync, key status management, message persistence via vaultMessagesService(messages.service.ts) — HTTP API for message CRUD with auth validation and error propagationUserService(user.service.ts) — user lookup and key exchange via repository pattern
NotificationService(notification.service.ts) — real-time notifications with rate limiting, debounced refresh, mobile change detection, NgZone integrationThemeService(theme.service.ts) — dark/light theme, system preference detection, localStorage persistence, mobile meta tag updates, reactive BehaviorSubjectLoadingService(loading.service.ts) — global loading state, 15s timeout guard, emergency stop, auth-specific statesScrollService(scroll.service.ts) — cross-browser scroll management with mobile fallback strategies
AuthGuard(auth.guard.ts) — protects routes for unauthenticated users, redirects to loginUnauthGuard(unauth.guard.ts) — prevents authenticated users from accessing auth pagesResetPasswordGuard(reset-password.guard.ts) — validates reset token presence before rendering formAuthInterceptor(auth.interceptor.ts) — attaches CSRF tokens, handles 401/429 responses, rate limit feedback
ApiPathsUtil(api-paths.util.ts) — constructs environment-specific API and WebSocket pathsAvatarUtil(avatar.util.ts) — default avatar generation based on user input hash with consistent styling
| Route | Description |
|---|---|
auth.routes |
Register, login, logout, refresh, password reset flow |
users.routes |
Avatar update, user lookup |
messages.routes |
Send, edit, delete, mark-read, paginated history |
rooms.routes |
DM room creation and listing |
keys.routes |
RSA public key upload, retrieval, mark-missing |
upload.routes |
Image upload with server-side compression (image/* only) |
analytics.routes |
Privacy-preserving GA4 Measurement Protocol proxy |
DatabaseService(database.service.ts) — PostgreSQL connection management via Prisma ORM with connection pooling, health checks with retry logic, graceful connection/disconnection, timeout protectionEmailService(email.service.ts) — SMTP email delivery for password reset with HTML/text dual format emails, mobile-responsive templates, TLS support, connection verification
auth.middleware— JWT validation, attaches user to requestcsrf.middleware— double-submit cookie CSRF validationbot-blocker— 98+ blocked malicious paths, user-agent filtering, auto-IP-blacklistingbot-trap— honeypot path traps that log and block crawlershoneypot-captcha— server-side form timing and field validationsecurity-headers— Helmet.js with CSP, HSTS, and other headersrequest-logger— comprehensive request logging with daily rotation
encryption.utils— AES-256 encryption/decryption for reset tokenspassword-reset.utils— secure token generation, hashing, and expiry logicrefresh-token.utils— refresh token rotation and revocationcookie.utils— HttpOnly + SameSite cookie management, environment-aware settingssanitization.utils— input sanitization for all user-supplied datasecurity-logger.utils— structured security event logging
script.js— interactive UI management with beta banner, mobile menu, scroll effects, carousel functionality, touch/swipe support, and intersection observer animationscookieConsent.js— GDPR-compliant cookie consent management with analytics tracking, batched event sending, and localStorage persistenceimageOptimization.js— client-side responsive image loading and optimization
- Facade pattern —
ChatRoomFacadeServiceorchestrates complex chat functionality behind a single API - Observer pattern — RxJS BehaviorSubjects for all reactive state across services
- Repository pattern — clean data access abstraction for users and messages
- Singleton services — Angular
providedIn: 'root'for consistent service instances
- Memory management — automatic cleanup of RxJS subscriptions and event listeners
- Change detection — strategic NgZone usage to avoid unnecessary Angular cycles
- Event throttling — debounced typing events and scroll listeners
- Layout — CSS variables and
dvhunits for smooth mobile experience - Lazy evaluation — deferred calculations using
requestAnimationFrame - Connection pooling — Prisma connection pooling for database efficiency
- Message vault — local caching of decrypted messages with key status tracking
-
Key generation (on user registration)
- Generate RSA-OAEP key pair in the browser
- Store private key in browser's IndexedDB (wrapped with AES-GCM)
- Upload public key to server
-
Sending messages
- Generate a fresh AES-GCM session key
- Encrypt message body with the session key
- Encrypt the session key with recipient's RSA public key
- Send encrypted message + encrypted session key as opaque blobs
-
Receiving messages
- Decrypt the session key using own RSA private key
- Decrypt the message body using the decrypted session key
- Display plaintext — decryption happens entirely in the browser
The server stores and forwards ciphertext only. It never participates in decryption.
- HTTPS only — all production traffic must use TLS
- JWT authentication — stateless auth with token expiry and refresh rotation
- Rate limiting — brute-force protection across all sensitive endpoints
- CORS — strict origin validation and pre-flight handling
- Helmet.js — security headers including CSP and HSTS
- Input validation — server-side validation and sanitization for all inputs
- SQL injection protection — Prisma ORM with parameterized queries only
- Password requirements — minimum length enforced, hashed with bcrypt
- Node.js 22+ / npm 10+
- PostgreSQL 14+
-
Clone the repository
git clone https://github.com/art2url/quasar-contact-app.git cd quasar-contact-app -
Install dependencies
npm run install:all
-
Set up PostgreSQL
createdb quasar_chat
-
Configure backend — create
backend/.env:PORT=3000 NODE_ENV=development DATABASE_PUBLIC_URL=postgresql://user:password@localhost:5432/quasar_chat?connection_limit=10 JWT_SECRET=your-jwt-secret TOKEN_ENCRYPTION_SECRET=your-token-encryption-secret SESSION_SECRET=your-session-secret COOKIE_SECRET=your-cookie-secret CLIENT_ORIGIN=http://localhost:4200 TURNSTILE_SECRET_KEY=your-turnstile-secret # optional — enables password reset emails SMTP_HOST=smtp.gmail.com SMTP_PORT=587 SMTP_SECURE=false SMTP_USER=you@gmail.com SMTP_PASS=your-app-password SMTP_FROM=noreply@quasar.contact # optional — enables analytics proxy GA_MEASUREMENT_ID=G-XXXXXXXXXX GA_API_SECRET=your-ga-api-secret
-
Set up Cloudflare Turnstile
Go to Cloudflare Dashboard → Turnstile → create a new site. Add
localhostand your production domain. Copy the site key into your env files. -
Run database migrations
cd backend npx prisma migrate dev npx prisma generate -
Configure frontend — create
frontend/.env:NG_APP_API_URL=http://localhost:3000/api NG_APP_WS_URL=http://localhost:3000 NG_APP_TURNSTILE_SITE_KEY=your-turnstile-site-key
Start the backend dev server (serves the pre-built Angular app from dist/):
npm run devFor Angular hot-reload, run in a separate terminal:
cd frontend && npm startAccess:
- Angular app (hot-reload): http://localhost:4200
- Angular app (via backend): http://localhost:3000
- Landing (dev): run
npm run dev:landing→ http://localhost:4321 - Backend API: http://localhost:3000/api
npm run buildThis builds:
- Astro landing pages
- Angular application
- Copies all assets to
public/ - Compiles backend TypeScript
npm start # start production server# root
npm run install:all # install all workspaces
npm run dev # start backend dev server (serves pre-built frontend)
npm run dev:landing # start Astro landing dev server
npm run build # full production build
npm run start # start production server
npm run clean # wipe build artifacts and node_modules
npm run full # clean + full build + start (one-shot deploy)
npm run copy:landing # copy Astro output to public/
npm run style:fix # run all linters with --fix across workspaces
# backend
cd backend
npm run dev # ts-node-dev with hot reload
npm run build # prisma generate + tsc
npm run typecheck # tsc --noEmit
npm test # jest
npm run style:fix # ESLint + Prettier fix
# frontend
cd frontend
npm start # ng serve (Angular dev server at localhost:4200)
npm run build # ng build
npm run typecheck # ng build with type checking
npm run style:css # Stylelint check
npm run style:css:fix # Stylelint fix
# landing
cd landing
npm run dev # astro dev
npm run build # astro build
npm run build:selective # selective build optimization
npm run deploy:pages # deploy to GitHub Pages
npm run style:fix # Prettier + ESLint fix- Flat config — modern ESLint 9+ flat configuration across all three workspaces
- TypeScript support — full TypeScript linting with strict unused variable detection
- Angular rules — Angular-specific linting with template checking
- Import sorting — automatic import organization
- Husky — git hooks for code quality enforcement
- lint-staged — runs linters only on staged files
- Automatic fixes — auto-fix ESLint and Prettier issues before commit
- Type checking — TypeScript compilation verified on every commit
- Prettier — consistent code formatting across all files
- Stylelint — CSS/SCSS quality and property ordering
- Angular template linting — accessibility and template best-practice checks
Multi-stage Docker build:
- Smaller images via separate build and runtime stages
- Health checks for container monitoring
- Proper layer caching for faster rebuilds
- Non-root user for security
- Build-time environment variable injection
Container health check:
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD curl -f http://localhost:${PORT:-3000}/health || exit 1- Custom build process optimized for cloud deployment
- Secure environment variable management
- Automatic Prisma migrations on deploy
- Development, staging, and production configs via environment files
- Angular environment files injected at build time
- Server configuration via runtime environment variables
Before submitting a PR, verify:
- User registration and login
- Key generation and exchange
- Message encryption/decryption
- Real-time message delivery
- Offline message queuing
- Connection recovery
- Message editing/deletion
- User search functionality
- Database migrations (Prisma)
- Message grouping with date headers
- Typing indicators and textarea auto-resize
- Intelligent auto-scrolling
- Read receipt tracking
- New message notifications
- Enhanced message styling and visual hierarchy
- System message icons and states
- Emoji picker functionality and theme compatibility
- Image attachment — upload, display, modal view
- Real-time message editing and deletion
- Virtual keyboard show/hide — layout adjusts without breaks (iOS + Android)
- Safe area on iPhone — input not hidden behind home indicator
- Smooth 60fps scrolling on mobile
- Orientation change — no layout breakage
- Touch interaction responsiveness
- Emoji picker mobile scrolling and positioning
- Theme switching consistency on mobile
- Bot blocker — suspicious paths return 403/404
- Honeypot trap detection
- Cloudflare Turnstile — widget renders, theme switches, resets correctly
- Rate limiting — too many requests get 429
- CSRF token — state-changing requests include token header
- Security headers verification
- All npm scripts execute without errors
- TypeScript compiles (
npm run typecheck) in all three workspaces - Linting passes — no ESLint or Stylelint errors
- Docker build succeeds and health check passes (
/api/health) - Environment variable injection works at build time
-
npx prisma migrate devruns clean on a fresh database
- Avatar picker — select and save a stock avatar
- Private key download — exports as PEM file
- Private key import — restores from backup file, shows fingerprint
- All authentication endpoints
- Room management (DM creation/listing)
- Message CRUD operations
- Key management endpoints
- Analytics proxy functionality
- User avatar updates
- Landing page navigation
- SEO meta tags and sitemap
- Cookie consent and Google Analytics integration
- Connect your GitHub repository to Railway
- Set environment variables in the Railway dashboard
- Deploy using the included
nixpacks.toml— migrations run automatically on deploy
# NG_APP_* vars are baked in at build time — pass them as --build-arg
docker build -t quasar-contact-app \
--build-arg NG_APP_API_URL=https://your-domain.com/api \
--build-arg NG_APP_WS_URL=https://your-domain.com \
--build-arg NG_APP_TURNSTILE_SITE_KEY=your-turnstile-site-key \
.
docker run -p 3000:3000 \
-e NODE_ENV=production \
-e DATABASE_PUBLIC_URL=your-postgres-uri \
-e JWT_SECRET=your-jwt-secret \
-e TOKEN_ENCRYPTION_SECRET=your-token-secret \
-e SESSION_SECRET=your-session-secret \
-e COOKIE_SECRET=your-cookie-secret \
-e CLIENT_ORIGIN=https://your-domain.com \
-e TURNSTILE_SECRET_KEY=your-turnstile-secret-key \
quasar-contact-appNODE_ENV=production
DATABASE_PUBLIC_URL=postgresql://user:password@host:5432/db?connection_limit=10
JWT_SECRET=<strong-random-secret>
TOKEN_ENCRYPTION_SECRET=<strong-random-secret>
SESSION_SECRET=<strong-random-secret>
COOKIE_SECRET=<strong-random-secret>
CLIENT_ORIGIN=https://your-domain.com
TURNSTILE_SECRET_KEY=<from-cloudflare>
# NG_APP_* variables must be set at docker build time (--build-arg), not at runtime
# NG_APP_API_URL=https://your-domain.com/api
# NG_APP_WS_URL=https://your-domain.com
# NG_APP_TURNSTILE_SITE_KEY=<from-cloudflare>
# optional — SMTP for password reset emails
SMTP_HOST=smtp.provider.com
SMTP_PORT=587
SMTP_SECURE=true
SMTP_USER=...
SMTP_PASS=...
SMTP_FROM=noreply@your-domain.com
# optional — analytics proxy
GA_MEASUREMENT_ID=G-XXXXXXXXXX
GA_API_SECRET=...Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature - Commit your changes:
git commit -m 'feat: add your feature' - Push to the branch:
git push origin feature/your-feature - Open a Pull Request with a clear description of what changed and why
- Follow Angular style guide for frontend code
- Follow Astro best practices for landing pages
- Use ESLint and Prettier for code formatting
- Write meaningful commit messages (
fix: ...,feat: ...,chore: ...) - No
console.login production paths, no unused variables or imports - Add comments only when the "why" is non-obvious
- Your contributions will be licensed under GPL-3.0
- Any derivative work must also be open-source under GPL-3.0
- You must preserve copyright notices and license information
- If you distribute a modified version, you must clearly mark it as changed
This project is licensed under the GNU General Public License v3.0 — see the LICENSE file for details.
- Freedom to use — for any purpose, including commercial (with conditions)
- Freedom to study — access and study the source code
- Freedom to share — copy and distribute the software
- Freedom to improve — modify and distribute your modifications
- Copyleft — any distributed modifications must also be GPL-3.0
- Source code disclosure — must provide source code when distributing
- Copyright notices — must include original copyright and license notices
- Document changes — changes must be clearly documented
- No proprietary derivatives — cannot create closed-source commercial versions
- Network use clause — if you modify and offer as a network service, you must provide source to users
- Astro — landing pages
- Angular — frontend framework
- Socket.IO — real-time transport
- Prisma — database ORM
- Boring Avatars — avatar design inspiration (MIT)
- Web Crypto API — browser-side encryption primitives
- The open-source community
For issues and feature requests, please use the GitHub Issues page.
Note: This is a beta release. The core features are stable and ready for production use. The encryption implementation should be audited by security professionals before deploying in sensitive environments.