Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplified event-based communicator interface #106

Merged
merged 7 commits into from
May 27, 2016
8 changes: 5 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,14 @@ before_install:

## Command to install pip dependencies
install:
- pip install keyring colorama python2-pythondialog \
beautifulsoup4 argcomplete requests
- pip install keyring colorama beautifulsoup4 argcomplete requests cursor
#python2-pythondialog
# - pip install dbus-python

## command to run tests
script: python setup.py install
script:
# - python setup.py install
- ./kotnetcli-dummy.py --run-tests

#- ./kotnetcli.py -h
#- ./kotnetcli.py -1 -c
Expand Down
Empty file modified kotnetcli-dummy.py
100644 → 100755
Empty file.
194 changes: 58 additions & 136 deletions kotnetcli/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,17 @@

import re ## Basislib voor reguliere expressies
import time ## Voor timeout om venster te sluiten
import urlparse ## Diverse URL-manipulaties
import requests ## Invullen van HTTP POST-request
import socket ## Voor ophalen IP
import os ## Basislib

from bs4 import BeautifulSoup, Comment ## Om webinhoud proper te parsen.

import logging
logger = logging.getLogger(__name__)

NETLOGIN_HOST = "netlogin.kuleuven.be"
NETLOGIN_PORT = 443

## the maximum waiting time in seconds for browser connections
BROWSER_TIMEOUT_SEC = 1.5

Expand All @@ -44,7 +45,10 @@
RC_INVALID_INSTITUTION = 211
RC_INTERNAL_SCRIPT_ERR = 301

## custom exceptions
## custom exceptions to be caught by worker
class KotnetOfflineException(Exception):
pass

class WrongCredentialsException(Exception):
pass

Expand All @@ -58,7 +62,6 @@ def __init__(self, inst):
def get_inst(self):
return self.inst

##TODO hier het ip address in opslaan (~ hieronder de rccode)
class MaxNumberIPException(Exception):
pass

Expand All @@ -70,66 +73,67 @@ def __init__(self, rccode, html):
def get_info(self):
return (self.rccode, self.html)

## The class doing the actual browser emulation work. One can extend this
## class to add specific behavior (e.g. communicating; err catching; etc).
## The class doing the actual browser emulation work.
## KotnetBrowser() is like an API: it contains all possible Browser operations.
## So, we don't create a LoginBrowser(), LogoutBrowser(), etc. Instead, the
## proper Worker() is instantiated by kotnetcli.py, and this instance calls
## only the Browser() methods that it needs.
## Some
class KotnetBrowser(object):

## Note: the browser itself doesn't save any credentials. These are kept in a
## credentials object that is supplied when needed
def __init__(self, inst):
self.institution = inst
self.language = "nl"
self.host = NETLOGIN_HOST
self.port = NETLOGIN_PORT

## What the user sees when using netlogin. We need this url to
## find the password field name ("pwdXXXXX")
self.user_url = (
"https://netlogin.kuleuven.be/cgi-bin/wayf2.pl?inst={}"
"&lang=nl&submit=Ga+verder+%2F+Continue".format(self.institution)
)
## What the user sees when using netlogin. We need this url to find the
## password field name ("pwdXXXXX")
self.html_get_url = "https://{}:{}/cgi-bin/wayf2.pl".format(self.host, self.port)

## The backend: contains the to-be-submitted form.
self.form_url = "https://netlogin.kuleuven.be/cgi-bin/netlogin.pl"

## returns True | False depending on whether or not the user seems to be on the
## kotnet network (connect to netlogin.kuleuven.be)
def bevestig_kotnetverbinding(self):
## try to open a TCP connection on port 443 with a maximum waiting time
self.html_post_url = "https://{}:{}/cgi-bin/netlogin.pl".format(self.host, self.port)

def get_server_url(self):
return "{}:{}".format(self.host, self.port)

def check_connection(self):
## open a connection with the netlogin server using a maximum waiting time
try:
sock = socket.create_connection(("netlogin.kuleuven.be", 443), BROWSER_TIMEOUT_SEC)
sock = socket.create_connection((self.host,self.port), BROWSER_TIMEOUT_SEC)
sock.close()
return True
except socket.error:
## note: socket.timeout, socket.gaierror and socket.herror seem to be subclasses of socket.error
return False
raise KotnetOfflineException

def login_open_netlogin(self):
## Voorstel: vervangen door "Onderzoekt HTML..." (dwz zoekt wachtwoordvaknaam op)
## of: verwijder in zijn geheel. Is alleen interessant om de legacy
## kotnetcli-werkingen te tonen, heeft nauwelijks nog relevantie voor
## de huidige codebase. Het opzoeken van het wachtwoordvak kan
## haast net zo goed in login_input_credentials() worden gezet.

r = requests.get(self.user_url)
def login_get_request(self):
payload = {
"inst" : self.institution,
"lang" : self.language,
"submit" : "Ga verder / Continue",
}
try:
r = requests.get(self.html_get_url, params=payload, timeout=BROWSER_TIMEOUT_SEC)
except requests.exceptions.Timeout:
raise KotnetOfflineException
#logger.debug("HTTP GET RESPONSE FROM SERVER is:\n\n%s\n" % r.text)
## search for something of the form name="pwd123" and extract the pwd123 part
self.wachtwoordvak = re.findall("(?<=name=\")pwd\d*", r.text)[0]

