-
Notifications
You must be signed in to change notification settings - Fork 0
Sharing Credentials
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.
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.
sequenceDiagram
participant R as Receiver
participant U as User
participant S as Sender
Note over R,S: The sender generates and displays<br/> a 4-digit pairing code and the user enters<br/> it on the receiver
R->>R: Generate TLS cert
R->>R: Start HTTPS server on random port
loop Every 1 second
R->>R: UDP broadcast PSIE_RECV:{port}:{fingerprint}
end
S->>S: Listen on UDP port 54321
S->>S: Discover receiver (IP, port, cert fingerprint)
U->>U: Read code from one device,<br/>enter it on the other
S->>R: HTTPS GET /pairing-code-hash<br/>(TLS with certificate fingerprint pinning)
R-->>S: { codeHash }
alt Sender verifies pairing code hash matches
S->>R: HTTPS POST /share-payload<br/>{ codeHash, payload }
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
- Both sides start — the sender and receiver are launched on their respective devices.
- Receiver prepares — 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. It also sets a small request budget — the maximum number of HTTPS requests it will accept before aborting the share.
- Pairing code is generated and communicated — the sender generates a random 4-digit pairing code and displays it. The user reads it from the sender's screen and types it into the receiver. This is always the case, for both the CLI and the desktop app.
- Sender discovers receiver — listens on the network for the receiver's UDP broadcast. When one arrives, it knows the receiver's address, port, and expected certificate fingerprint.
-
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. -
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. - 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.
- 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. - Sender always generates the pairing code — the pairing code is generated on the sender and communicated to the receiver out-of-band (the user reads it from the sender's screen and types it on the receiver). This means the code is a secret held by the sender; a receiver must prove it received that secret from the user before any credentials are delivered. A rogue receiver on the network was never told the code, so it cannot pass the hash check even if the sender accidentally connects to it first.
-
Rate limiting — the receiver aborts after a small number of total requests across both endpoints. A legitimate share requires exactly one
GET /pairing-code-hashand onePOST /share-payload, so any excess requests indicate something unexpected and the share is cancelled.
If the receiver were to generate the pairing code instead of the sender, the GET /pairing-code-hash verification would provide no real protection against a rogue receiver. A receiver always knows the hash of its own code because it generated that code itself. If the sender accidentally connects to a rogue receiver (for example, the rogue device responded to the UDP broadcast before the legitimate receiver did), the rogue receiver can trivially pass the hash check — it simply returns the hash of whatever code it displayed. The only remaining protection would be whether the user happened to enter the correct code, which is a weaker guarantee that depends entirely on the user's attention rather than the protocol. With a sender-generated code, a rogue receiver that was never shown the code has, at best, a 1-in-10,000 chance of guessing it, and the request budget limits even that.
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 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.
- Open Manage Databases from the sidebar
- Click the Share button on the database you want to send
- Review and edit the database name, description, and path
- Choose which linked secrets to include using the checkboxes
- Click Send — the app generates a 4-digit pairing code and searches for a receiver on the LAN
- Tell the receiver the pairing code so they can enter it on their device
- The app verifies the code and sends the database
- The dialog shows success
- Open Manage Databases from the sidebar
- Click Receive Database and wait for a sender to connect
- Enter the 4-digit pairing code shown on the sender's screen
- When the sender delivers the payload, review and edit the name, description, path, and choose which secrets to import
- 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
- Click Save to import the database and its secrets
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.
psi dbs receiveStarts 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 sends a single vault entry (S3 credentials, encryption key, or API key) to another device.
- Open Manage Secrets from the sidebar
- Click the Share button on the secret you want to send
- Review the secret type and name
- Click Send — the app generates a 4-digit pairing code and searches for a receiver on the LAN
- Tell the receiver the pairing code so they can enter it on their device
- The app verifies the code and sends the secret
- The dialog shows success
- Open Manage Secrets from the sidebar
- Click Receive Secret and wait for a sender to connect
- Enter the 4-digit pairing code shown on the sender's screen
- When the sender delivers the payload, review the secret type and edit the name to save it as
- 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
- Click Save to import the secret
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.
psi secrets receiveStarts 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.
- 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).
- Managing-Databases — managing the database list
- Managing-Secrets — managing secrets in the vault
-
Command-Reference — full CLI command reference (
dbs send/receiveandsecrets send/receive)