No description
  • JavaScript 46.8%
  • Go 27.2%
  • CSS 13%
  • HTML 12.6%
  • Dockerfile 0.4%
Find a file
2026-04-08 13:04:18 +08:00
static Fix critical security issues in DayLine 2026-04-08 04:39:13 +00:00
.env.example Maximize .env.example to minimize docker-compose.yml editing 2026-04-07 22:35:01 +00:00
.gitignore Maximize .env.example to minimize docker-compose.yml editing 2026-04-07 22:35:01 +00:00
docker-compose.yml Fix critical security issues in DayLine 2026-04-08 04:39:13 +00:00
Dockerfile First commit, mate! 2026-04-08 06:08:46 +08:00
go.mod First commit, mate! 2026-04-08 06:08:46 +08:00
go.sum Fix critical security issues in DayLine 2026-04-08 04:39:13 +00:00
init.sql First commit, mate! 2026-04-08 06:08:46 +08:00
LICENSE Create LICENSE 2026-04-08 06:14:00 +08:00
main.go Fix critical security issues in DayLine 2026-04-08 04:39:13 +00:00
README.md Merge pull request #3 from kalvin0x8d0/claude/fix-dayline-issues-EapOm 2026-04-08 12:47:29 +08:00

DayLine 📱

Go 1.22 License: CC0

Zeroknowledge medicine & mood tracker Your health data stays encrypted in your browser. The server never sees plaintext.

DayLine is a privacy-first health tracking application that puts you in complete control of your data through end-to-end encryption. Track your medicine intake, mood patterns, and health insights without compromising privacy.

Features

  • 🔐 Endtoend encryption All entries are encrypted with AESGCM before leaving your browser. Only you hold the master key. The server is completely blind to your data.
  • 💊 Medicine logging Track doses, timing, side effects, notes, and bookmark frequently used medicines for quick logging.
  • 😊 Mood tracking Quick 5point mood logging (😡😢😐😴😊) with visual indicators and time-series data.
  • 📊 Visual insights Medicine intake frequency charts and average mood charts with flexible time ranges (24h, 7d, 28d, 12m).
  • 📅 Year in colours GitHub-style heatmap view of your mood throughout the year to see patterns at a glance.
  • 🔑 Recovery passphrase Optional secondary encryption key to restore access if you forget your password. You control the recovery data.
  • 🔐 Password change Securely change your password while re-encrypting your master key without losing any data.
  • 👥 Admin controls Enable/disable public signups and manage registered users.
  • 🐳 Dockerready Easy deployment with Docker Compose for home servers or cloud platforms.
  • 📱 Responsive design Works seamlessly on desktop, tablet, and mobile devices.

🏗️ Tech Stack

Component Technology
Frontend HTML5, CSS3 (Material Design 3), Vanilla JS
Backend Go 1.22
Database MariaDB 11
Encryption Web Crypto API (AESGCM, PBKDF2)
Deployment Docker + Docker Compose

🚀 Getting Started

1. Clone the repository

git clone https://github.com/your-username/dayline.git
cd dayline

2. Configure environment (optional)

Copy the example environment file and customize as needed:

cp .env.example .env

Then edit .env to customize settings (all variables are optional with sensible defaults):

DAYLINE_PORT=8080              # Port to access the app
DB_HOST=db                     # Database hostname
DB_USER=dayline                # Database username
DB_PASS=your_strong_password   # Database password (change in production!)
DB_ROOT_PASS=root_password     # MariaDB root password (change in production!)
FORCE_SECURE=false             # Set to true when using HTTPS

See .env.example for all available configuration options and detailed explanations.

3. Run with Docker Compose

docker compose up -d

The app will be available at http://localhost:8080 (or the port you configured).

4. First run

  • The first user to register automatically becomes the admin.
  • After that, public signups are disabled by default. The admin can enable them in Settings → Admin.

Manual Setup (Without Docker)

Requirements

  • Go 1.22+
  • MariaDB 10.5+ (or MySQL 8.0+)

Steps

  1. Create a database and user:

    CREATE DATABASE dayline CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
    CREATE USER 'dayline'@'%' IDENTIFIED BY 'your_strong_password';
    GRANT ALL PRIVILEGES ON dayline.* TO 'dayline'@'%';
    FLUSH PRIVILEGES;
    
  2. Import the schema:

    mysql -u root -p dayline < init.sql
    
  3. Set environment variables:

    export DB_USER=dayline
    export DB_PASS=your_strong_password
    export DB_HOST=localhost
    export DB_PORT=3306
    export DB_NAME=dayline
    
  4. Build and run:

    go mod tidy
    go build -o dayline .
    ./dayline
    

    The server will listen on :8080 by default.

🔐 How Encryption Works

DayLine implements a zero-knowledge architecture where the server never has access to your plaintext data:

┌─────────────────────────────────────────────────────────────┐
│  Your Browser (Client-Side)                                 │
│  • Generate random 256-bit master key                        │
│  • Encrypt master key with password (PBKDF2)                │
│  • Encrypt all entries with master key (AES-GCM)           │
│  • Decrypt locally before displaying                         │
└─────────────────────────────────────────────────────────────┘
                         │
                    [HTTPS only]
                         ↓
