## 3. Selectively Revealing Repositories [TOC] In his influential work, *[A Cypherpunk's Manifesto][cyph-man]* (1993), Eric Hughes eloquently encapsulated the essence of privacy, stating: ***Privacy is the power to selectively reveal oneself to the world.*** This notion of self-determination and control over one's personal information stands in stark contrast to the reality of using "private repository" features on traditional centralized code forges. In these systems, privacy is merely an illusion maintained by terms of service agreements, as data is stored in cleartext, fully accessible to the platforms employees, vulnerable to potential misuse, and subject to external pressures such as government requests. Users are left with no real control, forced to blindly trust that their code and data won't be viewed, exploited, or even used without consent for purposes like training large language models. In contrast, Radicle's decentralized approach puts the power of privacy directly in the hands of users by leveraging public key cryptography and granular access control mechanisms. The *power to selectively reveal* is a foundational principle in Radicle, fostering a more resilient and autonomous environment for code collaboration. Through selective replication, private repositories are only accessible to and replicated by repository delegates and collaborators, or nodes specified by the delegates, while fully encrypted connections ensure confidential data transfer between these authorized nodes. Repositories are not encrypted at rest. However, the combination of selective replication and encrypted connections renders them invisible to the rest of the network. This approach effectively creates isolated spaces for private collaboration, embodying the true essence of user-controlled privacy. In this chapter, we'll explore how to maintain sovereignty and control over a private repository while collaborating with a trusted circle. We'll demonstrate how this works by including a seed node in the repository's allow list. ### Initializing a private repository When a private repository is created in Radicle, it's only visible and accessible to explicitly authorized nodes. Privacy is extended to all aspects of the repository, including its data, creation time, Repository ID (RID), and the set of collaborators. To maintain this privacy during data transfer, all connections between nodes, including those to seed nodes, are fully encrypted using the Noise Protocol Framework, which employs ChaCha20-Poly1305 for its cryptographic operations. <aside class="span-2"> <strong>ChaCha20-Poly1305</strong> is a modern encryption system designed for speed and security. It combines two parts: ChaCha20, which scrambles the data to keep it secret, and Poly1305, which creates a unique "fingerprint" for the encrypted data to ensure it hasn't been tampered with. This system works efficiently on all types of devices, from smartphones to computers, without needing special hardware. </aside> To demonstrate how this works in practice, let's create a private repository for a sensitive research project we're working on with our peer, Calyx. We'll start by initializing Git within a new directory named `schrรถdingers-paradox` and committing our initial research findings: $ cd schrรถdingers-paradox $ git init $ cp /var/run/897af.log data/897af.log $ git add data/ $ git add analysis/paxels-report.md $ git commit -m "Add data and report from ship 897AF" Next, to securely share this with Calyx, we initialize it as a private repository in Radicle by passing the `--private` flag with `rad init`: $ rad init --private This command functions similarly to the public repository initialization process. It guides us through creating a new private repository, generates a Repository ID (RID), and creates a special Git remote named `rad` in our working copy. The key difference is that setting the `--private` flag automatically configures the `visibility` option to private. As a result, the repository remains unannounced and unpublished on the network, reflecting its nature ๐Ÿฅท. $ rad init --private Initializing private radicle ๐Ÿ‘พ repository in /home/paxel/src/schrรถdingers-paradox.. โœ“ Name schrรถdingers-paradox โœ“ Description Recent data from research vessel 897AF has revealed peculiar patterns that, if verified, could have significant implications for our understanding of the universe. โœ“ Default branch main โœ“ Repository schrรถdingers-paradox created. Your Repository ID (RID) is rad:z3jEQE4VMzkR1UVeSLiN9E8AMtV6a. You can show it any time by running `rad .` from this directory. You have created a private repository. This repository will only be visible to you, and to peers you explicitly allow. To make it public, run `rad publish`. To push changes, run `git push`. ### Curating the *allow* list Now that we have our private repository, the next step is to grant access to our collaborators. The newly created private repository, `schrรถdingers-paradox`, will initially be accessible solely to us. However, to collaborate on this repository with others, we need to curate its allow list to include the Decentralized Identifiers (DIDs) of Calyx, and a trusted [seed node][seeder] that we manage that has a public DNS address (e.g `example.darkstar.org`). This seed node is necessary to facilitate the synchronization of repository updates between Calyx and us. > ๐Ÿ‘ป > > Private repositories are not encrypted at rest, so any node that you add to > the allow list will have visibility to the contents of your private > repositories, but they are completely invisible to the rest of the network. > > There are two possible approaches for distributing private repositories among > collaborative peers: > > 1. Adding an intermediary seed node with a public DNS address to the allow > list (this is the option discussed in this current chapter). > 2. Adding a user node or seed node configured with a Tor .onion address (this > option is discussed in [Chapter 4][ch4]). We can add both Calyx and our managed seed node to the allow list using a single `rad id update` command. This command requires a `--title` for the update, along with each authorized DID specified following an `--allow` flag: $ rad id update --title "Add Calyx and example.darkstar.org to allow list" \ --allow did:key:z6Mkgom1bTxdh9fMFxFNXFMw3SbXnma6NARdsfcFuunurCap \ --allow did:key:z6MkqNZS9QWvC4wbZ8Vz4hQZ1FzN8q4XGj2KGmK9qNgQ8VWt Once we submit the update above, it is automatically approved, as we are the repository's sole delegate: ``` $ rad id update --title "Add Calyx and example.darkstar.org to allow list" \ --allow did:key:z6Mkgom1bTxdh9fMFxFNXFMw3SbXnma6NARdsfcFuunurCap \ --allow did:key:z6MkqNZS9QWvC4wbZ8Vz4hQZ1FzN8q4XGj2KGmK9qNgQ8VWt โœ“ Identity revision 8d3b8d3d4903026f7e0d4c969d82613025d34432 created โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ”‚ Title Add Calyx and iui.darkstar.org to allow list โ”‚ โ”‚ Revision 8d3b8d3d4903026f7e0d4c969d82613025d34432 โ”‚ โ”‚ Blob 219f9cd8130dad644375fa729ba7b31997358945 โ”‚ โ”‚ Author did:key:z6MkvZwzK64f3GuDcAs6dEcje89ddfHkBjS1v9Dkh7aCGq3C โ”‚ โ”‚ State accepted โ”‚ โ”‚ Quorum yes โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โœ“ did:key:z6MkvZwzK64f3GuDcAs6dEcje89ddfHkBjS1v9Dkh7aCGq3C paxel (you) โ”‚ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ @@ -1,17 +1,21 @@ { "payload": { "xyz.radicle.project": { "defaultBranch": "main", "description": "Recent data from research vessel 897AF has revealed peculiar patterns that, if verified, could have significant implications for our understanding of the universe.", "name": "schrรถdingers-paradox" } }, "delegates": [ "did:key:z6MkvZwzK64f3GuDcAs6dEcje89ddfHkBjS1v9Dkh7aCGq3C" ], "threshold": 1, "visibility": { - "type": "private" + "type": "private", + "allow": [ + "did:key:z6Mkgom1bTxdh9fMFxFNXFMw3SbXnma6NARdsfcFuunurCap", + "did:key:z6MkqNZS9QWvC4wbZ8Vz4hQZ1FzN8q4XGj2KGmK9qNgQ8VWt" + ] ``` You can see that the two DIDs were added to the `allow` list, which now grants both Calyx and our seed node access to the `schrรถdingers-paradox` repository. > ๐Ÿ‘ป > > It is possible to update a repository that is currently public to become > private, with a repository identity update: > ``` > $ rad id update --title "Update visibility" --visibility private > ``` > This won't delete historic repository data from public seed nodes or other > peers that previously seeded or cloned the repository, meaning the public will > still be able to clone the old version of the repository. > > Instead, future updates to the repository, including and repository's private > status will only be announced and accessible to those explicitly defined in > the `allow` list. ### Replicating to our seed node Now that we've set up our private repository and managed access, let's replicate `schrรถdingers-paradox` onto our seed node. Our repository has the RID `rad:z3jEQE4VMzkR1UVeSLiN9E8AMtV6a`, which we'll use with the `rad seed` command to accomplish this. Since `schrรถdingers-paradox` is a private repository, we also need to specify our (Paxel's) Node ID using the `--from` flag to explicitly indicate the source node. Let's run the command: darkstar$ rad seed rad:z3jEQE4VMzkR1UVeSLiN9E8AMtV6a --from z6MkvZwzK64f3GuDcAs6dEcje89ddfHkBjS1v9Dkh7aCGq3C This will both update the seeding policy to include `rad:z3jEQE4VMzkR1UVeSLiN9E8AMtV6a` and also fetch the repository from our node. To ensure the replication was successful, we can check the seeding status: darkstar$ rad seed Now that the repository is on the seed node, it can serve as a reliable access point for other authorized peers, since the seed node will always be running, and our computer won't be. Remember, only peers on the repository's allow list will be able to fetch from this seed node. > ๐Ÿ‘พ > > In the instructions above, we are assuming the use case where the seed node is > already specified as a `preferredSeeds` in our node configuration, which > ensures an automatic connection is established when starting our node. > > If you're experiencing issues with repository replication, try these > troubleshooting steps: > > 1. Check your current connections: > ``` > $ rad node status > ``` > > 2. If your seed node isn't listed, manually connect using: > ``` > $ rad node connect <address> > ``` > For example: > ``` > $ rad node connect z6MkqNZS9QWvC4wbZ8Vz4hQZ1FzN8q4XGj2KGmK9qNgQ8VWt@example.darkstar.org:8776 > ``` > > To find your seed node's address, run `rad node config --addresses` on the > seed node itself. > > For comprehensive information on setting up and managing seed nodes, refer to > our [Seeder's Guide][seeder]. ### Cloning as a trusted peer With our repository now successfully seeded, Calyx can clone our project. Since `schrรถdingers-paradox` is a private repository, Calyx needs to specify the seed node to fetch from, using the `--seed` flag: calyx$ rad clone rad:z3jEQE4VMzkR1UVeSLiN9E8AMtV6a --seed z6MkqNZS9QWvC4wbZ8Vz4hQZ1FzN8q4XGj2KGmK9qNgQ8VWt By providing the seed node's NID, Calyx can fetch the repository data directly. There's no need for a `rad node connect` command because the seed node is already hosting the repository and is accessible via a public address. After cloning, Calyx begins working on the research project. Once he completes his initial findings, he commits them to the repository and pushes a patch: $ git add analysis/calyxs-report.md $ git commit -m "Calyx's report of vessel 897AF data" $ git push rad HEAD:refs/patches > ๐Ÿ‘พ > > Need a refresher on collaboration basics? Check out [Chapter 2][ch2], or > review `man rad-patch` for details on working with patches. ### Removing nodes from the *allow* list Our seed node became compromised, and now we have to revoke access privileges to it. We use the `rad id update` command with the `--disallow` flag: $ rad id update --title "Revoke compromised node" \ --disallow did:key:z6MkqNZS9QWvC4wbZ8Vz4hQZ1FzN8q4XGj2KGmK9qNgQ8VWt This removes the seed node from being able to access it. (Luckily, we were able to delete the data on the seed node before the attacker got access to it!) > ๐Ÿ‘พ > > As projects evolve, you might decide that a repository no longer needs to be > private. In such cases, you can easily change its visibility. Simply run `rad > publish` within the repository to transform it from private to public. *Radicle's codebase hasn't yet undergone formal security audits. While we're confident in its security, undiscovered vulnerabilities may exist. If you encounter any issues, we encourage you to report them to **security@radicle.xyz*** ## 4. Embracing the Onion **[Tor][tor]**, aka The Onion Router, is a decentralized network that anonymizes users' online activities by routing internet traffic through multiple encrypted relays, providing stronger anonymity compared to traditional VPNs. To further enhance collaboration on private repositories, Radicle nodes can be configured to run on Tor, allowing connections to be represented by `.onion` addresses. <aside class="span-2"> Tor, originally developed by the U.S. Naval Research Laboratory in the 1990s, was designed to protect government communications. It was further developed by DARPA before becoming a public project. In 2006, the non-profit Tor Project was established to maintain and improve the network. Today, Tor is widely used by individuals, activists, journalists, and organizations seeking greater online privacy.</aside> Depending on how you configure Tor with Radicle, it offers several key advantages: * **Enhanced Anonymity**: Your node's real IP address is hidden, making it difficult for others to track your online activities or determine your location. * **NAT Traversal**: Tor automatically handles Network Address Translation (NAT) traversal, eliminating the need for manual port forwarding or UPnP configuration. This means peers can directly connect with one another, without a seed node, even those behind restrictive firewalls. * **Censorship Resistance**: Repositories accessible via Tor are more resilient against censorship attempts, as the Tor network is designed to circumvent blocking. Network Address Translation (NAT) typically creates barriers for direct peer-to-peer (P2P) communication. Devices behind NAT gateways are often isolated with non-routable private IP addresses, making them inaccessible from the public internet. This is common in most consumer internet setups. Tor addresses this issue by providing static `.onion` addresses โ€“ cryptographic identifiers representing nodes that are routable across the Tor network. This allows peers behind NAT to connect directly without needing to know each other's public IP addresses, overcoming limitations faced by traditional P2P networks. This chapter will explore a few distinct Tor configurations for Radicle: 1. **Mixed Mode**: Only connections to other onion addresses go through Tor, while other connections work normally. 2. **Full Proxy Mode**: All traffic is routed through Tor for maximum anonymity. 3. **Transparent Proxy**: Leverages an existing fully transparent Tor proxy on the network. Before proceeding, ensure you have Tor installed on your system. Use your preferred package manager to install it (the package name is typically "tor"). For detailed instructions, refer to the [Tor installation guide][install-tor]. ### Setting up a Tor Onion Service for Radicle We've been collaborating with Calyx on the private `schrรถdingers-paradox` repository. Recently, we removed a compromised seed node from the repository's `allow` list, which inadvertently cut off Calyx's access to the repository. To restore Calyx's access and enhance the security of our sensitive research, we'll configure our own node as a Tor Onion Service (also known as a hidden service). This setup will make our node accessible via a `.onion` address, allowing Calyx to connect directly to us without relying on any intermediary seed nodes. Let's set up our Tor Onion Service (the following steps are for Linux-based systems): 1. Create a new `radicle` directory for our Onion Service, ensuring it's readable and writable: $ sudo mkdir -m 700 /var/lib/tor/radicle This directory will store information and cryptographic keys for your Onion Service. 2. Open up your Tor configuration file (`torrc`) in an editor, such as vi: $ sudo vi /etc/tor/torrc 3. Add the following lines to the configuration file: HiddenServiceDir /var/lib/tor/radicle HiddenServicePort 8776 These lines set the `HiddenServiceDir` to the path of the folder we just created (replace the path if yours is in a different location) and specify the `HiddenServicePort` as 8776, which is the default port for Radicle. 4. Restart Tor to apply the configuration changes: $ sudo systemctl restart tor 5. Retrieve your `.onion` address: $ sudo cat /var/lib/tor/radicle/hostname Copy this `.onion` address to your clipboard, as we'll need it to configure our Radicle node in the next steps. (It should be something like `1odmmeotgcfx65l5hn6ejkaruvai222vs7o7tmtllszqk5xbysolfdd.onion`) > ๐Ÿง  > > If you are a macOS user, these alternate commands may be handy: > - You can install Tor via `brew install tor` and restart it via `brew > services restart tor` > - Use the command `mkdir -m 700 ~/.tor/radicle` to create your hidden > service directory > - Edit the `torrc` configuration file via `vi /usr/local/etc/tor/torrc` > - The hidden service directory line should be: `HiddenServiceDir > /Users/your-user-name/.tor/radicle` -- yet replace `your-user-name` > - Get your `.onion` address via `cat ~/.tor/radicle/hostname` > > If you are a Debian user who got Tor from a Debian repo, you may need to > change the ownership of the `radicle` directory to the `debian-tor` user and > group first: > > $ sudo chown -R debian-tor:debian-tor /var/lib/tor/radicle ### Balancing privacy and performance with the *mixed mode* Now that we have Tor properly set up, it's time to configure the networking on our Radicle node to work with it. There are several configuration options available, but for our use case, we'll implement the *Mixed Mode* where only connections to `.onion` addresses go through Tor, while other connections work normally. This configuration offers a balance between privacy and performance: * It maintains low latency for regular public repositories. * It allows connectivity to Tor nodes for enhanced privacy when needed. We're choosing this mode because we've already been collaborating on public repositories with our IP address exposed. To set this up: 1. We stop our Radicle node and open our node configuration file: $ rad node stop $ rad config edit 2. Under the `node` key in our configuration, we define a new `onion` subkey where we set its `mode` to `proxy` and `address` to the Tor SOCKS5 address `127.0.0.1:9050`: "node": { ... "onion": { "mode": "proxy", "address": "127.0.0.1:9050" }, ... } 1. Still under the `node` key, we make our node publicly accessible via our `.onion` address, on port 8776: "node": { ... "externalAddresses": [ "1odmmeotgcfx65l5hn6ejkaruvai222vs7o7tmtllszqk5xbysolfdd.onion:8776" ], ... } *This is the `.onion` address we obtained earlier.* 2. Lastly, under the `node` key again, we ensure our node listens for connection requests on `0.0.0.0:8776`: "node": { ... "listen": [ "0.0.0.0:8776" ], ... } This configuration allows our node to use Tor for `.onion` connections while maintaining direct connections for regular traffic, balancing our privacy and performance needs. ### Applying changes and making connections Now that we have updated our configuration, we can start up our node again: paxel$ rad node start Since our node is online, Calyx can now continue to collaborate with us on `schrรถdingers-paradox`. He uses the `rad node connect` command to establish a direct connection with us: calyx$ rad node connect z6Mkhp7VUnuufpvuQ3PdysShAjL86VDRUpPpkesqiysDBGs9@odmmeotgcfx65l5hn6ejkaruvai222vs7o7tmtllszqk5xbysolfdd.onion:8776 By leveraging Radicle's private repositories and the Tor network, we protected our project's confidentiality and stood resilient in the face of attacks on our infrastructure. When nodes are *Torrified* like ours is, it's also easy for other peers to establish connections directly with us, without requiring an intermediary seed node. > ๐Ÿ‘พ > > Of course, Tor can also be set up on a seed node for a persistent, private > connection. Simply follow the previous Tor configuration steps on your seed > node, and enable it as a system service that starts automatically on boot > using `sudo systemctl enable tor`. ### Alternative Tor configurations While we've focused on Mixed Mode, there are two additional configurations that offer more comprehensive network privacy through Tor. These options route all Radicle traffic through the Tor network, which may impact latency but provide enhanced anonymity. **Full Proxy Mode** Full Proxy Mode routes all traffic through Tor for maximum anonymity. This mode leverages the same Tor connection we set up earlier. Here's how to configure it: 1. In your Radicle configuration file, assign the global proxy to the Tor SOCKS5 address `127.0.0.1:9050`: "node": { ... "proxy": "127.0.0.1:9050", ... } 2. Configure onion connections to use the global proxy by setting the mode to `forward`: "node": { ... "onion": { "mode": "forward" }, ... } 3. Make your node publicly accessible via its `.onion` address, on port 8776: "node": { ... "externalAddresses": [ "your-onion-address.onion:8776" ], ... } *Be sure to replace `your-onion-address.onion` with your actual `.onion` address.* 4. Ensure your node listens for connection requests on `0.0.0.0:8776`: "node": { ... "listen": [ "0.0.0.0:8776" ], ... } **Transparent Proxy Mode** If you've already set up a fully transparent Tor proxy on your network, you can use this simpler *Transparent Proxy Mode* configuration: Don't set any other `proxy` settings. Instead, set the onion mode to `forward`: "node": { ... "onion": { "mode": "forward" }, ... } <aside>Configuring a transparent Tor proxy for your entire network is beyond the scope of this guide. If you're interested in this setup, consult the Tor Project documentation for detailed instructions.</aside> *Radicle's codebase hasn't yet undergone formal security audits. While we're confident in its security, undiscovered vulnerabilities may exist. If you encounter any issues, we encourage you to report them to **security@radicle.xyz*** [proto]: /guides/protocol/ [seeder]: /guides/seeder/ [zulip]: https://radicle.zulipchat.com/ [did]: https://en.wikipedia.org/wiki/Decentralized_identifier [ssb]: https://en.wikipedia.org/wiki/Secure_Scuttlebutt [bt]: https://en.wikipedia.org/wiki/BitTorrent [tor]: https://www.torproject.org [install-tor]: https://community.torproject.org/onion-services/setup/install/ [cyph-man]: https://www.activism.net/cypherpunk/manifesto.html [heartwood]: https://app.radicle.xyz/nodes/seed.radicle.xyz/rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 [cobs]: /guides/protocol/#collaborative-objects [ch1]: /guides/user/#1-getting-started [ch2]: /guides/user/#2-collaborating-the-radicle-way [ch3]: /guides/user/#3-grow-resilient-with-seeding [ch4]: /guides/user/#4-embracing-the-onion