Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@deel77
Copy link
Owner

@deel77 deel77 commented Jun 3, 2025

Summary

  • remove duplicated crypto code from KeyGeneraterView
  • reuse helper functions for keypair and preshared key generation

Testing

  • make test (fails: pattern frontend-dist/assets/ not found)*

https://chatgpt.com/codex/tasks/task_e_683f730b4af0832b821e0b5c36adf652

Summary by CodeRabbit

  • New Features

    • Added support for client-side generation of WireGuard peer key pairs, allowing keys to be created directly in the browser.
    • Introduced an option to prevent private keys from being stored on the server, enhancing user control over key security.
    • Users now receive clear notifications about where and how their keys are generated and stored.
  • Bug Fixes

    • Improved handling and messaging in the peer editing interface regarding key generation and storage settings.
  • Documentation

    • Updated configuration documentation to describe new key generation and storage options.
  • Localization

    • Added informational messages about key management to multiple languages, improving clarity for international users.

@deel77 deel77 marked this pull request as ready for review June 3, 2025 23:25
@coderabbitai
Copy link

coderabbitai bot commented Jun 3, 2025

Walkthrough

This update introduces support for client-side WireGuard peer key generation and configurable private key storage. It adds configuration options, updates API schemas and backend logic, implements frontend cryptographic helpers, and enhances user interface messaging and localization. The changes ensure private keys can be generated and/or stored according to new settings, with clear user guidance.

Changes

Files/Groups Change Summary
docs/documentation/configuration/overview.md Documented new client_side_peer_keygen and store_private_keys config options in the WireGuard Portal overview.
internal/config/config.go Added ClientSidePeerKeygen and StorePrivateKeys to core config, with defaults and logging.
internal/app/api/core/assets/doc/v0_swagger.json
internal/app/api/core/assets/doc/v0_swagger.yaml
Updated API schema: added PrivateKeys to PeerMailRequest, and ClientSidePeerKeygen/StorePrivateKeys to Settings.
internal/app/api/v0/model/models.go Added ClientSidePeerKeygen and StorePrivateKeys fields to Settings struct.
internal/app/api/v0/model/models_peer.go Added PrivateKeys map field to PeerMailRequest struct.
internal/app/api/v0/handlers/endpoint_config.go Included new config flags in settings API response for all users.
internal/app/api/v0/handlers/endpoint_peers.go
internal/app/api/v0/backend/peer_service.go
Updated SendPeerEmail method signatures to accept privKeys parameter; updated handler to pass it.
internal/app/mail/manager.go Updated SendPeerEmail to accept/use privKeys, added generatePeerQr for QR code creation without comments.
internal/app/wireguard/wireguard.go Disabled default peer creation if ClientSidePeerKeygen is enabled.
internal/app/wireguard/wireguard_peers.go Conditional key generation/storage: skip server-side keygen if client-side enabled, clear private keys if disabled.
internal/domain/crypto.go
internal/domain/crypto_test.go
Added ValidatePrivateKey function and tests for validating WireGuard private keys.
frontend/src/helpers/crypto.js New module: exposes generateKeypair, generatePresharedKey, arrayBufferToBase64, and b64urlToB64.
frontend/src/views/KeyGeneraterView.vue Refactored to use new crypto helpers instead of local cryptographic functions.
frontend/src/components/PeerEditModal.vue Added client-side key generation, crypto info messages, and improved notifications; code formatting improvements.
frontend/src/lang/translations/en.json
.../de.json
.../fr.json
.../ko.json
.../pt.json
.../ru.json
.../uk.json
.../vi.json
.../zh.json
Added new translation strings for crypto/keygen info in peer edit modal (all supported languages).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Browser (Frontend)
    participant API Server
    participant Database

    User->>Browser (Frontend): Open Peer Edit Modal
    Browser (Frontend)->>API Server: Fetch settings (ClientSidePeerKeygen, StorePrivateKeys)
    API Server-->>Browser (Frontend): Return settings

    alt Client-side keygen enabled
        Browser (Frontend)->>Browser (Frontend): Generate keypair & preshared key
        Browser (Frontend)->>API Server: Submit peer data (public key only)
        API Server->>Database: Store peer (no private key)
    else Server-side keygen
        Browser (Frontend)->>API Server: Request peer creation (no keys)
        API Server->>API Server: Generate keypair & preshared key
        API Server->>Database: Store peer (with/without private key per config)
    end

    Note over Browser (Frontend): Show info message about key generation/storage
Loading

Poem

A rabbit hops with keys anew,
Now client or server—it's up to you!
Private secrets kept or tossed,
Configured safely, never lost.
With helpers, docs, and words so clear,
The portal's safer, have no fear!
🗝️🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 01e2042 and 7cbdf7c.

