Skip to content

Sharing Credentials

Ashley Davis edited this page Apr 25, 2026 · 8 revisions

Photosphere supports sharing database configurations and secrets between devices over the local network (LAN). This is useful for setting up a new device with the same databases and credentials as an existing one, without manually copying secrets.

Both devices must be on the same local network. This feature does not work over the internet.

One device acts as the sender and the other as the receiver. The sender chooses what to share and can edit details before sending. The receiver reviews the incoming data and can edit it before saving.

Security Architecture

Credentials are transferred over HTTPS with a self-signed TLS certificate generated at runtime. This encrypts all traffic so that no other device on the network can read it, even if it intercepts the packets.

How it works

sequenceDiagram
    participant R as Receiver
    participant Net as LAN (UDP + HTTPS)
    participant S as Sender

    S->>S: Generate 4-digit code, display to user
    R->>R: Generate TLS cert
    R->>R: Start HTTPS server on random port

    loop Every 1 second
        R->>Net: UDP broadcast<br/>PSIE_RECV:{port}:{fingerprint}
    end

    S->>Net: Listen on UDP port 54321
    Net-->>S: Discover receiver<br/>(IP, port, cert fingerprint)

    R->>R: User enters pairing code<br/>from sender's screen

    S->>Net: HTTPS GET /pairing-code-hash<br/>TLS with certificate fingerprint pinning
    Net->>R: Deliver request
    R-->>S: { codeHash }

    alt Sender verifies pairing code hash matches
        S->>Net: HTTPS POST /share-payload<br/>{ codeHash, payload }
        Net->>R: Deliver request

        alt Pairing code hash matches
            R-->>S: 200 OK
            R->>R: Display payload for review
            R->>R: User edits and saves
        else Pairing code hash mismatch (request budget exhausted)
            R-->>S: 403 Forbidden
        end
    else Pairing code hash mismatch
        S->>S: Abort — not talking to the right receiver
    end
Loading
  1. Sender starts — generates a random 4-digit pairing code and displays it to the user.
  2. Receiver starts — generates a self-signed TLS certificate and starts an HTTPS server on a random port. It broadcasts its availability via UDP so that senders can discover it. The receiver also sets a small request budget — the maximum number of HTTPS requests it will accept before aborting the share.
  3. User enters code on receiver — the user reads the pairing code from the sender's screen and enters it on the receiver.
  4. Sender discovers receiver — listens on the network for the receiver's broadcast. When one arrives, it knows the receiver's address, port, and expected certificate fingerprint.
  5. Sender verifies the receiver — connects over HTTPS (pinning the certificate fingerprint from the broadcast) and requests the receiver's pairing code hash from GET /pairing-code-hash. This counts against the receiver's request budget. The sender checks the returned hash matches its own code. If it doesn't match, the sender aborts — it is not talking to the correct receiver.
  6. Sender sends payload — the sender posts the JSON payload along with the pairing code hash to POST /share-payload. This also counts against the receiver's request budget.
  7. Receiver verifies and accepts — checks the pairing code hash. On match, the payload is presented to the user for review. On mismatch the request is rejected. The receiver maintains a small budget of total requests across both endpoints; once exhausted it aborts the share entirely, preventing brute-force attempts.

Why this is safe

  • Transport encryption — all HTTP traffic is encrypted by TLS. Even if another device on the LAN captures the packets, it cannot read the contents.
  • Certificate pinning — the TLS certificate fingerprint is included in the UDP broadcast, so the sender verifies it is talking to the correct receiver. A man-in-the-middle attacker cannot substitute their own certificate without the sender rejecting the connection.
  • Mutual pairing code verification — authentication is two-way. The sender verifies the receiver knows the pairing code (via GET /pairing-code-hash) before sending anything. The receiver also verifies the sender knows the pairing code before accepting the payload. A rogue receiver that doesn't know the code cannot receive a payload, and a rogue sender that doesn't know the code cannot deliver one.
  • Rate limiting — the receiver aborts after a small number of total requests across both endpoints. A legitimate share requires exactly one GET /pairing-code-hash and one POST /share-payload, so any excess requests indicate something unexpected and the share is cancelled.