┌─────────────────────────────────────────────────────────────┐
│  Server (Blind Storage)                                      │
│  • Store encrypted master key (wrapped with password)        │
│  • Store encrypted entries (ciphertext + IV)                │
│  • NO plaintext data EVER visible                           │
│  • Cannot decrypt even if compromised                       │
└─────────────────────────────────────────────────────────────┘

Detailed Flow

  1. Registration:

    • Generate random 256-bit master key in browser
    • Derive encryption key from password using PBKDF2 (600k iterations, SHA-256)
    • Encrypt master key with password-derived key
    • Send encrypted master key to server
    • Server stores encrypted master key, never sees plaintext
  2. Login:

    • Server returns encrypted master key
    • Browser decrypts with password-derived key
    • Master key loaded into memory (never persisted)
    • All user data can now be decrypted locally
  3. Adding Entry:

    • Entry (medicine/mood) encrypted locally with master key
    • Ciphertext + IV sent to server
    • Server stores as-is, cannot decrypt
  4. Recovery Passphrase:

    • Raw master key encrypted with recovery passphrase
    • Stored on server separately from password-derived encryption
    • If you forget password: use recovery passphrase to recover raw master key
    • Set new password, re-encrypt master key with new password
    • All data remains accessible (no data loss)

Security Properties

  • Forward secrecy: Even if server is compromised, encrypted data cannot be decrypted without your password
  • No password vulnerability: Password only used locally; never transmitted
  • PBKDF2 strengthening: 600,000 iterations slow down brute-force attacks (≈100ms per attempt)
  • Authenticated encryption: AES-GCM includes authentication (detects tampering)
  • Unique IVs: Every encryption uses a random IV, preventing pattern analysis

📋 API Overview

Most endpoints require a valid session cookie. All request/response bodies are JSON.

Health Check

Endpoint Method Auth Description
/health GET No Health check endpoint (for orchestration)

Authentication

Endpoint Method Auth Description
/api/register POST No Create account with encrypted master key
/api/login POST No Authenticate, receive encrypted master key
/api/logout POST Yes Destroy session
/api/me GET Yes Get current user info + recovery hint

Password Management

Endpoint Method Auth Description
/api/users/me/password POST Yes Change password (verify old, update hash)
/api/users/me/masterkey PUT Yes Update encrypted master key (password recovery)

Health Data

Endpoint Method Auth Description
/api/entries GET Yes List encrypted entries (filter by type, date range)
/api/entries POST Yes Add new encrypted entry
/api/entries/{id} DELETE Yes Delete an entry
/api/medicines GET Yes List saved medicine templates
/api/medicines POST Yes Save a medicine template
/api/medicines/{id} DELETE Yes Remove a saved medicine

Recovery

Endpoint Method Auth Description
/api/recovery/setup POST Yes Store encrypted recovery blob + hint
/api/recovery/recover POST No Retrieve recovery blob for username

Admin (Admin-only)

Endpoint Method Auth Description
/api/admin/settings GET Yes Get public signup setting
/api/admin/settings PUT Yes Update signup setting
/api/admin/users GET Yes List all registered users

🔐 Security Considerations

HTTPS Requirement ⚠️

Always use HTTPS in production. DayLine sets the Secure flag on session cookies only over HTTPS. Without HTTPS:

  • Session cookies can be intercepted
  • Passwords transmitted in plaintext
  • Encryption keys vulnerable to man-in-the-middle attacks

