You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

11 KiB

Messaging Forwarding Feature

This feature allows users with unlimited access to forward Nostr events to messaging platforms (Telegram, SimpleX, Email) and Git hosting platforms (GitHub, GitLab, Gitea, Codeberg, Forgejo) when they publish events.

Security Architecture

Multi-Layer Security

  1. Encrypted Salt Storage: Each user's salt is encrypted with a separate key (MESSAGING_SALT_ENCRYPTION_KEY)
  2. HMAC Lookup Keys: User pubkeys are hashed with HMAC before being used as database keys
  3. Rate Limiting: Decryption attempts are rate-limited (10 attempts per 15 minutes)
  4. Per-User Key Derivation: Encryption keys derived from master key + pubkey + salt
  5. AES-256-GCM: Authenticated encryption with random IV per encryption

Threat Mitigation

  • Database Compromise: All data encrypted at rest with per-user keys
  • Key Leakage: Per-user key derivation means master key leak doesn't expose all users
  • Brute Force: Rate limiting prevents rapid decryption attempts
  • Lookup Attacks: HMAC hashing prevents pubkey enumeration

Environment Variables

Required for Encryption

# Master encryption key (256-bit hex, generate with: openssl rand -hex 32)
MESSAGING_PREFS_ENCRYPTION_KEY=<256-bit-hex>

# Salt encryption key (256-bit hex, generate with: openssl rand -hex 32)
MESSAGING_SALT_ENCRYPTION_KEY=<256-bit-hex>

# HMAC secret for lookup key hashing (256-bit hex, generate with: openssl rand -hex 32)
MESSAGING_LOOKUP_SECRET=<256-bit-hex>

Optional for Messaging Platforms

# Telegram Bot Configuration
TELEGRAM_BOT_TOKEN=<bot-token>
TELEGRAM_ENABLED=true

# Email SMTP Configuration
SMTP_HOST=<smtp-host>
SMTP_PORT=587
SMTP_USER=<smtp-username>
SMTP_PASSWORD=<smtp-password>
SMTP_FROM_ADDRESS=<from-email>
SMTP_FROM_NAME=GitRepublic
EMAIL_ENABLED=true

# OR use SMTP API (alternative to direct SMTP)
SMTP_API_URL=<smtp-api-url>
SMTP_API_KEY=<api-key>

# SimpleX API Configuration
SIMPLEX_API_URL=<simplex-api-url>
SIMPLEX_API_KEY=<api-key>
SIMPLEX_ENABLED=true

# Git Platforms Forwarding Configuration
GIT_PLATFORMS_ENABLED=true

Setup

1. Generate Encryption Keys

# Generate all three required keys
openssl rand -hex 32  # For MESSAGING_PREFS_ENCRYPTION_KEY
openssl rand -hex 32  # For MESSAGING_SALT_ENCRYPTION_KEY
openssl rand -hex 32  # For MESSAGING_LOOKUP_SECRET

2. Store Keys Securely

Development:

  • Store in .env file (never commit to git)

Production:

  • Use secret management service (AWS Secrets Manager, HashiCorp Vault, etc.)
  • Or environment variables in deployment platform
  • Consider using Hardware Security Modules (HSM) for maximum security

3. Configure Messaging Platforms

Telegram

  1. Create a bot with @BotFather
  2. Get bot token
  3. Users will provide their chat ID when configuring preferences

Email

  1. Configure SMTP settings (host, port, credentials)
  2. Or use an SMTP API service
  3. Users will provide their email addresses (to/cc)

SimpleX

  1. Set up SimpleX Chat API
  2. Configure API URL and key
  3. Users will provide their contact ID

Git Platforms (GitHub, GitLab, Gitea, Codeberg, Forgejo)

  1. Users create Personal Access Tokens with appropriate scopes
  2. Users provide platform, username/org, repository name, and token
  3. Events will be forwarded as issues or PRs on the selected platform
  4. Supports self-hosted instances via custom API URL

User Flow

1. User Saves Preferences (Client-Side)

// User encrypts preferences to self on Nostr (kind 30078)
const encryptedContent = await window.nostr.nip44.encrypt(
  userPubkey,
  JSON.stringify(preferences)
);

// Publish to Nostr (backup/sync)
const event = {
  kind: 30078,
  pubkey: userPubkey,
  tags: [['d', 'gitrepublic-messaging'], ['enabled', 'true']],
  content: encryptedContent
};

// Sign and publish
const signedEvent = await signEventWithNIP07(event);
await nostrClient.publishEvent(signedEvent);

// Send decrypted copy to server (over HTTPS)
await fetch('/api/user/messaging-preferences', {
  method: 'POST',
  body: JSON.stringify({
    preferences,
    proofEvent: signedEvent
  })
});

2. Server Stores Securely

  • Verifies proof event signature
  • Checks user has unlimited access
  • Generates random salt
  • Encrypts salt with MESSAGING_SALT_ENCRYPTION_KEY
  • Derives per-user encryption key
  • Encrypts preferences with AES-256-GCM
  • Stores using HMAC lookup key

3. Event Forwarding

When user publishes an event (issue, PR, highlight):

  1. Server checks user has unlimited access
  2. Retrieves encrypted preferences
  3. Decrypts (with rate limiting)
  4. Checks if forwarding enabled and event kind matches
  5. Forwards to configured platforms

API Endpoints

POST /api/user/messaging-preferences

Save messaging preferences.

Request:

{
  "preferences": {
    "telegram": "@username",
    "simplex": "contact-id",
    "email": {
      "to": ["user@example.com"],
      "cc": ["cc@example.com"]
    },
    "gitPlatforms": [
      {
        "platform": "github",
        "owner": "username",
        "repo": "repository-name",
        "token": "ghp_xxxxxxxxxxxx"
      },
      {
        "platform": "gitlab",
        "owner": "username",
        "repo": "repository-name",
        "token": "glpat-xxxxxxxxxxxx"
      },
      {
        "platform": "codeberg",
        "owner": "username",
        "repo": "repository-name",
        "token": "xxxxxxxxxxxx"
      },
      {
        "platform": "onedev",
        "owner": "project-path",
        "repo": "repository-name",
        "token": "xxxxxxxxxxxx",
        "apiUrl": "https://your-onedev-instance.com"
      },
      {
        "platform": "custom",
        "owner": "username",
        "repo": "repository-name",
        "token": "xxxxxxxxxxxx",
        "apiUrl": "https://your-git-instance.com/api/v1"
      }
    ],
    "enabled": true,
    "notifyOn": ["1621", "1618"]
  },
  "proofEvent": { /* Signed Nostr event (kind 30078) */ }
}

Response:

{
  "success": true
}

GET /api/user/messaging-preferences

Get preferences status (without decrypting).

Response:

{
  "configured": true,
  "rateLimit": {
    "remaining": 10,
    "resetAt": null
  }
}

DELETE /api/user/messaging-preferences

Delete messaging preferences.

Response:

{
  "success": true
}

Security Best Practices

  1. Key Management

    • Never commit keys to git
    • Rotate keys periodically
    • Use secret management services in production
    • Consider HSM for maximum security
  2. Monitoring

    • Monitor rate limit violations
    • Alert on decryption failures
    • Audit log all preference changes
  3. Access Control

    • Only users with unlimited access can use this feature
    • Requires valid signed Nostr event proof
    • Server verifies all inputs
  4. Data Protection

    • All data encrypted at rest
    • Per-user key derivation
    • HMAC lookup keys
    • Rate limiting on decryption

Troubleshooting

"Decryption rate limit exceeded"

User has exceeded 10 decryption attempts in 15 minutes. Wait for the window to reset.

"Messaging forwarding requires unlimited access"

User must have relay write access (unlimited level) to use this feature.

"Failed to forward event"

Check:

  • Messaging platform API credentials
  • Network connectivity
  • Platform-specific error logs

Email Setup

Option 1: Direct SMTP

Install nodemailer:

npm install nodemailer

Configure environment variables:

SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-app-password
SMTP_FROM_ADDRESS=noreply@yourdomain.com
SMTP_FROM_NAME=GitRepublic
EMAIL_ENABLED=true

Option 2: SMTP API

Use an SMTP API service (e.g., SendGrid, Mailgun, AWS SES):

SMTP_API_URL=https://api.sendgrid.com/v3/mail/send
SMTP_API_KEY=your-api-key
EMAIL_ENABLED=true

Git Platforms Setup

Supported Platforms

  • GitHub (github) - github.com
  • GitLab (gitlab) - gitlab.com (also supports self-hosted)
  • Gitea (gitea) - Self-hosted instances
  • Codeberg (codeberg) - codeberg.org
  • Forgejo (forgejo) - Self-hosted instances
  • OneDev (onedev) - Self-hosted instances (requires apiUrl)
  • Custom (custom) - Any Gitea-compatible API with custom URL

Creating Personal Access Tokens

GitHub

  1. Go to Settings → Developer settings → Personal access tokens → Tokens (classic)
  2. Click "Generate new token (classic)"
  3. Select repo scope
  4. Generate and copy token

GitLab

  1. Go to Settings → Access Tokens
  2. Create token with api scope
  3. Generate and copy token

Gitea/Codeberg/Forgejo

  1. Go to Settings → Applications → Generate New Token
  2. Select repo scope
  3. Generate and copy token

OneDev

  1. Go to User Settings → Access Tokens
  2. Create a new access token
  3. Select appropriate scopes (typically write:issue and write:pull-request)
  4. Generate and copy token
  5. Note: OneDev is self-hosted, so you must provide the apiUrl (e.g., https://your-onedev-instance.com)

User Configuration

Users provide:

  • Platform: One of github, gitlab, gitea, codeberg, forgejo, onedev, or custom
  • Owner: Username or organization name (project path for OneDev)
  • Repo: Repository name (project name for OneDev)
  • Token: Personal access token (stored encrypted)
  • API URL (required for OneDev, optional for custom/self-hosted): Base URL of the instance (e.g., https://your-onedev-instance.com)

Event Mapping

  • Nostr Issues (kind 1621) → Platform Issues
  • Nostr PRs (kind 1618) → Platform Pull Requests/Merge Requests (if branch info available) or Issues with PR label
  • Other events → Platform Issues with event kind label

Platform-Specific Notes

  • GitLab: Uses description field instead of body, and source_branch/target_branch for PRs
  • OneDev: Uses description field and source_branch/target_branch for PRs. Requires apiUrl (self-hosted). API endpoints: /api/projects/{owner}/{repo}/issues and /api/projects/{owner}/{repo}/pull-requests
  • GitHub: Uses body field and head/base for PRs
  • Gitea/Codeberg/Forgejo: Compatible with GitHub API format
  • Custom: Must provide apiUrl pointing to Gitea-compatible API

Security Note

All tokens are stored encrypted in the database. Users should:

  • Use tokens with minimal required scopes
  • Rotate tokens periodically
  • Revoke tokens if compromised

Future Enhancements

  • Support for more messaging platforms
  • User-configurable message templates
  • Webhook support
  • Encrypted preferences sync across devices
  • Per-repository forwarding rules
  • HTML email templates