Commit 81208c1f authored by Pascal Engélibert's avatar Pascal Engélibert 🚴

Initial commit

parents
peers
default.ini
This diff is collapsed.
#!/usr/bin/env python3
"""
This file is part of ĞMix.
ĞMix is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ĞMix 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with ĞMix. If not, see <https://www.gnu.org/licenses/>.
"""
import sys, os, socket, re, configparser, json, asyncio, getpass
import duniterpy.api.bma as bma
from duniterpy.api.client import Client
from duniterpy.key import SigningKey
from threading import Thread
VERSION = "0.1.0"
AUTHORS = ["Pascal Engélibert <tuxmain@zettascript.org>"]
CONF_PATH = "default.ini"
PEERS_PATH = "peers"
HOST = socket.gethostname()
PORT = "10951"
BMA_URL = "g1.duniter.fr"
BMA_PORT = "443"
ID_SALT = "" # if empty, will be asked at runtime
ID_PSW = "" # if empty, will be asked at runtime
RECBUF = 1024
def getargv(arg, default="", n=1):
if arg in sys.argv and len(sys.argv) > sys.argv.index(arg)+n:
return sys.argv[sys.argv.index(arg)+n]
else:
return default
class Peer:
def __init__(self, pubkey, host, port):
self.pubkey = pubkey
self.host = host
self.port = port
def __str__(self):
return self.pubkey + " " + self.host + " " + self.port
# Read ini config file
def readConfig(conf_path):
if not os.path.isfile(conf_path):
open(CONF_PATH, "w").close()
conf = configparser.ConfigParser()
conf.read(conf_path)
if not "Config" in conf:
conf["Config"] = {}
if not "PeersFile" in conf["Config"]:
conf["Config"]["PeersFile"] = PEERS_PATH
if not "Host" in conf["Config"]:
conf["Config"]["Host"] = HOST
if not "Port" in conf["Config"]:
conf["Config"]["Port"] = PORT
if not "BMA_URL" in conf["Config"]:
conf["Config"]["BMA_URL"] = BMA_URL
if not "BMA_Port" in conf["Config"]:
conf["Config"]["BMA_Port"] = BMA_PORT
if not "ID_Salt" in conf["Config"]:
conf["Config"]["ID_Salt"] = ID_SALT
if not "ID_Password" in conf["Config"]:
conf["Config"]["ID_Password"] = ID_PSW
with open(CONF_PATH, "w") as configfile:
conf.write(configfile)
return conf
# Read peers list
def readPeers(peers_path):
if not os.path.isfile(peers_path):
open(peers_path, "w").close()
peers = []
peers_index = {}
peersfile = open(peers_path, "r")
while True:
line = peersfile.readline()
if len(line) <= 1:
break
else:
cols = line.replace("\n", "").split(" ")
peer = Peer(cols[0], cols[1], cols[2])
peers.append(peer)
peers_index[peer.pubkey] = peer
peersfile.close()
return peers, peers_index
# Save peers list
def writePeers(peers_path, peers):
peersfile = open(peers_path, "w")
for peer in peers:
peersfile.write(str(peer)+"\n")
peersfile.close()
class ServerThread(Thread):
def __init__(self, conf, peers, peers_index, keys):
Thread.__init__(self)
self.conf = conf
self.peers = peers
self.peers_index = peers_index
self.keys = keys
self.sock = None
self.work = True
def run(self):
p_clen = re.compile("\r?\ncontent-length: *(\d)+\r?\n", re.IGNORECASE)
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind((self.conf["Host"], int(self.conf["Port"])))
self.sock.listen(1)
while self.work:
client, addr = self.sock.accept()
# Get request
paquet = b""
header = b""
content = b""
content_len = 0
resp = {}
lf = 0
while True:
raw = client.recv(RECBUF)
if raw:
paquet += raw
if lf >= 0:
for c in raw:
if c == 10:# LF
lf += 1
elif c != 13:# CR
lf = 0
if lf > 1:
parts = paquet.split(b"\r\n\r\n")
header = parts[0]
content = parts[1]
try:
content_len = int(p_clen.search(header.decode()).group(1))
except AttributeError:
content_len = 0
break
if lf > 1:
break
else:
break
while len(content) < content_len:
raw = client.recv(RECBUF)
paquet += raw
content += raw
# Parse request
httpreq = paquet.decode().split("\n")
url = httpreq[0].split(" ")[1].split("/")
while "" in url:
url.remove("")
urll = len(url)
resp = {}
if urll > 0:
if url[0] == "pubkey":
resp["pubkey"] = self.keys.pubkey
content_raw = json.dumps(resp).encode()
client.sendall(b"HTTP/2.0 200 OK\r\nContent-type: text/json; charset=UTF-8\r\nContent-length: "+str(len(content_raw)).encode()+b"\r\n\r\n"+content_raw)
client.close()
self.sock.close()
def stop(self):
self.work = False
self.sock.shutdown(socket.SHUT_WR)
class ClientThread(Thread):
def __init__(self, conf, peers, peers_index, keys):
Thread.__init__(self)
self.conf = conf
self.peers = peers
self.peers_index = peers_index
self.keys = keys
self.bma_endpoint = "BMAS "+conf["BMA_URL"]+" "+conf["BMA_Port"]
self.work = True
def run(self):
#asyncio.get_event_loop().run_until_complete(self.startClient())
asyncio.run(self.startClient())
async def startClient(self):
client = Client(self.bma_endpoint)
while self.work:
break
await client.close()
# Main function
def main():
# Load conf & peers
conf = readConfig(CONF_PATH)["Config"]
peers, peers_index = readPeers(conf["PeersFile"])
# Get private key
salt = conf["ID_Salt"]
if salt == "":
salt = getpass.getpass("Enter your passphrase (salt): ")
password = conf["ID_Password"]
if password == "":
password = getpass.getpass("Enter your password: ")
keys = SigningKey.from_credentials(salt, password)
# Start threads
clientThread = ClientThread(conf, peers, peers_index, keys)
serverThread = ServerThread(conf, peers, peers_index, keys)
clientThread.start()
serverThread.start()
# Wait
input()
# Stop threads
serverThread.stop()
serverThread.join()
clientThread.work = False
clientThread.join()
# Save peers
writePeers(conf["PeersFile"], peers)
if __name__ == "__main__":
CONF_PATH = getargv("-c", os.path.expanduser(CONF_PATH))
if "-s" in sys.argv:
main()
elif "-v" in sys.argv:
print(VERSION)
elif "--help" in sys.argv:
print("\
ĞMix Server "+VERSION+"\n\
\n\
Options:\n\
-c <path> Change config file path\n\
default: default.ini\n\
-s Start server\n\
-v Display version\n\
")
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment