Is this a correct class-based-django-view? - python

In my project i have a page that displays a form where the User inputs some irrelevant(for the moment project name) and a host/ip-address. When he hits the scan button he makes a post request.
In the current moment i get that ip address and im trying to 'banner-grab' the running services on that ip/host and render the results to the page. In the code below i got that working but as im litteraly using django for the first time i think that my aproach is really bad cause all of my code( for grabbing the banner etc ) is in the POST function in my class-based-view.So question is can i do this in a better way? Maybe write that bannerGrab() function somewere else and, if form is valid just call the function in the POST method...
class NewProject(View):
# Reusable across functions
form_class = ProjectData
template_name = 'projectRelated/create_project.html'
ports = [20, 21, 22, 23, 80, 3306]
def get(self, request):
# redundant to use it like this
# form = ProjectData()
form = self.form_class
context = {
'form': form
# this is a context variable that i can use in my html page. like this <h3> {{ context.var }} </h3>
# context = {
# 'context.var': 'This will render in the html'
# }
}
print('Get method accessed!')
return render(request, self.template_name, context)
# TODO: Find a better way to show and store ports
# Store the results in JSON
# TODO: Store to JSON by choice. Not all code in POST method!!!
def post(self, request):
list_of_services = []
form = self.form_class(request.POST)
if form.is_valid():
_target = form.cleaned_data['target']
host_to_ip = ''
# project_from_input = form.cleaned_data['project_name']
print(_target)
for port in self.ports:
try:
error_message = 'Couldn\'t connect. Try another subnet!'
socket_obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# if connection is established result is 0.
# 0.5 seconds timeout. If subnet isn't reachable
socket_obj.settimeout(2)
if _target.isalpha():
# if user's input was alphanumeric convert to an ip address
host_to_ip = socket.gethostbyname(_target)
result = socket_obj.connect_ex((host_to_ip, port))
else:
# user's input was an IP address.
result = socket_obj.connect_ex((_target, port))
# If port is HTTP we need to make a request to get data!
if port == 80 and result == 0:
# in order to get an answer from the server we need to make a legitimate request to him.
bytes_to_send = str.encode("HEAD / HTTP/1.1\r\n\r\n")
# send our request FIRST.
socket_obj.send(bytes_to_send)
# grab the banner after server answers
banner = socket_obj.recv(1024).decode('utf-8')
for service in banner.split('\n'):
if 'Server:' in service:
list_of_services.append(service + ' running at port : ' + str(port))
socket_obj.close()
# an established connection returns 0 !
if result == 0:
banner = socket_obj.recv(1024).decode('utf-8')
banner_with_port = banner + ' running at port : ' + port
list_of_services.append(banner_with_port)
socket_obj.close()
except Exception as ex:
print('Exception -> ' + str(ex))
finally:
socket_obj.close()
# After button Run-Scan is pressed clear the form without reloading the page.
form = self.form_class
context = {
'form': form,
'list_of_services': list_of_services,
'error_message': error_message,
'target_input': _target,
}
print('POST METHOD ACCESSED!')
return render(request, self.template_name, context)```

Yes sure, moving all that logic into another method will make the code much cleaner. The post method should usually be concerned with parsing the form data, validating it and returning the response.
You could just make another method inside the NewProject class. Or you can create a new class called BannerManager and move the logic there. But I don't see a point in creating a new class unless you have more place where you are working with sockets, banners etc.

Related

Redirect to the same page and display a message if user insert wrong data

I am building a web chat application with chat rooms.
I have a page where users can open a new room, inside the page, there is a form.
I want to display a message to the user if he submits the form with a room that already exists.
For example:
Room 456 already exists and the user tried to open 456 room.
so I want to pop up a message that the room already exists.
The server side
#app.route('/NewRoom')
def newRm():
return render_template('NewRoom.html')
#app.route('/chat',methods=['GET','POST'])
def CreateRm():
if(request.method=='POST'):
username = request.form['username'].lower()
room = request.form['room'].lower()
ExistRoom = DBManage.ExistRoom(room)
error = "YOU ENTERED ROOM THAT ALREADY EXISTS"
if not ExistRoom:
limit = request.form['limit']
if limit == '':
limit = 'UNLIMITED'
session['limit'] = limit
image = request.files['getFile']
newImgs = open("static/images/" + username + ".jpg","wb")
newImgs.write(image.read())
newImgs.close()
room = room[:5].strip()
DBManage.newRoom(room,limit)
DBManage.newPerson(username,room)
#sDBManage.RoomUsers(room)
#Store the data in session
session['username'] = username
session['room'] = room
return render_template('chat.html', session = session)
else:
flash(error)
return redirect(url_for('newRm',error=error))
Inside CreateRm function the else at the end didn't work for me well, it's refreshing the page but doesn't send the error message, not really know how to solve that.
Client side
{% if error %}
<p class=error><strong>Error:</strong> {{ error }}
{% endif %}
Thanks all.
The problem is that you are returning a redirect to another route as well as trying to pass a variable to a template in that route. One way you could do this is by simply re-rendering the template, passing the variable, error to it at the same time. Try replacing:
return redirect(url_for('newRm',error=error))
with
return render_template('NewRoom.html', error=error)
Another option would be configuring your newRm route to accept optional arguments. This could look something like this:
#app.route('/NewRoom', defaults={'error':''})
#app.route('/Newroom/<error>')
def newRm():
return render_template('NewRoom.html')
You then pass an error to this route exactly as you have been doing.
return redirect(url_for('newRm', error=error))
To completely solve your problem, you'll also have to add a return statement outside your if(request.method=='POST'): to catch any GET requests. It could be something like this:
return render_template('NewRoom.html')

Twilio: Create two outgoing calls and join the conference using Python

I am trying to create a conferencing app with max 2 speakers using Twilio using Python/Django. However, in the docs I found out that you can do this by having inbound calls. but, my business model doesnt work like that. Is there a way for this to work like:
My Twilio number calls number 1
My Twilio number calls number 2
Twilio brings two channels to a new conference
I've tried this solution:
Twilio how to make two outbound calls and join(conference) them using node js
but it didn't help me much..
Here's my code:
#csrf_exempt
def conference(request):
print("success")
response = VoiceResponse()
dial = Dial()
dial.conference('Rooxm 1234')
response.append(dial)
print(response)
return HttpResponse('')
def call(number):
client = Client(TWILIO_ACCOUNT_SID,TWILIO_AUTH_TOKEN)
call = client.calls.create(
url='https://<blahblah_removed_purposefully>.ngrok.io/conf/',
to='+' + str(number),
from_='<removed_my_twilio_num>'
)
print(call.sid)
def index(request):
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = CallForm(request.POST)
# check whether it's valid:
if form.is_valid():
#print(dir(form.data.values))
call(form.cleaned_data['inline'])
call(form.cleaned_data['outline'])
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = CallForm()
return render(request, 'CallForm.html', {'form': form})
This gave me an error message during the call which is:
"An application error has occurred. Goodbye"
And I also get this in the debugger:
"Error on line 1 of document : Premature end of file. "
Any idea?
Okay so, I figured this out. The only thing that was needed to make that setup work is I had to modify the response, add the xml string there and then set the content_type of the returned object.
return HttpResponse(str(response),content_type='application/xml')

How to set cookie values and then immediately redirect to the next page and display what's in them

So I need to store two variables from one view and redirect to another view and display them. The obvious solution would be to use sessions but I don't have access to sessions because I don't have a database for this project so I'm trying to do sessions client sided because this isn't really a security issue anyways. This is my attempt so far:
View where I set the cookies:
response = HttpResponse('/result')
response.set_cookie('passes', True)
response.set_cookie('errors', [])
v = jsonschema.Draft4Validator(schema)
#Uses lazy validation to add all errors to validationErrors array
for error in v.iter_errors(jsonFile):
validationErrors.append(error)
response.set_cookie('passes', False)
for error in validationErrors:
error.schma_path = error.schema_path.__str__()[5:]
print error.schma_path
print error.schema_path
response.set_cookie('errors',validationErrors)
...
return redirect('/result')
View where I try to get the cookies:
passes = request.COOKIES.get('passes',"Doesn't Exist")
errors = request.COOKIES.get('errors', "Doesn't Exist")
return render(request, 'result.html', context = {'errors': errors, 'passes': passes})
passes and errors isn't set because they both return Doesn't Exist. How would I do this without returning to the original page? I don't want to return response where response = render_to_response(current view's template) because it defeats the purpose of what I'm trying to do.
You are not getting any cookies values, because actually after assigning the response a cookie, the function returns another Http response.
response = HttpResponse('/result') # first Http Response
response.set_cookie('errors', [])
...
return redirect('/result') # An other one
In the last line, you return another response.
so you should return the same response:
response = redirect('/result') # redirect is here
response.set_cookie('errors', [])
...
return response

Tornado set_secure_cookie

When I set a value in a set_secure_cookie function in Python Tornado, I can get the value whit a get_secure_cookie function when I make a redirec, but when I use a render action it doesn't appear.
form = UserAddForm(self.request.arguments)
if form.validate():
record = User(**form.data)
self.db.add(record)
self.db.commit()
self.set_secure_cookie("flash", "success")
self.redirect("/user") # Show the flash message with self.get_secure_cookie("flash")
else:
self.set_secure_cookie("flash", "error")
self.render("user/add.html", form=form) # Don't show the flash message with self.get_secure_cookie("flash")
Function "set_cookie" will set cookie in the HTTP response header which will effect in the next request.

How do I return the Instagram Realtime subscription challenge?

I'm trying to subscribe to a tag. It appears that the callback URL is being called correctly with a hub.challenge and hub.mode, and I figured out how to access the challenge using self.request.get('hub.challenge'). I thought I was just supposed to echo the challenge, but that doesn't appear to work since I receive the following errors in the GAE logs:
InstagramAPIError: (400) APISubscriptionError-Challenge verification failed. Sent "647bf6dbed31465093ee970577ce1b72", received "
647bf6dbed31465093ee970577ce1b72
".
Here is the full handler:
class InstagramHandler(BaseHandler):
def get(self):
def process_tag_update(update):
update = update
mode = self.request.get('hub.mode')
challenge = self.request.get('hub.challenge')
verify_token = self.request.get('hub.verify_token')
if challenge:
template_values = {'challenge':challenge}
path = os.path.join(os.path.dirname(__file__), '../templates/instagram.html')
html = template.render(path, template_values)
self.response.out.write(html)
else:
reactor = subscriptions.SubscriptionsReactor()
reactor.register_callback(subscriptions.SubscriptionType.TAG, process_tag_update)
x_hub_signature = self.request.headers.get('X-Hub-Signature')
raw_response = self.request.data
try:
reactor.process('INSTAGRAM_SECRET', raw_response, x_hub_signature)
except subscriptions.SubscriptionVerifyError:
logging.error('Instagram signature mismatch')
So returning it as a string worked. I should have payed closer attention to the error message, but it took a helpful person on the Python IRC to point out the extra line breaks in the message. Once I put the template files on one line, it seemed to work. I can now confirm that my app is authorized via Instagram's list subscription URL.

Categories

Resources