Group: GNU Social P2P/Node Architecture
Contents
Introduction
This is a proposal for the structure of a GNU Social node. This document makes no assumptions about the high-level protocol of GNU Social; rather, it attempts to specify what a GNU Social node should look like.
Goals
The goal of this design is to be, above else, modular and adaptable. The design attempts to define points of high-level interaction between components, and isolate that higher-level protocol from the underlying implementation. This yields the property of adaptability - as time marches on and languages or systems pass in and out of vogue, this design should minimize the amount of work required to change relevant parts of the system.
Inspiration
This design is chiefly inspired by the node structure of GNUnet, an anonymous, decentralized, and censorship-resistant peer-to-peer and friend-to-friend network. Initially, GNUnet was a file sharing network, but the modular nature of its implementation allowed it to grow to fill a number of other roles.
GNUnet introduced a concept I believe to be novel - the modular transport layer. Rather than communications between nodes being routed over a low-level networking stack, such as a kernel's TCP or UDP implementation, the GNUnet core communicates with other GNUnet nodes via an internal transports API. Nodes specify which transports they have in common and communicate over shared transports, transparently to the core. As long as two GNUnet nodes have at least one transport in common, they can communicate.
Design
I propose a structure wherein a complete GNU Social node - something which a user can install and use - will consist of five parts: the core, the UI, the core transports, the datastore modules, and the UI transports. A message will arrive on the node's machine via a core transport, where it will be relayed to the core. The core will process the message as it must, and relay it to the UI through a variety of UI transports. If the message or user response involves a manipulation or changing of local state, the core will invoke the user-specified datastore module to retrieve or store information.
The Core
The core is the controlling element of GNU Social. It manipulates data and controls node state. The core might live on a different server than the UI - this fact should be kept in mind during implementation of UI programs, in that the core should never be trusted with sensitive data or encryption tasks.
The core has a high-level view of GNU Social operations. It sees "friending" someone in the context of high-level actions, such as communicating with a remote node and making a change in local state, rather than low-level procedures, such as sending an HTTP POST request to a remote HTTP server and committing a change to a database or relational document. The core has a repertoire of actions which it knows how to do, which it exposes to the UI transports.
The core speaks the GNU Social protocol to other nodes, by means of the core transports. It is agnostic as to how these messages are actually delivered. In a similar manner, it speaks the GNU Social UI protocol to UI instances, but is agnostic as to how or what these programs ultimately receive, and it speaks the GNU Social Datastore protocol to datastore modules, which handle actually recording persistent state.
Core Transports
Core transports manage communication between nodes. Transports are agnostic to the GNU Social protocol - they merely relay messages between nodes. For comparison, the GNUnet transport API consists of two functions for starting and stopping the transport itself, five functions for establishing connections between nodes (two only for bi-directional functionality), and two functions for sending and receiving data.
The GNU Social core has an API by which it communicates with another node. Calls to this API are dynamically dispatched to the appropriate transport module, which actually sends and receives data in some manner to the other node.
With this method, we can ensure that GNU Social is not trivially censorable - there is no one port to throttle or block, and no one protocol to attempt to detect. GNU Social traffic can be tunneled over arbitrary other protocols for which a transport module has been written.
Additionally, we can prevent network topology limitations such as NAT or censorship from having a major impact by routing traffic through intermediary nodes. If Alice and Bob wish to talk to each other, but Alice only speaks HTTP and Bob only speaks XMPP, an intermediary node Charlie which speaks both HTTP and XMPP can relay traffic for them.
In a maximally secure GNU Social system, transport layers would use their lower-level protocols cryptographic capabilities to the fullest extent.
Example lower-level transports which could exist include:
- HTTPS
- XMPP
- PSYC
- OStatus
- TCP
- UDP
- SCTP
- DNS
- ICMP
- 802.11x
- <CvL> In order to not inhibit distribution efficiency I would suggest to extend the API as follows: One function to send a message to a group of people and another to define such a group of people. This allows for multicast-capable protocols to optimize routing and massively reduce overhead. To avoid abuse, recipients must reject and prune content they have received from a source they did not subscribe to.
The UI
The UI is responsible for retrieving messages from the core via UI transports, displaying these messages to the user in an intelligible way, and sending the user's commands back to the node.
Different UIs will exist for different purposes. As such, it might be rare that a UI implement all the functionality in GNU Social. UIs could be as simple as the Ubuntu MeMenu, which modifies "status" or presence data, or as complex as a PHP-based web interface. UIs will hopefully exist in a diverse GNU Social culture.
The UI is the only place where user data needs to be unencrypted, unless users are outfitted with decrypting retinal implants. Consequently, it is where end-to-end encryption between users must occur. This could be totally transparent to the user, or entirely visible, depending on the discretion of the UI author. However, all data should be encrypted end-to-end. If the data is meant for other users, it should be encrypted with those users keys. If the data is meant to be stored on the local node, it should be encrypted with that user's key. Public, unencrypted actions should only be supported in a subset of cases.
- <CvL> Here it makes sense to write up a clear specification for multicast-capable cryptography which also happens to be a lot more efficient: In every group context the group manager generates a symmetric key to encrypt all group content with. This key is distributed once to all members encrypted to their respective public keys. From then on only one encryption operation is necessary at sending time and all messages can be identical for all recipients which allows for efficient multicast distribution.
UI Transports
Similar to core transports, UI transports transmit higher-level concepts from the core to lower-level systems. This allows for different systems to control the core in a way most appropriate to them. For instance, for the case of a web UI and core, the most appropriate UI transport might be a simple callback system. For the case of the MeMenu, D-BUS would be more appropriate. Desktop UI's written for the GNOME or KDE desktops might want to use a local or internet socket to communicate with the core.
Datastore Modules
Different node profiles call for different means of keeping persistent state. For high-profile, massively multi-user nodes, the best choice might be an enterprise-grade SQL database. For a single user node, a more lightweight database like SQLite or CouchDB, or even a simple RDF file, might suffice.
For this reason, the core has knowledge not of SQL or RDF, but of datastores. Each node has at least one datastore to keep track of its user's data.
Hazy areas
Some design decisions regarding this problem are decidedly undecided. For instance, how should the core interact with transport modules? Should they be plugins, loaded at runtime, or independent processes?
Conclusion
Our design, if implemented, will create a GNU Social culture wherein no technology reigns supreme. Any part of the implementation can be swapped out with any other part implementing that same protocol at the will of the user. This will "future-proof" the system: rather than investing heavily in one paradigm or technology, this specifies a high-level set of interactions which components must support, and allows anything to implement that set of interactions. Further, this design allows data to be unencrypted on a strict need-to-know basis, and ensures that cryptography can be executed on a CPU the user controls (presuming the user is running the UI responsibly).
I believe that this is the best way for GNU Social nodes to be designed. It allows for maximum user choice and security, and for components to be obsolesced whenever a better component is available.