HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Basic web app that returns a JSON of information

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
appthatreturnswebjsonbasicinformation

Problem

My web application can take URL-encoded strings and return a JSON that contains information, like API calls.

My main concerns are with security. I need a cheap and easy (but secure) way to do certain commands. This part is handled by the adminhandle section of the code. My code is currently designed to be able to be deployed on a heroku app, but simply changing:

port = int(os.environ.get('PORT', 17995))


at line 12 to:

port = 80


should be fine, allowing you to access this server from http://localhost. Inside the code itself contains a hashed password and a salt. The password I use I generated with the random module (perhaps it is worth noting, since there are "more secure" RNGs out there).

My server is currently operational at here.

```
from twisted.web.server import Site
from twisted.web.resource import Resource
from twisted.internet import ssl, reactor
from twisted.python.modules import getModule
import urllib.parse
import cgi
import json
import os
import hashlib
admin_salt = ''
realpass = ''
port = int(os.environ.get('PORT', 17995))
class FormPage(Resource):
isLeaf = True
def render_GET(self, request):
out = {}
print(request.uri)
x = (request.uri).decode('ascii')
x = x[1:]
x = todi(x)
request.setHeader('Content-Type', 'text/plain; charset=UTF-8')
valid = False
if 'adminaccess' in x:
vlr = adminhandle(x)
out.update({'ADMIN':vlr[0]})
if len(vlr) != 1:
out.update({'CMDRES':vlr[1]})
if 'key' in x:
if x['key'] == 'chess':
valid = True
out.update({'my_name':'Bob'})
out.update({'success':valid})
return json.dumps(out).encode('UTF-8')

## def render_POST(self, request):
## x = request.content.read()
## print(x)
## return x

def todi(st):
if len(st) == 0:
return '{}'
if st[len(st)-1] == '/':
st = st[:-1]

Solution

The first problem is the function todi. I'm assuming a better name for it would be to_dict. If that is the case it does not make sense, that it sometimes returns the string "{}", sometimes "()" and sometimes an actual dictionary. I think this would be equivalent/better:

def to_dict(st):
    st = st.strip("/?")
    if not st:
        return dict()
    return dict(urllib.parse.parse_qsl(st))


This strips of any "/" or "?" from the beginning or end of the string and returns an empty dictionary if the string is empty.

Your function adminhandle should take the parameters it needs as parameters, not retrieve them on its own from data. It can also be slightly simplified by using the fact that lists are mutable, so you can just write result[0] = True instead of del result[0]; result.append(True):

def adminhandle(adminaccess, command):
    result = [False, ""]
    if adminaccess is not None:
        rawupass = (admin_salt+adminaccess).encode('ascii')
        hashupass = hashlib.sha512(rawupass).hexdigest()

        if hashupass == realpass:
            #access granted!
            result[0] = True
            if command == 'listdir':
                result[1] = str(os.listdir(os.getcwd()))
    return result


x is also a really bad name. At least name it data or something telling the reader what it actually is.

data = to_dict(request.uri.decode('ascii')[1:])


Your placeholder variable valid is also not necessary. As is writing out.update({'success': valid}). out['success'] = valid is sufficient. I would also use the fact that dictionaries have a dict.get method, that returns None if the key does not exist.

out = {'success': False}
    adminaccess, command = data.get('adminaccess'), data.get('command')
    out['ADMIN'], out['CMDRES'] = adminhandle(adminaccess, command)
    if not out['CMDRES']:
        del out['CMDRES']
    if data.get('key') == 'chess':
        out['my_name'] = 'Bob'
        out['success'] = True
    return json.dumps(out).encode('UTF-8')

Code Snippets

def to_dict(st):
    st = st.strip("/?")
    if not st:
        return dict()
    return dict(urllib.parse.parse_qsl(st))
def adminhandle(adminaccess, command):
    result = [False, ""]
    if adminaccess is not None:
        rawupass = (admin_salt+adminaccess).encode('ascii')
        hashupass = hashlib.sha512(rawupass).hexdigest()

        if hashupass == realpass:
            #access granted!
            result[0] = True
            if command == 'listdir':
                result[1] = str(os.listdir(os.getcwd()))
    return result
data = to_dict(request.uri.decode('ascii')[1:])
out = {'success': False}
    adminaccess, command = data.get('adminaccess'), data.get('command')
    out['ADMIN'], out['CMDRES'] = adminhandle(adminaccess, command)
    if not out['CMDRES']:
        del out['CMDRES']
    if data.get('key') == 'chess':
        out['my_name'] = 'Bob'
        out['success'] = True
    return json.dumps(out).encode('UTF-8')

Context

StackExchange Code Review Q#148322, answer score: 2

Revisions (0)

No revisions yet.