def login_input_credentials(self, creds):
def login_post_request(self, creds):
(gebruikersnaam, wachtwoord) = creds.getCreds()

self.payload = {
"inst": self.institution,
"lang": self.language,
"submit": "Login",
"uid": gebruikersnaam,
self.wachtwoordvak: wachtwoord
}

def login_send_credentials(self):
r = requests.post(self.form_url, data=self.payload)
payload = {
"inst" : self.institution,
"lang" : self.language,
"submit" : "Login",
"uid" : gebruikersnaam,
self.wachtwoordvak : wachtwoord
}
try:
r = requests.post(self.html_post_url, data=payload, timeout=BROWSER_TIMEOUT_SEC)
except requests.exceptions.Timeout:
raise KotnetOfflineException
#logger.debug("HTTP POST RESPONSE FROM SERVER is:\n\n%s\n" % r.text)
self.html = r.text

## This method parses the server's response. On success, it returns a tuple of
Expand Down Expand Up @@ -183,69 +187,10 @@ def login_parse_results(self):
raise InternalScriptErrorException()

else:
raise UnknownRCException(rccode, html)

def logout_input_credentials(self):
## Lokale IP ophalen: lelijk, maar werkt goed en is snel. Is waar-
## schijnlijk de kortste code die crossplatform werkt, wat op zich
## wel vreemd is. Meer informatie:
## http://stackoverflow.com/questions/166506/finding-local-ip-addresses-using-pythons-stdlib
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("gmail.com", 80))
self.uitteloggenip = s.getsockname()[0]
s.close()

## Logoutformulier aanmaken, dan lokatie omvormen tot file://-URL zodat
## het browserobject hem kan gebruiken als lokatie.
gegevens = {"uitteloggenip" : self.uitteloggenip,
"gebruikersnaam": self.gebruikersnaam}

with open("tools/logoutformuliertemplate.html", "r") as logoutformulier_in:
data = logoutformulier_in.read()
data = data.format(**gegevens) ## gegevens worden hier ingevuld
with open("tools/logoutformulieringevuld.html", "w") as logoutformulier_out:
logoutformulier_out.write(data)

self.url_logoutformulier = urlparse.urljoin("file:", \
os.path.abspath("tools/logoutformulieringevuld.html"))

def logout_send_credentials(self):
self.browser.open(self.url_logoutformulier, timeout=1.8)
self.browser.select_form(nr=0)
self.browser.submit()
os.remove("tools/logoutformulieringevuld.html")

## returns True if logout is succesful; False when it fails
def logout_parse_results(self):
html = self.browser.response().read()
soup = BeautifulSoup(html)

## Zoek naar de rc-code in de comments van het html-bestand. Deze
## bevat de status.
comments = soup.findAll(text=lambda text:isinstance(text, Comment))
p = re.compile("weblogout: rc=\d+")

rccode = 100
## if not error codes appear, assume that everything went OK.
for c in comments:
m = p.search(c)
#m = p.findall(c)
#print m
if m:
rccode = int(m.group().strip("weblogout: rc="))

if rccode == 100:
## succesvolle logout
return True

elif rccode == 207:
## al uitgelogd
print "U had uzelf reeds succesvol uitgelogd."
return False
else:
print html
raise UnknownRCException(rccode, self.html)

class DummyBrowser(object):
## deprecated (see dev-srv)
class DummyBrowser(KotnetBrowser):
## allow custom test behavior via params
def __init__(self, inst, dummy_timeout, kotnet_online, netlogin_unavailable, rccode, downl, upl):
self.institution = inst
Expand All @@ -255,23 +200,20 @@ def __init__(self, inst, dummy_timeout, kotnet_online, netlogin_unavailable, rcc
self.rccode = rccode
self.download = abs(downl) %101
self.upload = abs(upl) %101
self.host = "dummynetlogin"
self.port = NETLOGIN_PORT

def bevestig_kotnetverbinding(self):
return self.kotnet_online
def check_connection(self):
if not self.kotnet_online:
raise KotnetOfflineException

def login_open_netlogin(self):
def login_get_request(self):
if (not self.netlogin_unavailable):
time.sleep(self.dummy_timeout)
else:
raise Exception
raise KotnetOfflineException

#def login_kies_kuleuven(self):
# time.sleep(0.1)

def login_input_credentials(self, *args):
time.sleep(self.dummy_timeout)

def login_send_credentials(self):
def login_post_request(self, creds):
time.sleep(self.dummy_timeout)

def login_parse_results(self):
Expand All @@ -295,23 +237,3 @@ def login_parse_results(self):

else:
raise UnknownRCException(self.rccode, "\n<html>\n<p>the dummy html page</p>\n</html>\n")


"""
## Deze klasse bevat functies voor de forceer-loginmethode. Gaan we nu nog
## niet gebruiken. Deze klasse wordt later waarschijnlijk samengevoegd met
## KotnetBrowser().
class KotnetForceerBrowser(KotnetBrowser):
def __init__():
pass

def uitteloggenipophalen(self):
html = self.browser.response().read()
soup = BeautifulSoup(html)

forms = soup.findAll("form")
form = forms[1]
uitteloggenip = form.contents[3]["value"]

return uitteloggenip
"""
68 changes: 0 additions & 68 deletions kotnetcli/communicator/bubblec.py

This file was deleted.

Loading