To enable HTTPS:

  • Use a reverse proxy (Nginx, Caddy, Traefik)
  • Obtain SSL/TLS certificates (Let's Encrypt is free)
  • Configure proxy to terminate TLS and forward traffic to DayLine

Example with Caddy:

example.com {
  reverse_proxy localhost:8080
}

Cookies Behind Reverse Proxy

If DayLine is behind an HTTPS-terminating reverse proxy (e.g., Nginx, Caddy), the application may not detect TLS and cookies won't have the Secure flag. Set FORCE_SECURE=true in environment variables to force the Secure flag:

export FORCE_SECURE=true
docker compose up -d  # or ./dayline if running manually

Session Invalidation

Password Change: When you change your password, all existing sessions for your account are invalidated and rotated to a new one. This ensures old sessions (even on other devices) are invalidated.

Account Recovery: When recovering your account using the recovery passphrase, all existing sessions are deleted. You must log in again with your new password.

Manual Session Cleanup (if needed): To manually invalidate all sessions for a user, run:

DELETE FROM sessions WHERE user_id = <user_id>;

Or to clear all sessions for all users:

DELETE FROM sessions;

Rate Limiting

Sensitive endpoints are rate-limited to 10 attempts per 5 minutes per IP:

  • /api/login
  • /api/register
  • /api/recovery/recover

This prevents brute-force attacks on passwords and recovery passphrases.

Password Requirements

  • Minimum 8 characters (enforced by frontend)
  • Recommended: 12+ characters with mixed case, numbers, symbols
  • Avoid common passwords

Recovery Passphrase

  • Use a unique, strong passphrase (different from your login password)
  • Write it down and store securely (not digitally)
  • Store the hint somewhere you'll remember (but not the passphrase itself)
  • Recovery only works if you set up the recovery feature before forgetting password

Session Security

  • Sessions expire after 30 days
  • Sessions stored server-side with random tokens
  • HttpOnly flag prevents JavaScript access
  • SameSite=Strict prevents CSRF attacks
  • Secure flag prevents transmission over HTTP

What the Server Cannot Do

Even if the server is fully compromised by an attacker:

  • Cannot read your medicine or mood entries
  • Cannot recover your master key
  • Cannot decrypt recovery passphrase data
  • Cannot change your password without your permission
  • Cannot see plaintext health data
  • Cannot use your data to train AI models

🔄 Password Recovery Flow

If you forget your password:

  1. Click "Recover account" on login screen
  2. Enter your username
  3. See the recovery hint you set (if any)
  4. Enter your recovery passphrase
  5. Set a new password
  6. DayLine will:
    • Decrypt your master key using recovery passphrase
    • Re-encrypt master key with new password
    • Update encrypted master key on server
    • Log you in automatically with new password
  7. All your data remains encrypted and accessible!

Important: Recovery only works if you set up recovery passphrase before forgetting your password.

🔑 Changing Your Password

You can change your password anytime without recovery:

  1. Go to Settings → Change password
  2. Enter your current password
  3. Enter your new password (min 8 chars)
  4. DayLine will:
    • Verify your current password
    • Re-encrypt master key with new password
    • Update server
  5. All data remains intact and accessible

🔨 Environment Variables

All configuration is managed through environment variables. For Docker, copy .env.example to .env and customize as needed.

Variable Default Description
DAYLINE_PORT 8080 Port where the app is accessible
DB_HOST db Database hostname (or localhost)
DB_PORT 3306 Database port
DB_NAME dayline Database name
DB_USER dayline Database username
DB_PASS changeme Database password (change in production!)
DB_ROOT_PASS rootchangeme MariaDB root password (change in production!)
FORCE_SECURE false Force Secure flag on cookies. Set to true when behind HTTPS reverse proxy
MARIADB_CHARSET utf8mb4 Database character set
MARIADB_COLLATION utf8mb4_unicode_ci Database collation

Note: All variables have sensible defaults and are optional. Only customize if you need non-default values.

Important: For HTTPS behind reverse proxy (Nginx, Caddy, etc.), set FORCE_SECURE=true to enable the Secure flag on cookies.

For Docker setup, copy .env.example to .env and modify as needed. For manual setup, set these as environment variables before running the application.

🐛 Troubleshooting

"user not found" on login

  • Check username spelling
  • Make sure you registered first
  • Admin may have disabled public signups (reset via database)

"recovery not available"

  • Recovery feature not set up for this account
  • Set up recovery from Settings before forgetting password

"too many requests"

  • Rate limiting active (10 requests per 5 minutes)
  • Wait a few minutes and try again

Cookies not working behind HTTPS proxy

  • Symptoms: Session doesn't persist, logged out after page refresh
  • Solution: Set FORCE_SECURE=true in environment variables
  • This forces the Secure flag on cookies when behind HTTPS reverse proxy
  • Example: FORCE_SECURE=true docker compose up -d

Database connection fails

  • Check DB_HOST, DB_PORT, DB_USER, DB_PASS
  • Ensure MariaDB/MySQL is running
  • Check firewall rules

HTTPS not working

  • Verify proxy is configured correctly
  • Check SSL/TLS certificate validity
  • Ensure proxy forwards to correct DayLine port

📊 Data Privacy

  • No tracking: No analytics, no telemetry, no cookies for tracking
  • No third-party services: All data stays on your server
  • Transparent: Open source code, audit-friendly
  • Your control: You own your data and can export/delete anytime
  • No backups on us: We never backup your encrypted data

🚧 Future Improvements

Potential enhancements (not yet implemented):

  • Data export: Export encrypted data for archival or migration
  • Sync multiple devices: Encrypted device-to-device sync
  • Medication interactions: Check drug interaction warnings
  • Time-based reminders: Push notifications for medicine timing
  • Symptom tracking: Connect mood to symptoms for pattern analysis
  • Doctor sharing: Securely share summaries with healthcare providers
  • 2FA: TOTP-based second factor authentication
  • Offline mode: Use service worker for offline data access
  • Advanced charts: ML-based mood prediction, trend analysis

📝 Contributing

Pull requests welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit changes with clear messages
  4. Push to branch (git push origin feature/amazing-feature)
  5. Open a pull request

For major changes, please open an issue first to discuss.

📄 License

Creative Commons CC0 1.0: No legal advice; no warranties; use at own risk.

Owners can waive rights to freely share, remix, and reuse works worldwide without claiming infringement.

Applying CC0 means surrendering all copyright and related rights permanently, globally, for any purpose.

If invalid, a fallback licence grants the public a free, unlimited right to use the work.

No trademark, patent rights waived; work is provided as-is; no liability or rights clearance.


Questions or issues? Open an issue on GitHub or review the code it's open source for transparency!

Privacy first, always. 🔒