Note: LAN sharing is designed for trusted networks such as your home or office. On public Wi-Fi or other shared networks, unknown devices could exhaust the receiver's request budget before the real sender connects, causing the share to fail. Credential theft is not a realistic risk — the protocol's mutual authentication prevents it — but the share may be unreliable on hostile networks.

Sharing a Database

Sharing a database sends the database configuration (name, description, path, origin) along with any linked secrets you choose to include (S3 credentials, encryption key, geocoding API key). The receiver gets a complete database entry with all selected secrets ready to use.

Desktop App

Sending

  1. Open Manage Databases from the sidebar
  2. Click the Share button on the database you want to send
  3. Review and edit the database name, description, and path
  4. Choose which linked secrets to include using the checkboxes
  5. Click Send — a 4-digit pairing code is displayed
  6. Tell the receiver the pairing code so they can enter it on their device
  7. The app searches for a receiver on the LAN, verifies it, and sends the database
  8. The dialog shows success

Receiving

  1. Open Manage Databases from the sidebar
  2. Click Receive Database
  3. Enter the 4-digit pairing code shown on the sender's screen
  4. When the sender delivers the payload, review and edit the name, description, path, and choose which secrets to import
  5. If an incoming secret name already exists in your vault, you will be prompted to resolve the conflict: reuse the existing secret, replace it, or save the incoming one under a new name
  6. Click Save to import the database and its secrets

CLI

Sending

psi dbs send [name]

If the name is omitted, an interactive prompt lists all configured databases to choose from. You can review and edit the database fields and choose which secrets to include before sending. A 4-digit pairing code is displayed — tell the receiver this code so they can enter it on their device.

Receiving

psi dbs receive

Starts a receiver and waits for a sender. Enter the 4-digit pairing code shown on the sender's screen. When a payload arrives, you can review and edit the fields before saving.

If an incoming secret name already exists in your vault, you will be prompted to resolve the conflict: reuse the existing secret, replace it with the incoming one, or save the incoming one under a new name. In non-interactive mode (--yes), conflicts are resolved by reusing the existing secret.

Sharing a Secret

Sharing a secret sends a single vault entry (S3 credentials, encryption key, or API key) to another device.

Desktop App

Sending

  1. Open Manage Secrets from the sidebar
  2. Click the Share button on the secret you want to send
  3. Review the secret type and name
  4. Click Send — a 4-digit pairing code is displayed
  5. Tell the receiver the pairing code so they can enter it on their device
  6. The app searches for a receiver on the LAN, verifies it, and sends the secret
  7. The dialog shows success

Receiving

  1. Open Manage Secrets from the sidebar
  2. Click Receive Secret
  3. Enter the 4-digit pairing code shown on the sender's screen
  4. When the sender delivers the payload, review the secret type and edit the name to save it as
  5. If the chosen name already exists in your vault, you will be prompted to resolve the conflict: reuse the existing secret, replace it, or save under a new name
  6. Click Save to import the secret

CLI

Sending

psi secrets send [name]

If the name is omitted, an interactive prompt lists all vault secrets to choose from. A security warning is shown before sending. A 4-digit pairing code is displayed — tell the receiver this code so they can enter it on their device.

Receiving

psi secrets receive

Starts a receiver and waits for a sender. Enter the 4-digit pairing code shown on the sender's screen. When a payload arrives, you can review the type and edit the save name before importing. If the chosen name already exists in your vault, you will be prompted to resolve the conflict: reuse the existing secret, replace it, or save under a new name.

Tips

  • Only run one receiver at a time on a device. If two receivers are running, the sender connects to whichever it discovers first and verifies it knows the correct pairing code — but it's simpler to avoid the ambiguity.
  • The share times out after 60 seconds if no connection is made. You can cancel at any time with Ctrl+C (CLI) or the Cancel button (desktop).
  • Imported secrets are automatically linked to the imported database entry.
  • The sender and receiver must be on the same local network (same subnet for UDP broadcast to work).

Related Pages

Clone this wiki locally