from twisted.internet.protocol import Protocol
from twisted.internet.protocol import Factory
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.internet import reactor
from twisted.protocols.policies import TimeoutMixin
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
import struct
import os
import logging
from exc import *
from model import *
def get_hex(data):
return "".join([hex(ord(c))[2:].zfill(2) for c in data])
def print_datagram(data):
print "=================================="
print "Received datagram:"
print get_hex(data)
print "=================================="
db_path = "piztor.sqlite"
FORMAT = "%(asctime)-15s %(message)s"
logging.basicConfig(format = FORMAT)
logger = logging.getLogger('piztor_server')
logger.setLevel(logging.INFO)
class _SectionSize:
LENGTH = 4
OPT_ID = 1
STATUS = 1
USER_ID = 4
USER_TOKEN = 32
GROUP_ID = 4
ENTRY_CNT = 4
LATITUDE = 8
LONGITUDE = 8
LOCATION_ENTRY = USER_ID + LATITUDE + LONGITUDE
PADDING = 1
class _OptCode:
user_auth = 0x00
location_update = 0x01
location_request= 0x02
user_info_request = 0x03
class _StatusCode:
sucess = 0x00
failure = 0x01
class RequestHandler(object):
def __init__(self):
self.engine = create_engine('sqlite:///' + db_path, echo = False)
self.Session = sessionmaker(bind = self.engine)
@classmethod
def get_uauth(cls, token, username, session):
try:
uauth = session.query(UserAuth) \
.filter(UserAuth.token == token).one()
if uauth.user.username != username:
logger.warning("Toke and username mismatch")
return None
return uauth
except NoResultFound:
logger.warning("Incorrect token")
return None
except MultipleResultsFound:
raise DBCorruptedError()
@classmethod
def trunc_padding(cls, data):
leading = bytes()
for i in xrange(len(data)):
ch = data[i]
if ch == '\x00':
print get_hex(leading), get_hex(data[i + 1:])
return (leading, data[i + 1:])
else:
leading += ch
# padding not found
return (None, data)
class UserAuthHandler(RequestHandler):
_user_auth_response_size = \
_SectionSize.LENGTH + \
_SectionSize.OPT_ID + \
_SectionSize.STATUS + \
_SectionSize.USER_ID + \
_SectionSize.USER_TOKEN
def handle(self, tr_data):
logger.info("Reading auth data...")
pos = -1
for i in xrange(0, len(tr_data)):
if tr_data[i] == '\x00':
pos = i
break
if pos == -1:
raise BadReqError("Authentication: Malformed request body")
username = tr_data[0:pos]
password = tr_data[pos + 1:]
logger.info("Trying to login with " \
"(username = {0}, password = {1})" \
.format(username, password))
session = self.Session()
try:
user = session.query(UserModel) \
.filter(UserModel.username == username).one()
except NoResultFound:
logger.info("No such user: {0}".format(username))
return struct.pack("!LBBL32s", UserAuthHandler \
._user_auth_response_size,
_OptCode.user_auth,
_StatusCode.failure,
0,
bytes('\x00' * 32))
except MultipleResultsFound:
raise DBCorruptedError()
uauth = user.auth
i