Download custom client installer via Python

A Python 3 script to create a new client on the server and to download and execute a custom client installer. The current version works with UrBackup 2.x:

import http.client as http
import json
from urllib.parse import urlparse
from urllib.parse import urlencode
from base64 import b64encode
import hashlib
import socket
import shutil
import os
import binascii
 
#############################
# Settings. Please edit.
#############################
 
#Your server URL. Do not forget the 'x' at the end
server_url = 'http://example.com:55414/x'
 
 
#If you have basic authentication via .htpasswd
server_basic_username = ''
server_basic_password = ''
 
 
# Login user needs following rights
#   "status": "some"
#   "add_client": "all"
# Optionally, to be able to 
# install existing clients:
#   "settings": "all"
server_username='adduser'
server_password='foo'
 
 
#############################
# Global script variables.
# Please do not modify.
# Only modify something after this line
# if you know what you are doing
#############################
 
session=""
 
def get_response(action, params, method):
    global server_url;
    global server_basic_username;
    global server_basic_password;
    global session;
     
    headers = {
        'Accept': 'application/json',
        'Content-Type': 'application/json; charset=UTF-8'
    }
     
    if('server_basic_username' in globals() and len(server_basic_username)>0):
        userAndPass = b64encode(str.encode(server_basic_username+":"+server_basic_password)).decode("ascii")
        headers['Authorization'] = 'Basic %s' %  userAndPass
     
    curr_server_url=server_url+"?"+urlencode({"a": action});
     
    if(len(session)>0):
        params["ses"]=session
     
    if method=='GET':
        curr_server_url+="&"+urlencode(params);
     
    target = urlparse(curr_server_url)
    
    if not method:
        method = 'GET'
        
    if method=='POST':
        body = urlencode(params)
    else:
        body = ''
     
    if(target.scheme=='http'):
        h = http.HTTPConnection(target.hostname, target.port)
    elif(target.scheme=='https'):
        h = http.HTTPSConnection(target.hostname, target.port)
    else:
        print('Unkown scheme: '+target.scheme)
        raise Exception("Unkown scheme: "+target.scheme)
     
    h.request(
            method,
            target.path+"?"+target.query,
            body,
            headers)
     
    return h.getresponse();
 
def get_json(action, params = {}):
     
    response = get_response(action, params, "POST")
     
    if(response.status != 200):
        return ""
     
    data = response.read();
     
    response.close()
         
    return json.loads(data.decode("utf-8"))
 
def download_file(action, outputfn, params):
     
    response = get_response(action, params, "GET");
     
    if(response.status!=200):
        return False
     
    with open(outputfn, 'wb') as outputf:
        shutil.copyfileobj(response, outputf)
    
    if os.path.getsize(outputfn)<10*1024:
        return False
    
    return True       
 
def md5(s):
    return hashlib.md5(s.encode()).hexdigest()
 
 
print("Logging in...")
 
salt = get_json("salt", {"username": server_username})
 
if( not ('ses' in salt) ):
    print('Username does not exist')
    exit(1)
     
session = salt["ses"];
     
if( 'salt' in salt ):
    password_md5_bin = hashlib.md5((salt["salt"]+server_password).encode()).digest()
    password_md5 = binascii.hexlify(password_md5_bin).decode()
    
    if "pbkdf2_rounds" in salt:
        pbkdf2_rounds = int(salt["pbkdf2_rounds"])
        if pbkdf2_rounds>0:
            password_md5 = binascii.hexlify(hashlib.pbkdf2_hmac('sha256', password_md5_bin, 
                                               salt["salt"].encode(), pbkdf2_rounds)).decode()
    
    password_md5 = md5(salt["rnd"]+password_md5)
     
    login = get_json("login", { "username": server_username,
                                "password": password_md5 })
     
    if('success' not in login or not login['success']):
        print('Error during login. Password wrong?')
        exit(1)
        
    clientname = socket.gethostname()
         
    print("Creating client "+clientname+"...")
         
    new_client = get_json("add_client", { "clientname": clientname})
    
    if "already_exists" in new_client:
        print("Client already exists")
        
        status = get_json("status")
        
        if "client_downloads" in status:
            for client in status["client_downloads"]:         
                if (client["name"] == clientname):
                    print("Downloading Installer...")
                    
                    if not download_file("download_client", "Client Installer.exe",
                                 {"clientid": client["id"] }):
                        print("Downloading client failed")
                        exit(1)
        else:        
            print("Client already exists and login user has probably no right to access existing clients")
            exit(2) 
    else:
        if not "new_authkey" in new_client:
            print("Error creating new client")
            exit(3)
            
        print("Downloading Installer...")
                 
        if not download_file("download_client", "Client Installer.exe",
                             {"clientid": new_client["new_clientid"],
                              "authkey": new_client["new_authkey"]
                              }):
             
            print("Downloading client failed")
            exit(1)
         
    print("Sucessfully downloaded client")
    os.startfile("Client Installer.exe")
    exit(0)


Use e.g. http://cx-freeze.sourceforge.net/ to create an executable, if you need to.