diff --git a/.gitignore b/.gitignore index 9dd40bc..ae6e504 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ Python/venv Python/dist Python/buildc Python/lonadb_client.egg-info -token \ No newline at end of file +Python/token \ No newline at end of file diff --git a/JavaScript/Client.js b/JavaScript/Client.js index 272c2d8..302d9cf 100644 --- a/JavaScript/Client.js +++ b/JavaScript/Client.js @@ -2,6 +2,7 @@ const crypto = require('crypto'); class LonaDB { constructor(host, port, name, password) { + //Import all connection details this.host = host; this.port = port; this.name = name; @@ -12,21 +13,21 @@ class LonaDB { let result = ''; const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz'; let counter = 0; - + //Add random characters to result until it has reached the desired length while (counter < length) { result += characters[Math.floor(Math.random() * characters.length)]; counter += 1; } - return result; } sendRequest = async function(action, data) { let net = require('net'); + //Generate ProcessID let processID = this.makeid(5); - + //Generate encryptionKey for encrypting passwords let encryptionKey = crypto.createHash('sha256').update(processID).digest('base64'); - + //Check if we need to encrypt something other than our own password switch(action){ case "create_user": data.user.password = await this.encryptPassword(data.user.password, encryptionKey); @@ -35,9 +36,9 @@ class LonaDB { data.checkPass.pass = await this.encryptPassword(data.checkPass.pass, encryptionKey); break; } - + //Encrypt password let encryptedPassword = await this.encryptPassword(this.password, encryptionKey); - + //Generate request let request = JSON.stringify({ action, login: { @@ -49,19 +50,21 @@ class LonaDB { }); return new Promise((resolve, reject) => { + //Create socket let socket = net.createConnection({ host: this.host, port: this.port }, () => { + //Send request socket.write(request); }); let response = ''; - + //When server sends data, collect it socket.on('data', (chunk) => { response += chunk; }); - + //Once the server closes the connection, return the data socket.on('end', () => { resolve(JSON.parse(response)); }); @@ -73,23 +76,26 @@ class LonaDB { } encryptPassword(password, key) { + //Generate IV and create cipher const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key, 'base64'), iv); - + //Encrypt let encrypted = cipher.update(password); encrypted = Buffer.concat([encrypted, cipher.final()]); - + //Return IV and encrypted value return iv.toString('hex') + ':' + encrypted.toString('hex'); } + //All other functions work the same createFunction(name, content) { + //Generate request to send const data = { "function": { "name": name, "content": content } }; - + //Send request to the database and return the response return this.sendRequest("add_function", data); } diff --git a/JavaScript/package.json b/JavaScript/package.json index 6f3f739..9b38a4d 100644 --- a/JavaScript/package.json +++ b/JavaScript/package.json @@ -1,14 +1,14 @@ { "name": "lonadb-client", - "version": "4.5.2", - "description": "A client for the LonaDB Prototype", + "version": "4.5.3", + "description": "JavaScript client for LonaDB", "main": "Client.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", - "url": "https://github.com/LonaDB/JavaScript-Client" + "url": "https://git.lona-development.org/Lona-Development/Clients" }, "keywords": [ "database", @@ -17,7 +17,7 @@ "variable", "variables" ], - "author": "Collin Buchkamer", + "author": "Lona-Development", "license": "AGPL-3.0", "dependencies": { "net": "^1.0.2" diff --git a/PHP/Client.php b/PHP/Client.php index 46fae86..c5bac9e 100644 --- a/PHP/Client.php +++ b/PHP/Client.php @@ -1,12 +1,14 @@ host = $host; $this->port = $port; $this->name = $name; @@ -17,40 +19,38 @@ class LonaDB { $result = ""; $characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz"; $counter = 0; - + //Add random characters from $characters to $result until it has reached the dired lenght while ($counter < $length) { $result .= $characters[mt_rand(0, strlen($characters) - 1)]; $counter += 1; } - return $result; } private function encryptPassword($password, $key) { + //Hash our encryption key (ProcessID) $keyBuffer = hash('sha256', $key, true); - + //Generate IV $iv = openssl_random_pseudo_bytes(16); - + //Encrypt $encrypted = openssl_encrypt($password, 'aes-256-cbc', $keyBuffer, OPENSSL_RAW_DATA, $iv); - + //Add the IV to the encrypted value $encryptedString = bin2hex($iv) . ':' . bin2hex($encrypted); - return $encryptedString; } private function sendRequest($action, $data) { + //Create socket $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); - if ($socket === false) { - return ["err" => socket_strerror(socket_last_error())]; - } - + //Check if socket was created successfully + if (!$socket) return ["err" => socket_strerror(socket_last_error())]; + //Try connecting to the database $result = socket_connect($socket, $this->host, $this->port); - if ($result === false) { - return ["err" => socket_strerror(socket_last_error($socket))]; - } - + //Check if connection was successfull + if (!$result) return ["err" => socket_strerror(socket_last_error($socket))]; + //Generate ProcessID $processID = $this->makeid(5); - + //Check if we need to encrypt something other than our own password switch($action){ case "create_user": $data['user']['password'] = $this->encryptPassword($data['user']['password'], $processID); @@ -59,9 +59,9 @@ class LonaDB { $data['checkPass']['pass'] = $this->encryptPassword($data['checkPass']['pass'], $processID); break; } - + //Encrypt password $encryptedPassword = $this->encryptPassword($this->password, $processID); - + //Generate request array $request = json_encode([ "action" => $action, "login" => [ @@ -70,23 +70,26 @@ class LonaDB { ], "process" => $processID ] + $data); - + //Send request to database socket_write($socket, $request, strlen($request)); - + //Read response form database $response = socket_read($socket, 2048); + //Close socket socket_close($socket); - + //Give back the response return json_decode($response, true); } - + + //All other functions work the same public function createFunction($name, $content) { + //Generate request to send to the database $data = [ "function" => [ "name" => $name, "content" => $content ] ]; - + //Send request to the database and return the response return $this->sendRequest("add_function", $data); } diff --git a/Python/build/lib/lonadb_client/lonadb_client.py b/Python/build/lib/lonadb_client/lonadb_client.py index 0ffdae2..8d3e6ac 100644 --- a/Python/build/lib/lonadb_client/lonadb_client.py +++ b/Python/build/lib/lonadb_client/lonadb_client.py @@ -1,43 +1,71 @@ import json import socket +import random +import hashlib +from Crypto.Cipher import AES +from Crypto.Random import get_random_bytes class LonaDB: def __init__(self, host, port, name, password): + #Import all connection details self.host = host self.port = port self.name = name self.password = password def make_id(self, length): - import random - import string - return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(length)) + characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz' + #Generate random string of desired lenght + return ''.join(random.choice(characters) for _ in range(length)) - def send_request(self, action, data): + async def send_request(self, action, data): + #Generate ProcessID process_id = self.make_id(5) + #Generate encryption key for passwords + encryption_key = hashlib.sha256(process_id.encode()).digest().hex() + #Check if we have to encrypt something else + if action == "create_user": + data["user"]["password"] = await self.encrypt_password(data["user"]["password"], encryption_key) + elif action == "check_password": + data["checkPass"]["pass"] = await self.encrypt_password(data["checkPass"]["pass"], encryption_key) + #Encrypt password + encrypted_password = await self.encrypt_password(self.password, encryption_key) + #Generate request request = json.dumps({ - 'action': action, - 'login': { - 'name': self.name, - 'password': self.password + "action": action, + "login": { + "name": self.name, + "password": encrypted_password }, - 'process': process_id, + "process": process_id, **data }) - - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.connect((self.host, self.port)) + #Send request + with socket.create_connection((self.host, self.port)) as s: s.sendall(request.encode()) - response = s.recv(4096).decode() + response = s.recv(1024).decode() + #Return response return json.loads(response) + async def encrypt_password(self, password, key): + #Generate IV and cipher + iv = get_random_bytes(16) + cipher = AES.new(key.encode(), AES.MODE_CBC, iv) + #Encrypt + encrypted = cipher.encrypt(password.encode()) + #Return IV and encrypted value + return iv.hex() + ':' + encrypted.hex() + + #All other functions work the same def create_function(self, name, content): + #Generate request to send to the database data = { 'function': { 'name': name, 'content': content } } + #Send request to the database and return the response return self.send_request('add_function', data) def execute_function(self, name): @@ -143,4 +171,4 @@ class LonaDB: def eval(self, func): data = {'function': func} - return self.send_request('eval', data) \ No newline at end of file + return self.send_request('eval', data) diff --git a/Python/lonadb_client/lonadb_client.py b/Python/lonadb_client/lonadb_client.py index c47a61e..8d3e6ac 100644 --- a/Python/lonadb_client/lonadb_client.py +++ b/Python/lonadb_client/lonadb_client.py @@ -7,6 +7,7 @@ from Crypto.Random import get_random_bytes class LonaDB: def __init__(self, host, port, name, password): + #Import all connection details self.host = host self.port = port self.name = name @@ -14,19 +15,22 @@ class LonaDB: def make_id(self, length): characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz' + #Generate random string of desired lenght return ''.join(random.choice(characters) for _ in range(length)) async def send_request(self, action, data): + #Generate ProcessID process_id = self.make_id(5) + #Generate encryption key for passwords encryption_key = hashlib.sha256(process_id.encode()).digest().hex() - + #Check if we have to encrypt something else if action == "create_user": data["user"]["password"] = await self.encrypt_password(data["user"]["password"], encryption_key) elif action == "check_password": data["checkPass"]["pass"] = await self.encrypt_password(data["checkPass"]["pass"], encryption_key) - + #Encrypt password encrypted_password = await self.encrypt_password(self.password, encryption_key) - + #Generate request request = json.dumps({ "action": action, "login": { @@ -36,25 +40,32 @@ class LonaDB: "process": process_id, **data }) - + #Send request with socket.create_connection((self.host, self.port)) as s: s.sendall(request.encode()) response = s.recv(1024).decode() + #Return response return json.loads(response) async def encrypt_password(self, password, key): + #Generate IV and cipher iv = get_random_bytes(16) cipher = AES.new(key.encode(), AES.MODE_CBC, iv) + #Encrypt encrypted = cipher.encrypt(password.encode()) + #Return IV and encrypted value return iv.hex() + ':' + encrypted.hex() + #All other functions work the same def create_function(self, name, content): + #Generate request to send to the database data = { 'function': { 'name': name, 'content': content } } + #Send request to the database and return the response return self.send_request('add_function', data) def execute_function(self, name): diff --git a/Python/publish.sh b/Python/publish.sh new file mode 100755 index 0000000..3b25a3c --- /dev/null +++ b/Python/publish.sh @@ -0,0 +1,2 @@ +./venv/bin/python setup.py sdist bdist_wheel +./venv/bin/twine upload --username __token__ --password "$(cat ./token)" dist/* \ No newline at end of file diff --git a/Python/setup.py b/Python/setup.py index 7aac52f..bd1cea8 100644 --- a/Python/setup.py +++ b/Python/setup.py @@ -6,11 +6,11 @@ long_description = (this_directory / "README.md").read_text() setup( name="lonadb-client", - version="2.2", - author="Collin Buchkamer", + version="2.3", + author="Lona-Development", author_email="collin@lona-development.org", description="A client library for interacting with LonaDB server", - url="https://github.com/LonaDB/Clients", + url="https://git.lona-development.org/Lona-Development/Clients", packages=["lonadb_client"], long_description=long_description, long_description_content_type='text/markdown',