Komrade is a socialist network. It seizes the means of digital production.
Comrad is a socialist network. It seizes the means of digital production.
## Why another social network?
## Why another social network?
@ -16,7 +16,7 @@ All of your data are strongly encrypted end-to-end: only you and those you write
### Untraceable
### Untraceable
All network traffic is routed through Tor, a "deep web" of computers so dense even the FBI can't follow you through it. Komrade's "Operator" or central server is accessible only from Tor. It's impossible to tell who is sending what to whom, or even who is using the app at all.
All network traffic is routed through Tor, a "deep web" of computers so dense even the FBI can't follow you through it. Comrad's "Operator" or central server is accessible only from Tor. It's impossible to tell who is sending what to whom, or even who is using the app at all.
### Unmonetizable
### Unmonetizable
@ -28,7 +28,7 @@ Group accounts or 'collectives', like @portland or @socialists, grow as existing
### (Semi-)decentralized
### (Semi-)decentralized
Data is deleted as soon as possible from Komrade. Komrade's "Operator" simply sorts and holds the mail temporarily: as soon as users log in to download their mail, the messages are deleted from the server and network forever.
Data is deleted as soon as possible from Comrad. Comrad's "Operator" simply sorts and holds the mail temporarily: as soon as users log in to download their mail, the messages are deleted from the server and network forever.
### Anti-profit
### Anti-profit
@ -67,19 +67,19 @@ We present a simplified set of social media features drawn from everything that'
## How is this different from ...?
## How is this different from ...?
See ["Comparison of alternative social networks" on the wiki](https://github.com/Komrade/Komrade/wiki/Comparison-of-alternative-social-networks) for an attempt at a systematic comparison. (And please help edit, if you can! The data there is a little incomplete and probably a little inaccurate.) But here are some imagined differences:
See ["Comparison of alternative social networks" on the wiki](https://github.com/Comrad/Comrad/wiki/Comparison-of-alternative-social-networks) for an attempt at a systematic comparison. (And please help edit, if you can! The data there is a little incomplete and probably a little inaccurate.) But here are some imagined differences:
* **It's not (fully) decentralized.** Who's afraid of a little central planning? In contrast to [Secure Scuttlebutt](https://scuttlebutt.nz/) and [Cabal Chat](https://cabal.chat/), which are 100% decentralized, subsisting only through peer-to-peer connections, Komrade sticks with the old, client/server model. Why?
* **It's not (fully) decentralized.** Who's afraid of a little central planning? In contrast to [Secure Scuttlebutt](https://scuttlebutt.nz/) and [Cabal Chat](https://cabal.chat/), which are 100% decentralized, subsisting only through peer-to-peer connections, Comrad sticks with the old, client/server model. Why?
* **It *is* anonymous.** Because P2P networks almost always expose your IP address: they privilege decentralization over anonymity -- and, potentially, safety. By contrast, lying hidden within the deep web of Tor, accessible only from this application and its built-in Tor client, Komrade will never reveal who is accessing it and its encrypted information. This is important for komrades organizing protests against the surveillance state, and to protect our social media traffic from being harvested and monetized by surveillance capitalism.
* **It *is* anonymous.** Because P2P networks almost always expose your IP address: they privilege decentralization over anonymity -- and, potentially, safety. By contrast, lying hidden within the deep web of Tor, accessible only from this application and its built-in Tor client, Comrad will never reveal who is accessing it and its encrypted information. This is important for comrads organizing protests against the surveillance state, and to protect our social media traffic from being harvested and monetized by surveillance capitalism.
* **It's 100% end-to-end encrypted.** Unlike [Mastodon](https://joinmastodon.org/) or [Diaspora](https://diasporafoundation.org/), direct messages between users and within groups remain encrypted 1:1 end-to-end among users. Posts to the public are encrypted to @komrades, a special account which automatically re-encrypts its messages back to any key-registered requester of them.
* **It's 100% end-to-end encrypted.** Unlike [Mastodon](https://joinmastodon.org/) or [Diaspora](https://diasporafoundation.org/), direct messages between users and within groups remain encrypted 1:1 end-to-end among users. Posts to the public are encrypted to @comrads, a special account which automatically re-encrypts its messages back to any key-registered requester of them.
* **It verifies identities.**Komrade's server, "The Operator", keeps a permanent record of one thing only: every komrade's name and public key, and requires that new komrades choose a unique name. Whenever you send or receive mail, the Operator will make sure that the name and public key on the letter matches what it has on file, verifying the identity of both parties.
* **It verifies identities.**Comrad's server, "The Operator", keeps a permanent record of one thing only: every comrad's name and public key, and requires that new comrads choose a unique name. Whenever you send or receive mail, the Operator will make sure that the name and public key on the letter matches what it has on file, verifying the identity of both parties.
* **It's (semi-)ephemeral.** Data, like all natural things, should not last forever. Direct messages auto-delete from the server as soon as they are downloaded. Group messages are sent as direct messages through the "web of trust" of the group membership network. Posts to the world auto-delete in however many days you specify. By contrast, data on both [SSB](https://scuttlebutt.nz/) and [Matrix](https://matrix.org/) is undeletable.
* **It's (semi-)ephemeral.** Data, like all natural things, should not last forever. Direct messages auto-delete from the server as soon as they are downloaded. Group messages are sent as direct messages through the "web of trust" of the group membership network. Posts to the world auto-delete in however many days you specify. By contrast, data on both [SSB](https://scuttlebutt.nz/) and [Matrix](https://matrix.org/) is undeletable.
* **It's easy to use.** No invitation or server is needed on startup, unlike [SSB](https://scuttlebutt.nz/), [Mastodon](https://joinmastodon.org/), [Diaspora](https://diasporafoundation.org/), or [Briar](https://briarproject.org/). It's basically a Twitter clone, but one where you can also post to a universal feed shared by the entire world (@komrades), so that you can make yourself known, participate in general discussions, find new contacts, and organize new groups.
* **It's easy to use.** No invitation or server is needed on startup, unlike [SSB](https://scuttlebutt.nz/), [Mastodon](https://joinmastodon.org/), [Diaspora](https://diasporafoundation.org/), or [Briar](https://briarproject.org/). It's basically a Twitter clone, but one where you can also post to a universal feed shared by the entire world (@comrads), so that you can make yourself known, participate in general discussions, find new contacts, and organize new groups.
@ -90,30 +90,30 @@ See ["Comparison of alternative social networks" on the wiki](https://github.com
<imgsrc="komrade/app/assets/komrade-terminal-preview--2020-09-20--tor.gif" alt="GIF animation of Tor connection"/>
<imgsrc="comrad/app/assets/comrad-terminal-preview--2020-09-20--tor.gif" alt="GIF animation of Tor connection"/>
#### "Meeting" (exchanging public keys)
#### "Meeting" (exchanging public keys)
<imgsrc="komrade/app/assets/komrade-terminal-preview--2020-09-16--meet.gif" alt="GIF animation of meeting process"/>
<imgsrc="comrad/app/assets/comrad-terminal-preview--2020-09-16--meet.gif" alt="GIF animation of meeting process"/>
#### Messaging
#### Messaging
<imgsrc="komrade/app/assets/komrade-terminal-preview--2020-09-16--msg.gif" alt="GIF animation of messaging"/>
<imgsrc="comrad/app/assets/comrad-terminal-preview--2020-09-16--msg.gif" alt="GIF animation of messaging"/>
### Posting
### Posting
<imgsrc="komrade/app/assets/komrade-terminal-preview--2020-09-19--posting.gif" alt="GIF animation of posting"/>
<imgsrc="comrad/app/assets/comrad-terminal-preview--2020-09-19--posting.gif" alt="GIF animation of posting"/>
## Usage
## Usage
@ -122,17 +122,17 @@ See ["Comparison of alternative social networks" on the wiki](https://github.com
#### ...on Mac OSX
#### ...on Mac OSX
Download and run [this installer](https://github.com/Komrade/Komrade/raw/master/script/InstallKomrade.app.zip).
Download and run [this installer](https://github.com/Comrad/Comrad/raw/master/script/InstallComrad.app.zip).
#### ...on Linux or Windows
#### ...on Linux or Windows
Open a terminal in Linux, or a [Cygwin shell](https://cygwin.com/install.html) in Windows, and copy and paste the following line into it:
Open a terminal in Linux, or a [Cygwin shell](https://cygwin.com/install.html) in Windows, and copy and paste the following line into it:
```
```
bash <(curl -s https://komrade.app/run)
bash <(curl -s https://comrad.app/run)
```
```
[That](https://komrade.app/run)'s a shortcut to [this auto-installer script](https://github.com/Komrade/Komrade/blob/master/script/install). It installs Komrade in a virtual Python environment in the folder "komrade" in your home directory.
[That](https://comrad.app/run)'s a shortcut to [this auto-installer script](https://github.com/Comrad/Comrad/blob/master/script/install). It installs Comrad in a virtual Python environment in the folder "comrad" in your home directory.
The mobile/desktop app is made with [KivyMD](https://github.com/kivymd/KivyMD), a variant of [Kivy](https://kivy.org/), a cross-platform app development framework in Python. Python is an easy and versatile progamming language to learn, which keeps the code accessible to as many people as possible. Code for the app is in [komrade/app](komrade/app).
The mobile/desktop app is made with [KivyMD](https://github.com/kivymd/KivyMD), a variant of [Kivy](https://kivy.org/), a cross-platform app development framework in Python. Python is an easy and versatile progamming language to learn, which keeps the code accessible to as many people as possible. Code for the app is in [comrad/app](comrad/app).
#### Terminal app
#### Terminal app
Vanilla Python. Code is in [komrade/cli](komrade/cli).
Vanilla Python. Code is in [comrad/cli](comrad/cli).
### Backend
### Backend
#### API
#### API
Plain old object-oriented code in Python. The root entity is a "Keymaker": anyone from @Telephone, to @Operator, to users, to groups, who has a public/private key pair. The database uses a simple file-based key-value store using the Redis protocol: [rlite](https://github.com/seppo0010/rlite), via its [rlite-py](https://github.com/seppo0010/rlite-py) Python bindings. All code for backend/API is in [komrade/backend](komrade/backend).
Plain old object-oriented code in Python. The root entity is a "Keymaker": anyone from @Telephone, to @Operator, to users, to groups, who has a public/private key pair. The database uses a simple file-based key-value store using the Redis protocol: [rlite](https://github.com/seppo0010/rlite), via its [rlite-py](https://github.com/seppo0010/rlite-py) Python bindings. All code for backend/API is in [comrad/backend](comrad/backend).
#### Cryptography
#### Cryptography
@ -229,9 +229,9 @@ We are using [Themis](https://github.com/cossacklabs/themis), a high-level cross
@ -259,31 +259,31 @@ class LoginScreen(BaseScreen):
return{'success':False,'status':'This is already a contact of yours'}
return{'success':False,'status':'This is already a contact of yours'}
#
#
awaitlogfunc(f'Hello, this is Komrade @{name}. I would like to join the socialist network.',pause=True,komrade_name=name)
awaitlogfunc(f'Hello, this is Comrad @{name}. I would like to join the socialist network.',pause=True,comrad_name=name)
awaitlogfunc(f'Welcome, Komrade @{name}. To help us communicate safely, I have cut for you a matching pair of encryption keys.',pause=True,clear=True,komrade_name='Keymaker')
awaitlogfunc(f'Welcome, Comrad @{name}. To help us communicate safely, I have cut for you a matching pair of encryption keys.',pause=True,clear=True,comrad_name='Keymaker')
# await logfunc(f'Here. I have cut for you a private and public asymmetric key pair, using the iron-clad Elliptic curve algorithm:',komrade_name='Keymaker')
# await logfunc(f'Here. I have cut for you a private and public asymmetric key pair, using the iron-clad Elliptic curve algorithm:',comrad_name='Keymaker')
awaitlogfunc(f'The first is your "public key", which you can share with anyone. With it, someone can write you an encrypted message.',komrade_name='Keymaker')
awaitlogfunc(f'The first is your "public key", which you can share with anyone. With it, someone can write you an encrypted message.',comrad_name='Keymaker')
# delete qr!
# delete qr!
os.remove(fnfn)
os.remove(fnfn)
# await logfunc(f'(1) {pubkey} -- and -- (2) {privkey}',clear=True,pause=True,komrade_name='Keymaker')
# await logfunc(f'(1) {pubkey} -- and -- (2) {privkey}',clear=True,pause=True,comrad_name='Keymaker')
# await logfunc(f'(1) You may store your public key both on your device hardware, as well as share it with anyone you wish: {pubkey.data_b64_s}') #\n\nIt will also be stored as a QR code on your device:\n{qr_str}',pause=True,clear=True)
# await logfunc(f'(1) You may store your public key both on your device hardware, as well as share it with anyone you wish: {pubkey.data_b64_s}') #\n\nIt will also be stored as a QR code on your device:\n{qr_str}',pause=True,clear=True)
@ -292,7 +292,7 @@ class LoginScreen(BaseScreen):
kommie._keychain['pubkey']=pubkey
kommie._keychain['pubkey']=pubkey
kommie._keychain['privkey']=privkey
kommie._keychain['privkey']=privkey
fromkomrade.utilsimportdict_format
fromcomrad.utilsimportdict_format
self.log('My keychain now looks like:'+dict_format(kommie.keychain()))
self.log('My keychain now looks like:'+dict_format(kommie.keychain()))
# return
# return
@ -313,22 +313,22 @@ class LoginScreen(BaseScreen):
# await logfunc(f'''We immediately whatever you typed through a 1-way hashing algorithm (SHA-256), scrambling it into (redacted):\n{make_key_discreet_str(passhash)}''',pause=True,clear=False)
# await logfunc(f'''We immediately whatever you typed through a 1-way hashing algorithm (SHA-256), scrambling it into (redacted):\n{make_key_discreet_str(passhash)}''',pause=True,clear=False)
self.log('My keychain now looks like v2:',dict_format(kommie.keychain()))
self.log('My keychain now looks like v2:',dict_format(kommie.keychain()))
# await logfunc(f'With this scrambled password we can encrypt your super-sensitive private key, from this:\n{privkey.discreet}to this:\n{privkey_encr_obj.discreet}',pause=True,clear=False)
# await logfunc(f'With this scrambled password we can encrypt your super-sensitive private key, from this:\n{privkey.discreet}to this:\n{privkey_encr_obj.discreet}',pause=True,clear=False)
# ### PUBLIC KEY
# ### PUBLIC KEY
awaitlogfunc('You must now register your username and public key with Komrade @Operator on the remote server.',pause=False,clear=False)
awaitlogfunc('You must now register your username and public key with Comrad @Operator on the remote server.',pause=False,clear=False)
awaitlogfunc('Connecting you to the @Operator...',komrade_name='Telephone')
awaitlogfunc('Connecting you to the @Operator...',comrad_name='Telephone')
## CALL OP WITH PUBKEY
## CALL OP WITH PUBKEY
# self.app.open_dialog('Calling @Operator...')
# self.app.open_dialog('Calling @Operator...')
@ -346,10 +346,10 @@ class LoginScreen(BaseScreen):
# await logfunc(f'Saving public key, encrypted private key, and login secret to hardware-only database. Also saving public key as QR code to: {_fnfn}.',pause=True,clear=False,use_prefix=False)
# await logfunc(f'Saving public key, encrypted private key, and login secret to hardware-only database. Also saving public key as QR code to: {_fnfn}.',pause=True,clear=False,use_prefix=False)
awaitlogfunc(f'You can share it by pasting it to someone in a secure message:\n{uri_s}',komrade_name='Keymaker')
awaitlogfunc(f'You can share it by pasting it to someone in a secure message:\n{uri_s}',comrad_name='Keymaker')
awaitlogfunc(f'You can also share it IRL, phone to phone, as a QR code. It is saved to {fnfn} and looks like this.',img_src=fnfn,komrade_name='Keymaker')
awaitlogfunc(f'You can also share it IRL, phone to phone, as a QR code. It is saved to {fnfn} and looks like this.',img_src=fnfn,comrad_name='Keymaker')
awaitlogfunc(f"(2) Your PRIVATE encryption key, on the other hand, will be stored encrypted on your device hardware. Do not it this with anyone or across any network whatsoever.")
awaitlogfunc(f"(2) Your PRIVATE encryption key, on the other hand, will be stored encrypted on your device hardware. Do not it this with anyone or across any network whatsoever.")
logfunc(f'I have cut for you a private and public asymmetric key pair, using the iron-clad Elliptic curve algorithm:\n\n(1) {pubkey}\n\n(2) {privkey}{ART_KEY_PAIR}',clear=True,pause=True)
logfunc(f'I have cut for you a private and public asymmetric key pair, using the iron-clad Elliptic curve algorithm:\n\n(1) {pubkey}\n\n(2) {privkey}{ART_KEY_PAIR}',clear=True,pause=True)
self._keychain['pubkey']=pubkey
self._keychain['pubkey']=pubkey
@ -168,14 +168,14 @@ class KomradeX(Caller):
### PUBLIC KEY
### PUBLIC KEY
qr_str=self.qr_str(pubkey.data_b64)
qr_str=self.qr_str(pubkey.data_b64)
logfunc(f'(1) You may store your public key both on your device hardware, as well as share it with anyone you wish:\n\n{pubkey.data_b64_s}\n\nIt will also be stored as a QR code on your device:\n{qr_str}',pause=True,clear=True)
logfunc(f'(1) You may store your public key both on your device hardware, as well as share it with anyone you wish:\n\n{pubkey.data_b64_s}\n\nIt will also be stored as a QR code on your device:\n{qr_str}',pause=True,clear=True)
logfunc('You must also register your username and public key with Komrade @Operator on the remote server.\n\nShall Komrade @Telephone send them over?',pause=False,clear=False)#),dict_format(data,tab=2),pause=True)
logfunc('You must also register your username and public key with Comrad @Operator on the remote server.\n\nShall Comrad @Telephone send them over?',pause=False,clear=False)#),dict_format(data,tab=2),pause=True)
ok_to_send='y'#input(f'\n@{name}: [Y/n] ')
ok_to_send='y'#input(f'\n@{name}: [Y/n] ')
ifok_to_send.strip().lower()=='n':
ifok_to_send.strip().lower()=='n':
logfunc('Cancelling registration.')
logfunc('Cancelling registration.')
return
return
else:
else:
print()
print()
logfunc('Connecting you to the @Operator...',komrade_name='Telephone')
logfunc('Connecting you to the @Operator...',comrad_name='Telephone')
logfunc(f'''Let's immediately run whatever you typed through a 1-way hashing algorithm (SHA-256), inflating it to (redacted):\n\n{make_key_discreet_str(passhash)}''',pause=True,clear=False)
logfunc(f'''Let's immediately run whatever you typed through a 1-way hashing algorithm (SHA-256), inflating it to (redacted):\n\n{make_key_discreet_str(passhash)}''',pause=True,clear=False)