It’s pretty disappointing. Basically it’s just a couple of “background messages” that I need as infrastructural components for the client and key exchange, as well as a ClientSpecific type that is so clients, utilizing a pod can use their own unique “client_id” on their payloads so that they can sort out what they can deserialize and what they can’t from the metadata. If it’s not your “client_id” in the “pod” then you can’t deserialize it.

There is concern about client_id collisions. Which would make sense, except that all it would actually do is cause deserialization to fail (and that should be handled), and both clients “fighting over” a client_id would suffer so there is really no advantage I can see.

Here are the new, messages, which will be serialized to binary before being “wrapped up” in the “ball” or “onion” (yuck to that metaphor) of encryption.

They’re intentionally sparse, and do expect client developers to serialize their payloads to and from binary (we will export supporting functions that make this easier, and some tools already exist). Currently strings are the industry standard and I think that I bad (personal preference… sorry. I’ve just done a lot with JavaScript and Rust + WASM, or v8 + Rust FFI, that binary and passing bytes around is so much easier than serializing structs. So just like get stoked about protobuf or make a better binary serialization format so that we don’t have to keep using strings /rant).

InnerUser

message InnerUser { 
    // there is also the public exchange user that is just the "account user" and that's the one you use for all of your updating
    // bytes are the unique, serialized, protobuf message, or other binary payload, defined by each client

    // ?? how do we handle conflicts
    map<string, bytes> pod_id_client_user_map = 1;
}

It’s really boring: binary is the only format for serialization that we support. The pod_id_client_user_map is exactly that, where the pod_id and client_id make up the key and the user is a set of bytes that can be deserialized by whatever tool was used to serialize it.

InnerMessage

message InnerMessage {
    message InitialKeyExchange {
        // compare against result of username that is user
        bytes their_pub_exchange_key = 1;
        // verify their signature based on a separate request for their user
        bytes their_pub_exchange_key_signature = 2;
    }

    message KeyExchange {
        string pool_id = 1;

        bytes their_pub_exchange_key = 2;
        bytes their_pub_exchange_key_signature = 3;
    }

    message ClientSpecific {
        // all messages are sent through "pods" and there is no restriction to whether or not they can
        // include a colliding client_id. it is however, not in the favor of either application to frequently
        // be failing deserialization of payload, and is a waste of resources so don't do it.
        string client_id = 1;        
        
        // bytes are the unique, serialized, protobuf message, or other binary payload, defined by each client
        bytes payload = 2;
    }
    
    // use to get separately and verify content against
    string sender_username = 1;
    
    oneof message {
        InitialKeyExchange initial_key_exchange = 2;
        KeyExchange key_exchange = 3;
        ClientSpecific client_specific = 4;
    }
}

There will be more messages that I add for infrastructure stuff later probably, for the client and as I think of better ways to serve users, passing these messages around.

Conclusion

Not much there and very intentionally says “do your own serialization and sorry if this makes you bummed but we only support values serialized to binary.”

Caveats

Right now I haven’t worked very hard to think about conflicts in the really wild scenario where two clients want to fight over a UUID (which I think can be preventable, but again, not thought about yet), they might be able to overwrite each other in a way that is irrecoverable for the user on that pod_id+client_id combo (because the client_id was being fought over).