📒 Files selected for processing (3)
  • internal/app/mail/manager.go (7 hunks)
  • internal/domain/crypto.go (2 hunks)
  • internal/domain/crypto_test.go (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
internal/domain/crypto_test.go (1)
internal/domain/crypto.go (1)
  • ValidatePrivateKey (72-80)
🪛 golangci-lint (1.64.8)
internal/app/mail/manager.go

222-222: expected '(', found generatePeerQr

(typecheck)


249-249: expected '}', found 'EOF'

(typecheck)

🔇 Additional comments (4)
internal/domain/crypto.go (1)

71-80: LGTM! Well-implemented private key validation.

The ValidatePrivateKey function correctly validates WireGuard private keys by:

  • Checking for empty strings
  • Trimming whitespace before parsing
  • Using the official wgtypes.ParseKey for validation
  • Providing descriptive error messages with proper error wrapping

This addresses the security concern raised in previous reviews about validating private keys before assignment.

internal/domain/crypto_test.go (1)

58-66: LGTM! Comprehensive test coverage for private key validation.

The test functions provide good coverage for the ValidatePrivateKey function:

  • Tests valid key scenario using a generated WireGuard key
  • Tests invalid key scenario with malformed input
  • Uses appropriate assertions for error handling

These tests ensure the validation logic works correctly for both positive and negative cases.

internal/app/mail/manager.go (2)

19-26: LGTM! Addresses previous review feedback.

The nopCloser type definition correctly implements io.WriteCloser for the QR code generation functionality, addressing the missing type issue flagged in previous reviews.


108-112: LGTM! Proper private key validation implemented.

The function signature now accepts privKeys parameter and validates each private key using the new domain.ValidatePrivateKey function before assignment. This addresses the security concern from previous reviews about validating private keys.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (4)
frontend/src/helpers/crypto.js (1)

29-36: Consider using modern APIs for better performance.

While the current implementation is correct, you could improve performance by using btoa(String.fromCharCode(...new Uint8Array(buffer))) directly instead of the loop.

-export function arrayBufferToBase64(buffer) {
-  const bytes = new Uint8Array(buffer);
-  let binary = "";
-  for (let i = 0; i < bytes.byteLength; ++i) {
-    binary += String.fromCharCode(bytes[i]);
-  }
-  return btoa(binary);
-}
+export function arrayBufferToBase64(buffer) {
+  const bytes = new Uint8Array(buffer);
+  return btoa(String.fromCharCode(...bytes));
+}
internal/app/api/core/assets/doc/v0_swagger.json (1)

2252-2253: Fix JSON formatting inconsistency.

The formatting is inconsistent with the rest of the JSON structure. Consider aligning with the standard formatting used elsewhere in the file.

-                ,"ClientSidePeerKeygen": {"type": "boolean"}
-                ,"StorePrivateKeys": {"type": "boolean"}
+                "ClientSidePeerKeygen": {
+                    "type": "boolean"
+                },
+                "StorePrivateKeys": {
+                    "type": "boolean"
+                }
frontend/src/components/PeerEditModal.vue (2)

109-115: Consider making the notification dismissible or showing it only once per session.

While the informational notification is helpful, showing it every time the modal opens might become repetitive for frequent users.

Consider implementing a session-based flag to show the notification only once:

+const hasShownCryptoMessage = ref(false);

 watch(
   () => props.visible,
   async (newValue, oldValue) => {
     if (oldValue === false && newValue === true) {
       // if modal is shown
-      notify({
-        title: "Info",
-        text: cryptoMessage.value,
-        type: "info",
-      });
+      if (!hasShownCryptoMessage.value) {
+        notify({
+          title: "Info", 
+          text: cryptoMessage.value,
+          type: "info",
+          duration: 10000, // Show for 10 seconds
+        });
+        hasShownCryptoMessage.value = true;
+      }

217-234: Consider debouncing the watcher to avoid excessive updates.

The watcher updates all overridable flags whenever IgnoreGlobalSettings changes. While the logic is correct, it might trigger multiple reactive updates.

Consider batching the updates:

 watch(
   () => formData.value.IgnoreGlobalSettings,
   async (newValue, oldValue) => {
-    formData.value.Endpoint.Overridable = !newValue;
-    formData.value.EndpointPublicKey.Overridable = !newValue;
-    formData.value.AllowedIPs.Overridable = !newValue;
-    formData.value.PersistentKeepalive.Overridable = !newValue;
-    formData.value.Dns.Overridable = !newValue;
-    formData.value.DnsSearch.Overridable = !newValue;
-    formData.value.Mtu.Overridable = !newValue;
-    formData.value.FirewallMark.Overridable = !newValue;
-    formData.value.RoutingTable.Overridable = !newValue;
-    formData.value.PreUp.Overridable = !newValue;
-    formData.value.PostUp.Overridable = !newValue;
-    formData.value.PreDown.Overridable = !newValue;
-    formData.value.PostDown.Overridable = !newValue;
+    const overridableFields = [
+      'Endpoint', 'EndpointPublicKey', 'AllowedIPs', 'PersistentKeepalive',
+      'Dns', 'DnsSearch', 'Mtu', 'FirewallMark', 'RoutingTable',
+      'PreUp', 'PostUp', 'PreDown', 'PostDown'
+    ];
+    
+    overridableFields.forEach(field => {
+      if (formData.value[field]) {
+        formData.value[field].Overridable = !newValue;
+      }
+    });
   },
 );
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7fd2bba and e24d77e.

📒 Files selected for processing (24)
  • docs/documentation/configuration/overview.md (2 hunks)
  • frontend/src/components/PeerEditModal.vue (1 hunks)
  • frontend/src/helpers/crypto.js (1 hunks)
  • frontend/src/lang/translations/de.json (1 hunks)
  • frontend/src/lang/translations/en.json (1 hunks)
  • frontend/src/lang/translations/fr.json (1 hunks)
  • frontend/src/lang/translations/ko.json (1 hunks)
  • frontend/src/lang/translations/pt.json (1 hunks)
  • frontend/src/lang/translations/ru.json (1 hunks)
  • frontend/src/lang/translations/uk.json (1 hunks)
  • frontend/src/lang/translations/vi.json (1 hunks)
  • frontend/src/lang/translations/zh.json (1 hunks)
  • frontend/src/views/KeyGeneraterView.vue (1 hunks)
  • internal/app/api/core/assets/doc/v0_swagger.json (2 hunks)
  • internal/app/api/core/assets/doc/v0_swagger.yaml (2 hunks)
  • internal/app/api/v0/backend/peer_service.go (2 hunks)
  • internal/app/api/v0/handlers/endpoint_config.go (2 hunks)
  • internal/app/api/v0/handlers/endpoint_peers.go (2 hunks)
  • internal/app/api/v0/model/models.go (1 hunks)
  • internal/app/api/v0/model/models_peer.go (1 hunks)
  • internal/app/mail/manager.go (5 hunks)
  • internal/app/wireguard/wireguard.go (2 hunks)
  • internal/app/wireguard/wireguard_peers.go (6 hunks)
  • internal/config/config.go (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
internal/app/api/v0/handlers/endpoint_config.go (1)
internal/config/auth.go (1)
  • Auth (12-24)
internal/app/api/v0/backend/peer_service.go (2)
internal/domain/peer.go (1)
  • PeerIdentifier (15-15)
internal/app/api/v0/handlers/endpoint_peers.go (1)
  • PeerService (17-44)
internal/app/wireguard/wireguard_peers.go (2)
internal/domain/crypto.go (2)
  • KeyPair (9-12)
  • NewFreshKeypair (37-47)
internal/domain/interface.go (1)
  • Interface (27-75)
🔇 Additional comments (40)
frontend/src/helpers/crypto.js (3)

1-7: Base64url to base64 conversion looks correct.

The implementation properly handles the character substitutions and padding. This is a standard and secure conversion method.


9-21: X25519 key generation implementation is secure and correct.

The function properly uses the Web Crypto API with appropriate parameters for WireGuard key generation. The JWK export and base64url to base64 conversion are handled correctly.


23-27: Secure random key generation for preshared keys.

Using window.crypto.getRandomValues() is the correct approach for cryptographically secure random number generation. The 32-byte length is appropriate for WireGuard preshared keys.

internal/app/api/v0/model/models.go (1)

15-16: Configuration fields for client-side key generation added correctly.

The new boolean fields ClientSidePeerKeygen and StorePrivateKeys are properly defined with appropriate JSON tags and align with the feature requirements.

internal/app/api/v0/model/models_peer.go (1)

185-189: Private keys field added for client-side key generation support.

The PrivateKeys map[string]string field appropriately supports the new client-side key generation feature. Ensure that these private keys are handled securely throughout the request lifecycle and not logged or cached inappropriately.

internal/app/wireguard/wireguard.go (2)

120-120: Correct logic to disable auto-creation when client-side key generation is enabled.

The additional ClientSidePeerKeygen check appropriately prevents automatic peer creation when users will be generating keys client-side instead.


141-141: Consistent logic applied to login event handler.

The same ClientSidePeerKeygen check is correctly applied to the user login event, maintaining consistency with the user creation event handler.

internal/app/api/v0/handlers/endpoint_config.go (2)

101-105: Expose new client-side keygen and storage flags for anonymous users
The ClientSidePeerKeygen and StorePrivateKeys fields are correctly added to the minimal settings response for unauthenticated sessions.


114-116: Include new configuration flags in authenticated settings response
The same new flags are properly exposed alongside existing fields in the full settings payload for logged-in users.

internal/config/config.go (3)

29-30: Add new Core config flags
The ClientSidePeerKeygen and StorePrivateKeys booleans are correctly declared with appropriate YAML tags.


83-84: Log new config flags at startup
The new flags are being output in the debug log alongside other Core feature flags, matching the existing logging style.


118-119: Set default values for new flags
Defaults (false for client-side keygen, true for storing keys) are initialized in defaultConfig to maintain backward compatibility.

frontend/src/lang/translations/en.json (1)

483-486: Add informational strings for key generation and storage
The new info- entries provide clear guidance on client vs. server keygen and private key handling. JSON syntax and comma placement are correct.

frontend/src/lang/translations/vi.json (1)

392-395: Insert Vietnamese messages for keygen and private key safety
The added entries align with English originals and maintain valid JSON structure.

frontend/src/lang/translations/ko.json (1)

431-434: Include Korean translations for new peer-edit info keys
The four new keys are localized correctly and integrate seamlessly into the existing JSON.

frontend/src/lang/translations/pt.json (1)

451-454: PT translations for peer-edit info added correctly.

The new entries use consistent key names (info-client-keygen, info-server-keygen, info-not-saved, info-safety), follow the same punctuation conventions as other sentences in this file, and are properly formatted as valid JSON.

frontend/src/lang/translations/uk.json (1)

415-418: UK translations for peer-edit info added correctly.

The keys match those in other locales, the Ukrainian strings are full sentences with proper punctuation, and JSON syntax is valid.

frontend/src/lang/translations/ru.json (1)

392-395: RU translations for peer-edit info added correctly.

The entries align with the shared key schema, maintain consistent sentence structure and punctuation, and the JSON remains well-formed.

frontend/src/lang/translations/fr.json (1)

415-418: FR translations for peer-edit info added correctly.

The new French sentences correspond precisely to the feature context, use the correct keys, and adhere to existing formatting.

frontend/src/lang/translations/de.json (1)

482-485: DE translations for peer-edit info added correctly.

The German strings correctly reflect the informational messages, reuse the established key names, and keep the file’s JSON structure intact.

docs/documentation/configuration/overview.md (1)

27-28: LGTM! Well-documented configuration options.

The new configuration options are clearly documented with appropriate defaults and comprehensive descriptions. The conservative defaults (client-side generation disabled, private key storage enabled) provide a good balance between security and usability.

Also applies to: 166-173

internal/app/api/core/assets/doc/v0_swagger.yaml (2)

333-336: LGTM! Appropriate API schema extension.

The PrivateKeys field addition to PeerMailRequest correctly supports the new client-side key generation functionality. The type definition as additionalProperties with string values is appropriate for a key-value mapping.


395-398: LGTM! Settings model properly extended.

The new boolean fields ClientSidePeerKeygen and StorePrivateKeys correctly expose the configuration options to the frontend, enabling the UI to adapt based on server settings.

frontend/src/lang/translations/zh.json (1)

391-394:

✅ Verification successful

LGTM! Important security-focused user guidance.

The new translation entries provide clear information about key generation methods and emphasize the importance of private key security. The translations appropriately inform users about:

  • Client-side vs server-side key generation
  • Private key storage policies
  • Security best practices

Verify that similar translation updates are made to other language files for consistency:


🏁 Script executed:

#!/bin/bash
# Description: Check if similar peer-edit translation keys exist in other language files

# Find all translation files and check for the new keys
fd "\.json$" frontend/src/lang/translations/ --exec grep -l "info-client-keygen\|info-server-keygen\|info-not-saved\|info-safety" {}

Length of output: 487


Translation consistency confirmed across all language files

All four new security-focused translation keys (info-client-keygen, info-server-keygen, info-not-saved, info-safety) are present in every supported locale:

  • frontend/src/lang/translations/en.json
  • frontend/src/lang/translations/fr.json
  • frontend/src/lang/translations/de.json
  • frontend/src/lang/translations/pt.json
  • frontend/src/lang/translations/ru.json
  • frontend/src/lang/translations/vi.json
  • frontend/src/lang/translations/uk.json
  • frontend/src/lang/translations/ko.json
  • frontend/src/lang/translations/zh.json

No further action required.

internal/app/api/v0/handlers/endpoint_peers.go (2)

467-467: LGTM! Correctly updated method call.

The call to SendPeerEmail is properly updated to pass req.PrivateKeys as the new privKeys parameter, maintaining the correct argument order and types.


41-41:

✅ Verification successful

Interface signature change requires verification.

The addition of the privKeys map[string]string parameter to the SendPeerEmail interface method is correctly implemented and aligns with the new client-side key generation functionality.

Verify that all implementations of the PeerService interface have been updated to match this new signature:


🏁 Script executed:

#!/bin/bash
# Description: Find all implementations of SendPeerEmail method to ensure they match the new signature

# Search for SendPeerEmail method implementations
ast-grep --pattern $'func ($$$) SendPeerEmail($_) error {
  $$$
}'

# Also search for interface implementations that might contain SendPeerEmail
rg -A 10 "SendPeerEmail.*context\.Context.*bool.*map\[string\]string"

Length of output: 3265


All SendPeerEmail implementations updated ✅

The new privKeys map[string]string parameter has been applied consistently across the codebase:

  • internal/app/mail/manager.go: updated Manager.SendPeerEmail implementation
  • internal/app/api/v0/backend/peer_service.go: updated interface stub and PeerService.SendPeerEmail method
  • internal/app/api/v0/handlers/endpoint_peers.go: handler signature and call site aligned

No further action required.

frontend/src/views/KeyGeneraterView.vue (1)

3-8: LGTM! Good refactoring to centralize crypto utilities.

This change successfully removes duplicated cryptographic code by importing the functions from a dedicated helper module, aligning perfectly with the PR objective.

internal/app/api/core/assets/doc/v0_swagger.json (1)

2156-2162: LGTM! Correct API schema for private key transmission.

The new PrivateKeys property properly supports the client-side key generation feature by allowing private keys to be transmitted in peer email requests.

internal/app/api/v0/backend/peer_service.go (2)

35-35: LGTM! Correct interface signature update.

The interface correctly adds the privKeys map[string]string parameter to support private key transmission in email operations.


106-107: LGTM! Implementation correctly matches interface.

The method implementation properly passes the privKeys parameter to the underlying mailer, maintaining consistency with the updated interface.

internal/app/wireguard/wireguard_peers.go (4)

106-113: LGTM! Correct conditional key generation logic.

The implementation properly skips server-side key generation when ClientSidePeerKeygen is enabled, allowing clients to generate their own keys.


125-128: LGTM! Appropriate peer identifier handling for client-side keygen.

Setting the peer identifier to an empty string when client-side key generation is enabled is correct, as the client will provide the public key later.


270-274: LGTM! Consistent private key clearing for multiple peers.

The logic correctly clears private keys for all peers when StorePrivateKeys is disabled, maintaining consistency with the single peer creation logic.


339-341: LGTM! Comprehensive private key clearing in update scenarios.

The implementation correctly handles private key clearing in both peer re-identification and normal update scenarios when StorePrivateKeys is disabled.

Also applies to: 352-354

internal/app/mail/manager.go (3)

98-98: LGTM! The addition of privKeys parameter enables client-side key generation support.

The new parameter allows passing client-generated private keys to be included in peer emails, which aligns with the PR's objective of supporting client-side key generation.


125-127: LGTM! Secure handling of client-provided private keys.

The implementation correctly replaces the peer's interface private key with the client-provided one before sending the email. This ensures that users receive configurations with their own generated keys.


161-161:

❓ Verification inconclusive

Verify the rationale for changing from configFiles to tplHandler for peer config retrieval.

The change from m.configFiles.GetPeerConfig to m.tplHandler.GetPeerConfig suggests a different approach to generating peer configurations. This might be related to the need to handle client-provided private keys dynamically.

Run the following script to understand the differences between these two methods:


🏁 Script executed:

#!/bin/bash
# Description: Compare the GetPeerConfig implementations to understand the change

# Find the tplHandler.GetPeerConfig implementation
echo "=== Looking for tplHandler.GetPeerConfig implementation ==="
ast-grep --pattern 'GetPeerConfig($_) $_'

# Find the configFiles.GetPeerConfig implementation  
echo -e "\n=== Looking for configFiles.GetPeerConfig implementation ==="
rg -A 10 "GetPeerConfig.*\(.*Peer" --type go

Length of output: 13584


Ensure correct preconditions when bypassing configFiles.GetPeerConfig

Switching from:

-  peerCfgReader, err := m.configFiles.GetPeerConfig(ctx, peer.Identifier)
+  peerConfig,   err := m.tplHandler.GetPeerConfig(peer)

bypasses the internal fetch (m.wg.GetPeer) and access‐check (domain.ValidateUserAccessRights) performed by configfile.Manager.GetPeerConfig. Since the mail manager already:

  • loads the peer (m.peers.GetPeer)
  • enforces access rights
  • applies any client‐provided private‐key overrides on peer

confirm that all of those steps occur before invoking tplHandler.GetPeerConfig(peer). Otherwise, you risk missing authorization checks or using an uninitialized key.

frontend/src/components/PeerEditModal.vue (3)

35-44: LGTM! Clear and informative messaging for users.

The cryptoMessage computed property provides excellent user guidance by:

  • Explaining whether keys are generated client-side or server-side
  • Warning when private keys won't be stored
  • Including a general safety reminder

This transparency helps users understand the security implications of their configuration.


118-130: LGTM! Well-implemented client-side key generation with proper fallback.

The implementation correctly:

  • Checks the ClientSidePeerKeygen setting
  • Generates keypair and preshared key client-side when enabled
  • Falls back to server-prepared keys when disabled
  • Uses the public key as the identifier consistently

195-212: LGTM! Correct logic for detecting overridden settings.

The logic properly sets IgnoreGlobalSettings to true when any of the overridable fields are set to non-overridable, which correctly reflects that the peer has custom settings.

Comment on lines +202 to +229
func generatePeerQr(cfgData io.Reader) (io.Reader, error) {
sb := strings.Builder{}
scanner := bufio.NewScanner(cfgData)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if !strings.HasPrefix(line, "#") {
sb.WriteString(line)
sb.WriteString("\n")
}
}
if err := scanner.Err(); err != nil {
return nil, err
}

code, err := qrcode.NewWith(sb.String(), qrcode.WithErrorCorrectionLevel(qrcode.ErrorCorrectionLow), qrcode.WithEncodingMode(qrcode.EncModeByte))
if err != nil {
return nil, err
}

buf := bytes.NewBuffer(nil)
wr := nopCloser{Writer: buf}
option := compressed.Option{Padding: 8, BlockSize: 4}
qrWriter := compressed.NewWithWriter(wr, &option)
if err := code.Save(qrWriter); err != nil {
return nil, err
}
return buf, nil
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Consider adding input validation and improving error messages.

The generatePeerQr function correctly strips comments and generates QR codes. However, there are a few improvements to consider:

  1. The function assumes nopCloser type exists but it's not defined in this file
  2. Consider validating that the resulting configuration is not empty after stripping comments
  3. The error messages could be more descriptive

First, let's verify if nopCloser is defined elsewhere:

Here's an improved version with validation and the missing type:

+type nopCloser struct {
+	io.Writer
+}
+
+func (nopCloser) Close() error { return nil }
+
 func generatePeerQr(cfgData io.Reader) (io.Reader, error) {
 	sb := strings.Builder{}
 	scanner := bufio.NewScanner(cfgData)
 	for scanner.Scan() {
 		line := strings.TrimSpace(scanner.Text())
 		if !strings.HasPrefix(line, "#") {
 			sb.WriteString(line)
 			sb.WriteString("\n")
 		}
 	}
 	if err := scanner.Err(); err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to read config data: %w", err)
 	}
 
+	configStr := sb.String()
+	if strings.TrimSpace(configStr) == "" {
+		return nil, fmt.Errorf("configuration is empty after removing comments")
+	}
+
-	code, err := qrcode.NewWith(sb.String(), qrcode.WithErrorCorrectionLevel(qrcode.ErrorCorrectionLow), qrcode.WithEncodingMode(qrcode.EncModeByte))
+	code, err := qrcode.NewWith(configStr, qrcode.WithErrorCorrectionLevel(qrcode.ErrorCorrectionLow), qrcode.WithEncodingMode(qrcode.EncModeByte))
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to create QR code: %w", err)
 	}
 
 	buf := bytes.NewBuffer(nil)
 	wr := nopCloser{Writer: buf}
 	option := compressed.Option{Padding: 8, BlockSize: 4}
 	qrWriter := compressed.NewWithWriter(wr, &option)
 	if err := code.Save(qrWriter); err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to save QR code: %w", err)
 	}
 	return buf, nil
 }

🏁 Script executed:

#!/bin/bash
# Description: Search for nopCloser type definition

# Search for nopCloser type definition
echo "=== Searching for nopCloser type ==="
rg -A 5 "type nopCloser" --type go

# If not found, search for any nopCloser references
echo -e "\n=== Searching for any nopCloser references ==="
rg "nopCloser" --type go

Length of output: 924


🏁 Script executed:

#!/bin/bash
echo "=== Showing package and import section of internal/app/mail/manager.go ==="
sed -n '1,30p' internal/app/mail/manager.go

Length of output: 1042


Add missing nopCloser type and validate non-empty config in generatePeerQr

The code in internal/app/mail/manager.go currently references nopCloser without defining it in the mail package. In addition, it should guard against an empty configuration after stripping comments and surface more descriptive errors.

Please update as follows:

• Define nopCloser at the top of internal/app/mail/manager.go:

// nopCloser wraps an io.Writer to satisfy io.WriteCloser.
type nopCloser struct {
    io.Writer
}

func (nopCloser) Close() error { return nil }

• In generatePeerQr, after scanning:

-   if err := scanner.Err(); err != nil {
-       return nil, err
-   }
+   if err := scanner.Err(); err != nil {
+       return nil, fmt.Errorf("failed to read config data: %w", err)
+   }
+
+   configStr := sb.String()
+   if strings.TrimSpace(configStr) == "" {
+       return nil, fmt.Errorf("configuration is empty after removing comments")
+   }

• Improve downstream errors:

-   code, err := qrcode.NewWith(sb.String(), …)
-   if err != nil {
-       return nil, err
-   }
+   code, err := qrcode.NewWith(configStr, …)
+   if err != nil {
+       return nil, fmt.Errorf("failed to create QR code: %w", err)
+   }-   if err := code.Save(qrWriter); err != nil {
-       return nil, err
-   }
+   if err := code.Save(qrWriter); err != nil {
+       return nil, fmt.Errorf("failed to save QR code: %w", err)
+   }
🤖 Prompt for AI Agents
In internal/app/mail/manager.go around lines 202 to 229, the function
generatePeerQr uses an undefined type nopCloser, lacks validation for empty
configuration after stripping comments, and has generic error messages. Define
the nopCloser type at the top of the file as a struct embedding io.Writer with a
Close method returning nil. In generatePeerQr, after scanning and building the
config string, check if the resulting string is empty and return a descriptive
error if so. Also, wrap or replace error returns with more descriptive messages
indicating which step failed, such as scanning input, creating QR code, or
saving QR code data.

…frontend`

Docstrings generation was requested by @deel77.

* #1 (comment)

The following files were modified:

* `frontend/src/helpers/crypto.js`
* `internal/app/api/v0/model/models_peer.go`
* `internal/app/mail/manager.go`
* `internal/config/config.go`
@coderabbitai
Copy link

coderabbitai bot commented Jun 3, 2025

Note

Generated docstrings for this pull request at #2

deel77 and others added 3 commits June 4, 2025 01:59
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…gFzywydZ0oSqAvSJI1c5w1TjJnodAp8KELdfeWHf3NSnGhxFPeVawzHw2IITJUR5G

📝 Add docstrings to `codex/make-key-pair-generation-configurable-for-frontend`
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
internal/app/mail/manager.go (1)

217-246: Implement missing improvements from past review.

The generatePeerQr function still lacks the validation and error message improvements suggested in the previous review. The current implementation doesn't validate for empty configuration after comment removal and uses generic error messages.

Apply the suggested improvements from the past review:

 func generatePeerQr(cfgData io.Reader) (io.Reader, error) {
 	sb := strings.Builder{}
 	scanner := bufio.NewScanner(cfgData)
 	for scanner.Scan() {
 		line := strings.TrimSpace(scanner.Text())
 		if !strings.HasPrefix(line, "#") {
 			sb.WriteString(line)
 			sb.WriteString("\n")
 		}
 	}
 	if err := scanner.Err(); err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to read config data: %w", err)
 	}

-	code, err := qrcode.NewWith(sb.String(), qrcode.WithErrorCorrectionLevel(qrcode.ErrorCorrectionLow), qrcode.WithEncodingMode(qrcode.EncModeByte))
+	configStr := sb.String()
+	if strings.TrimSpace(configStr) == "" {
+		return nil, fmt.Errorf("configuration is empty after removing comments")
+	}
+
+	code, err := qrcode.NewWith(configStr, qrcode.WithErrorCorrectionLevel(qrcode.ErrorCorrectionLow), qrcode.WithEncodingMode(qrcode.EncModeByte))
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to create QR code: %w", err)
 	}

 	buf := bytes.NewBuffer(nil)
 	wr := nopCloser{Writer: buf}
 	option := compressed.Option{Padding: 8, BlockSize: 4}
 	qrWriter := compressed.NewWithWriter(wr, &option)
 	if err := code.Save(qrWriter); err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to save QR code: %w", err)
 	}
 	return buf, nil
 }
🧰 Tools
🪛 golangci-lint (1.64.8)

219-219: expected '(', found generatePeerQr

(typecheck)


246-246: expected '}', found 'EOF'

(typecheck)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4084de5 and 01e2042.

📒 Files selected for processing (1)
  • internal/app/mail/manager.go (7 hunks)
🧰 Additional context used
🪛 golangci-lint (1.64.8)
internal/app/mail/manager.go

219-219: expected '(', found generatePeerQr

(typecheck)


246-246: expected '}', found 'EOF'

(typecheck)

🔇 Additional comments (5)
internal/app/mail/manager.go (5)

4-13: LGTM! Imports added correctly for QR code functionality.

The new imports support the QR code generation feature and are properly organized.


19-26: LGTM! nopCloser type implemented as suggested in past review.

The implementation correctly addresses the previous review feedback by defining the missing nopCloser type with appropriate documentation.


81-82: LGTM! Improved function documentation.

The expanded comment provides better clarity about the function's purpose and error conditions.


108-108: LGTM! Function signature updated to support private key injection.

The addition of the privKeys parameter correctly enables client-side key generation functionality as described in the PR objectives.


171-179: LGTM! Correctly switched to template handler and added QR generation.

The change from configFiles.GetPeerConfig to tplHandler.GetPeerConfig and the addition of generatePeerQr aligns with the refactoring objectives.

Comment on lines +192 to 202
if line != "" && !strings.HasPrefix(line, "#") {
return nil, fmt.Errorf("failed to scan config data: %w", err)
}

cfg := strings.TrimSpace(sb.String())
if cfg == "" {
return nil, fmt.Errorf("peer configuration is empty")
code, err := qrcode.NewWith(cfg, qrcode.WithErrorCorrectionLevel(qrcode.ErrorCorrectionLow), qrcode.WithEncodingMode(qrcode.EncModeByte))
return nil, fmt.Errorf("failed to create QR code: %w", err)
return nil, fmt.Errorf("failed to save QR code image: %w", err)
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Critical: Malformed code fragments causing syntax errors.

These lines appear to be misplaced fragments from the generatePeerQr function, causing syntax errors flagged by static analysis tools. This code is in the wrong location and breaks the file structure.

Remove these malformed lines entirely:

-		if line != "" && !strings.HasPrefix(line, "#") {
-		return nil, fmt.Errorf("failed to scan config data: %w", err)
-	}
-
-	cfg := strings.TrimSpace(sb.String())
-	if cfg == "" {
-		return nil, fmt.Errorf("peer configuration is empty")
-	code, err := qrcode.NewWith(cfg, qrcode.WithErrorCorrectionLevel(qrcode.ErrorCorrectionLow), qrcode.WithEncodingMode(qrcode.EncModeByte))
-		return nil, fmt.Errorf("failed to create QR code: %w", err)
-		return nil, fmt.Errorf("failed to save QR code image: %w", err)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if line != "" && !strings.HasPrefix(line, "#") {
return nil, fmt.Errorf("failed to scan config data: %w", err)
}
cfg := strings.TrimSpace(sb.String())
if cfg == "" {
return nil, fmt.Errorf("peer configuration is empty")
code, err := qrcode.NewWith(cfg, qrcode.WithErrorCorrectionLevel(qrcode.ErrorCorrectionLow), qrcode.WithEncodingMode(qrcode.EncModeByte))
return nil, fmt.Errorf("failed to create QR code: %w", err)
return nil, fmt.Errorf("failed to save QR code image: %w", err)
})
🧰 Tools
🪛 golangci-lint (1.64.8)

202-202: expected statement, found ')'

(typecheck)

🤖 Prompt for AI Agents
In internal/app/mail/manager.go around lines 192 to 202, there are malformed and
misplaced code fragments from the generatePeerQr function causing syntax errors.
Remove these incorrect lines entirely to restore proper file structure and
syntax correctness.

Comment on lines +135 to +137
if pk, ok := privKeys[string(peerId)]; ok {
peer.Interface.PrivateKey = pk
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify security implications of private key replacement.

The logic correctly replaces the peer's private key when provided in the privKeys map. However, ensure that this doesn't compromise security by allowing unauthorized key substitution.

Consider adding validation to ensure the provided private key is valid:


🏁 Script executed:

#!/bin/bash
# Description: Check if there are any validation functions for WireGuard private keys in the codebase
# Expected: Find functions that validate private key format or correctness

echo "=== Searching for private key validation functions ==="
rg -A 5 -B 2 "PrivateKey.*valid|valid.*PrivateKey|validatePrivateKey" --type go

echo "=== Searching for WireGuard key validation ==="
rg -A 5 -B 2 "wgkey|wireguard.*key.*valid" --type go

Length of output: 657


Validate the provided private keys before assignment

No existing validation for WireGuard private keys was found in the codebase. To prevent unauthorized or malformed key substitution, you should verify each pk before setting it on the peer.

  • File: internal/app/mail/manager.go (around lines 135–137)
  • Issue: peer.Interface.PrivateKey = pk is assigned blindly when privKeys contains an entry.

Suggested update:

-   if pk, ok := privKeys[string(peerId)]; ok {
-       peer.Interface.PrivateKey = pk
-   }
+   if pk, ok := privKeys[string(peerId)]; ok {
+       // Validate that pk is a well-formed WireGuard private key
+       if crypto.PublicKeyFromPrivateKey(pk) == "" {
+           return fmt.Errorf("invalid private key for peer %s", peerId)
+       }
+       peer.Interface.PrivateKey = pk
+   }

• If you prefer a dedicated validator, add a ValidatePrivateKey(pk string) error function in internal/domain/crypto and call it here.
• Add unit tests to cover both valid and invalid keys.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In internal/app/mail/manager.go around lines 135 to 137, the code assigns a
private key from privKeys to peer.Interface.PrivateKey without validation, which
risks unauthorized or malformed key substitution. To fix this, implement a
validation step before assignment: create a ValidatePrivateKey function in
internal/domain/crypto that checks the key's format and correctness, then call
this validator here to verify pk before setting it. Also, add unit tests to
cover scenarios with valid and invalid keys to ensure robustness.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant