2017-12-26 07:25:29 +00:00
#!/usr/bin/env python3
'''
2018-01-26 07:22:48 +00:00
Onionr - P2P Microblogging Platform & Social network .
2018-01-14 00:07:13 +00:00
Onionr is the name for both the protocol and the original / reference software .
Run with ' help ' for usage .
'''
'''
2017-12-26 07:25:29 +00:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < https : / / www . gnu . org / licenses / > .
'''
2018-01-26 07:22:48 +00:00
import sys , os , configparser , base64 , random , getpass , shutil , subprocess , requests , time , logger
import gui , api , core
2018-01-09 22:58:12 +00:00
from onionrutils import OnionrUtils
2018-01-19 09:16:38 +00:00
from netcontroller import NetController
2017-12-28 19:30:15 +00:00
2018-01-28 01:53:24 +00:00
try :
from urllib3 . contrib . socks import SOCKSProxyManager
except ImportError :
raise Exception ( " You need the PySocks module (for use with socks5 proxy to use Tor) " )
2017-12-26 07:25:29 +00:00
class Onionr :
def __init__ ( self ) :
2018-01-14 00:07:13 +00:00
''' Main Onionr class. This is for the CLI program, and does not handle much of the logic.
In general , external programs and plugins should not use this class .
'''
2018-01-15 08:52:45 +00:00
try :
os . chdir ( sys . path [ 0 ] )
except FileNotFoundError :
pass
2018-01-10 03:50:38 +00:00
if os . path . exists ( ' dev-enabled ' ) :
self . _developmentMode = True
2018-01-26 07:22:48 +00:00
logger . set_level ( logger . LEVEL_DEBUG )
logger . warn ( ' DEVELOPMENT MODE ENABLED (THIS IS LESS SECURE!) ' )
2018-01-10 03:50:38 +00:00
else :
self . _developmentMode = False
2018-01-26 07:22:48 +00:00
logger . set_level ( logger . LEVEL_INFO )
2017-12-27 01:13:19 +00:00
2018-01-14 08:48:23 +00:00
self . onionrCore = core . Core ( )
2018-01-26 06:28:11 +00:00
self . onionrUtils = OnionrUtils ( self . onionrCore )
2018-01-09 22:58:12 +00:00
2017-12-27 05:00:02 +00:00
# Get configuration and Handle commands
2018-01-26 07:22:48 +00:00
2018-01-02 08:43:29 +00:00
self . debug = False # Whole application debugging
2017-12-27 01:13:19 +00:00
2018-01-09 22:58:12 +00:00
if os . path . exists ( ' data-encrypted.dat ' ) :
while True :
print ( ' Enter password to decrypt: ' )
password = getpass . getpass ( )
2018-01-14 08:48:23 +00:00
result = self . onionrCore . dataDirDecrypt ( password )
2018-01-09 22:58:12 +00:00
if os . path . exists ( ' data/ ' ) :
break
else :
2018-01-26 07:22:48 +00:00
logger . error ( ' Failed to decrypt: ' + result [ 1 ] )
2018-01-09 22:58:12 +00:00
else :
2018-01-10 03:50:38 +00:00
if not os . path . exists ( ' data/ ' ) :
os . mkdir ( ' data/ ' )
2018-01-26 06:28:11 +00:00
os . mkdir ( ' data/blocks/ ' )
2018-01-26 07:22:48 +00:00
2018-01-10 08:40:25 +00:00
if not os . path . exists ( ' data/peers.db ' ) :
2018-01-14 08:48:23 +00:00
self . onionrCore . createPeerDB ( )
2018-01-10 03:50:38 +00:00
pass
2017-12-28 00:18:00 +00:00
2017-12-27 05:00:02 +00:00
# Get configuration
2017-12-27 01:13:19 +00:00
self . config = configparser . ConfigParser ( )
if os . path . exists ( ' data/config.ini ' ) :
self . config . read ( ' data/config.ini ' )
else :
2017-12-27 05:00:02 +00:00
# Generate default config
2017-12-27 01:13:19 +00:00
# Hostname should only be set if different from 127.x.x.x. Important for DNS rebinding attack prevention.
2017-12-28 00:18:00 +00:00
if self . debug :
2017-12-27 01:13:19 +00:00
randomPort = 8080
else :
2018-01-20 07:23:09 +00:00
while True :
randomPort = random . randint ( 1024 , 65535 )
if self . onionrUtils . checkPort ( randomPort ) :
break
2018-01-05 09:16:21 +00:00
self . config [ ' CLIENT ' ] = { ' CLIENT HMAC ' : base64 . b64encode ( os . urandom ( 32 ) ) . decode ( ' utf-8 ' ) , ' PORT ' : randomPort , ' API VERSION ' : ' 0.0.0 ' }
2017-12-27 01:13:19 +00:00
with open ( ' data/config.ini ' , ' w ' ) as configfile :
self . config . write ( configfile )
2017-12-26 07:25:29 +00:00
command = ' '
try :
command = sys . argv [ 1 ] . lower ( )
except IndexError :
2017-12-26 09:42:17 +00:00
command = ' '
2017-12-28 19:30:15 +00:00
finally :
2017-12-26 07:25:29 +00:00
if command == ' start ' :
2018-01-14 08:48:23 +00:00
if os . path . exists ( ' .onionr-lock ' ) :
2018-01-26 07:22:48 +00:00
logger . fatal ( ' Cannot start. Daemon is already running, or it did not exit cleanly. \n (if you are sure that there is not a daemon running, delete .onionr-lock & try again). ' )
2018-01-14 08:48:23 +00:00
else :
if not self . debug and not self . _developmentMode :
lockFile = open ( ' .onionr-lock ' , ' w ' )
lockFile . write ( ' ' )
lockFile . close ( )
self . daemon ( )
if not self . debug and not self . _developmentMode :
os . remove ( ' .onionr-lock ' )
2017-12-26 07:25:29 +00:00
elif command == ' stop ' :
self . killDaemon ( )
2018-01-28 01:53:24 +00:00
elif command in ( ' addmsg ' , ' addmessage ' ) :
while True :
messageToAdd = input ( ' Broadcast message to network: ' )
if len ( messageToAdd ) > = 1 :
break
2018-01-28 02:18:38 +00:00
addedHash = self . onionrCore . setData ( messageToAdd )
self . onionrCore . addToBlockDB ( addedHash , selfInsert = True )
2017-12-26 07:25:29 +00:00
elif command == ' stats ' :
self . showStats ( )
elif command == ' help ' or command == ' --help ' :
self . showHelp ( )
2017-12-28 19:42:37 +00:00
elif command == ' ' :
2018-01-26 07:22:48 +00:00
logger . info ( ' Do ' + logger . colors . bold + sys . argv [ 0 ] + ' --help ' + logger . colors . reset + logger . colors . fg . green + ' for Onionr help. ' )
2017-12-26 09:42:17 +00:00
else :
2018-01-26 07:22:48 +00:00
logger . error ( ' Invalid command. ' )
2018-01-10 03:50:38 +00:00
if not self . _developmentMode :
2018-01-26 07:22:48 +00:00
encryptionPassword = self . onionrUtils . getPassword ( ' Enter password to encrypt directory: ' )
2018-01-14 08:48:23 +00:00
self . onionrCore . dataDirEncrypt ( encryptionPassword )
2018-01-10 03:50:38 +00:00
shutil . rmtree ( ' data/ ' )
2017-12-26 07:25:29 +00:00
return
def daemon ( self ) :
2018-01-14 04:30:10 +00:00
''' Start the Onionr communication daemon
'''
2018-01-13 09:03:51 +00:00
if not os . environ . get ( " WERKZEUG_RUN_MAIN " ) == " true " :
2018-01-19 21:28:34 +00:00
net = NetController ( self . config [ ' CLIENT ' ] [ ' PORT ' ] )
2018-01-26 07:22:48 +00:00
logger . info ( ' Tor is starting... ' )
2018-01-28 01:53:24 +00:00
if not net . startTor ( ) :
sys . exit ( 1 )
2018-01-26 07:22:48 +00:00
logger . info ( ' Started Tor .onion service: ' + logger . colors . underline + net . myID )
2018-01-19 21:28:34 +00:00
time . sleep ( 1 )
2018-01-26 06:28:11 +00:00
subprocess . Popen ( [ " ./communicator.py " , " run " , str ( net . socksPort ) ] )
2018-01-26 07:22:48 +00:00
logger . debug ( ' Started communicator ' )
2017-12-27 01:13:19 +00:00
api . API ( self . config , self . debug )
2017-12-26 07:25:29 +00:00
return
def killDaemon ( self ) :
2018-01-14 08:48:23 +00:00
''' Shutdown the Onionr Daemon '''
2018-01-26 07:22:48 +00:00
logger . warn ( ' Killing the running daemon ' )
2018-01-27 08:43:36 +00:00
net = NetController ( self . config [ ' CLIENT ' ] [ ' PORT ' ] )
2018-01-14 08:48:23 +00:00
try :
self . onionrUtils . localCommand ( ' shutdown ' )
except requests . exceptions . ConnectionError :
pass
2018-01-27 01:24:38 +00:00
self . onionrCore . daemonQueueAdd ( ' shutdown ' )
2018-01-27 08:43:36 +00:00
net . killTor ( )
2017-12-26 07:25:29 +00:00
return
def showStats ( self ) :
2018-01-14 08:48:23 +00:00
''' Display statistics and exit '''
2017-12-26 07:25:29 +00:00
return
def showHelp ( self ) :
2018-01-14 08:48:23 +00:00
''' Show help for Onionr '''
2017-12-26 07:25:29 +00:00
return
2018-01-28 01:53:24 +00:00
Onionr ( )