Skip to content

Handshake

Overview

Every DFMailbox instance has an ed25519 public and private key. The public key is used as an identifier for an instance while the private key is used to verify that you own the identifier.

A public key and private key look almost identical: eSBGfP+sy5rCNGL3aqv2JSpgzdgYKjLkTY6CWTHA0us=

Example

In this example, there will be two instances named A and B. Instance A owns a.com and instance B owns b.com. This is what should happen when a user of instance A attempts to send a message to instance B when instance A and B never met.

  1. A initiates a websocket connection to b.com.
  2. B accepts the connection
  3. B immediately sends a hello packet
    {
        "type": "hello",
        // If A finds that this differs from what the user inputted,
        // then A knows that it isn't B's preferred host 
        // and starts the connection process again
        "host": "b.com",
        // B's public key
        "pubkey": "t79om1HOBhZk0oP8S2cG1OOvhrx1rxS9/wEfw9F9k9w=",
        "protocol": {
            "send_max_length": 5,
            "receive_max_length": 2
        }
    }
    
  4. A immediately sends a hello packet. The actual send_max_length is found by getting the lesser of these two, so in this case it would be 5. The same with receive_max_length; in this case it is 2. More information on what this option does can be found in messages.
    {
        "type": "hello",
        "host": "a.com",
        // A's public key
        "pubkey": "m5J/YoL14+z5wElTmMwoq388Jn7niIud684u10pw6n4=",
        "protocol": {
            "send_max_length": 10,
            "receive_max_length": 2
        }
    }
    
  5. B reads A's hello and finds that it hasn't met A before. B sends a host_challenge to verify that A actually owns a.com. Remember, A knows that B owns b.com because it connected to B with a url like wss://b.com/instance.
    {
        "type": "host_challenge",
        // 64 character (max) url safe token to be put in
        // /.well-known/dfmailbox-challenge/<HERE>
        "token": "2_qJtJ6LNjWj3h3r3IAM7SwtHWUEYYfU-7RRR5igcdQ"
    }
    
  6. A sets their /.well-known/dfmailbox-challenge/2_qJtJ6LNjWj3h3r3IAM7SwtHWUEYYfU-7RRR5igcdQ to return B's public key. To tell B to go check the url, A responds to host_challenge with host_ready.
    {
        "type": "host_ready",
        "token": "2_qJtJ6LNjWj3h3r3IAM7SwtHWUEYYfU-7RRR5igcdQ"
    }
    
  7. B sends a request to /.well-known/dfmailbox-challenge/2_qJtJ6LNjWj3h3r3IAM7SwtHWUEYYfU-7RRR5igcdQ and finds it's own public key. B sends a host_verified packet to indicate it's trust of A owning a.com

    {
        "type": "host_verified"
    }
    

  8. A sends a auth_challenge packet to make sure that B really is who they say they are. This is an example of challenge response authentication.

    {
        "type": "auth_challenge",
        // A random base64 string up to 64 bytes
        "nonce": "DeE585tu4Pm78zvJKCi6IqCnl5mc5Y7yl5AdFPTvpJM=",
        "expires_at": 1767218400
    }
    

  9. B responds to A's auth_challenge with a auth_response

    {
        "type": "auth_response",
        "nonce": "DeE585tu4Pm78zvJKCi6IqCnl5mc5Y7yl5AdFPTvpJM=",
        "sig": "2QNsu3Io9KIRmXdnMvfJoyl64TXX2x1HWSZiYRRBWRjHj8oGydnEiqJltFoUrBxeFZ19uUrgIyx73eUc/3oODQ=="
    }
    

  10. A checks the signature and finds that it is correct. It responds with a challenge_verified.
    {
        "type": "challenge_verified"
    }
    
  11. B sends a auth_challenge packet to see if A is who they say they are.
    {
        "type": "auth_challenge",
        "nonce": "SULmMO+hWVeEG21fSHt1teyzwJ+WzclIvCb7cA6IpF4=",
        "expires_at": 1767218400
    }
    
  12. A responds to B's challenge with a auth_response
    {
        "type": "auth_response",
        "nonce": "SULmMO+hWVeEG21fSHt1teyzwJ+WzclIvCb7cA6IpF4=",
        "sig": "hMa24IWFDUI7lOkacfNU/SM06vUc8FCozszmRFkeT3j5vcQLpUyAWfP/UzlepUnqMoxvALZ9T9YkdlaFwc9HDA=="
    }
    
  13. B checks the signature and finds that it is correct. It responds with a challenge_verified.
    {
        "type": "challenge_verified"
    }
    
  14. Since both parties have sent a challenge_verified packet, messages can be sent.

Some notes about this example

  • This series of messages usually isn't this organized and linear, the example follows a more linear form to make it less confusing.
  • The host_challenge only needs to be done when the two instances haven't met before.

Protocols

These are the Sec-WebSocket-Protocol sub protocols that are available - json.v1 - Communicate using JSON - msgpack.v1 - Communicate using MessagePack