160 lines
5.3 KiB
Python
160 lines
5.3 KiB
Python
# url handlers
|
|
|
|
import re, time, json, logging, hashlib, base64, asyncio
|
|
|
|
## markdown 是处理日志文本的一种格式语法
|
|
import markdown2
|
|
from aiohttp import web
|
|
from coroweb import get, post
|
|
|
|
## 分页管理以及调取API时的错误信息
|
|
from apis import Page, APIValueError, APIResourceNotFoundError,APIError
|
|
from models import User, Comment, Blog, next_id
|
|
from config import configs
|
|
|
|
COOKIE_NAME = 'awesession'
|
|
_COOKIE_KEY = configs.session.secret
|
|
|
|
def user2cookie(user, max_age):
|
|
# build cookie string by: id-expires-sha1
|
|
expires = str(int(time.time() + max_age))
|
|
s = '%s-%s-%s-%s' % (user.id, user.passwd, expires, _COOKIE_KEY)
|
|
L = [str(user.id), expires, hashlib.sha1(s.encode('utf-8')).hexdigest()]
|
|
return '-'.join(L)
|
|
|
|
@get('/')
|
|
async def index(request):
|
|
|
|
# users = await User.findAll()
|
|
summary = 'XXXXXXXXX啦啦啦啦啦啦啦'
|
|
blogs = [
|
|
Blog(id='1', name='AAAAA', summary=summary, created_at=time.time() - 1200),
|
|
Blog(id='2', name='BBBBB', summary=summary, created_at=time.time() - 3600),
|
|
Blog(id='3', name='CCCCC', summary=summary, created_at=time.time() - 7200)
|
|
]
|
|
return {
|
|
'__template__': 'blogs.html',
|
|
'blogs': blogs,
|
|
# '__user__': request.__user__
|
|
}
|
|
@get('/api/users')
|
|
async def api_get_users():
|
|
users = await User.findAll(orderBy='created_at desc')
|
|
for u in users:
|
|
u.passwd = '******'
|
|
return dict(users=users)
|
|
@get('/register')
|
|
def register():
|
|
return {
|
|
'__template__': 'register.html'
|
|
}
|
|
## 处理登录页面URL
|
|
@get('/signin')
|
|
def signin():
|
|
return {
|
|
'__template__': 'signin.html'
|
|
}
|
|
|
|
@get('/signout')
|
|
def signout(request):
|
|
referer = request.headers.get('Referer')
|
|
r = web.HTTPFound(referer or '/')
|
|
r.set_cookie(COOKIE_NAME, '-deleted-', max_age=0, httponly=True)
|
|
logging.info('user signed out.')
|
|
return r
|
|
|
|
## 用户登录验证API
|
|
@post('/api/authenticate')
|
|
async def authenticate(*, email, passwd):
|
|
if not email:
|
|
raise APIValueError('email', 'Invalid email.')
|
|
if not passwd:
|
|
raise APIValueError('passwd', 'Invalid password.')
|
|
users = await User.findAll('email=?', [email])
|
|
if len(users) == 0:
|
|
raise APIValueError('email', 'Email not exist.')
|
|
user = users[0]
|
|
# check passwd:
|
|
sha1 = hashlib.sha1()
|
|
sha1.update(user.id.encode('utf-8')) #AttributeError: 'int' object has no attribute 'encode'
|
|
sha1.update(b':')
|
|
sha1.update(passwd.encode('utf-8'))
|
|
# if user.passwd != sha1.hexdigest():
|
|
# raise APIValueError('passwd', 'Invalid password.')
|
|
# authenticate ok, set cookie:
|
|
r = web.Response()
|
|
r.set_cookie(COOKIE_NAME, user2cookie(user, 86400), max_age=86400, httponly=True)
|
|
user.passwd = '******'
|
|
r.content_type = 'application/json'
|
|
r.body = json.dumps(user, ensure_ascii=False).encode('utf-8')
|
|
return r
|
|
|
|
_RE_EMAIL = re.compile(r'^[a-z0-9\.\-\_]+\@[a-z0-9\-\_]+(\.[a-z0-9\-\_]+){1,4}$')
|
|
_RE_SHA1 = re.compile(r'^[0-9a-f]{40}$')
|
|
## 用户注册API
|
|
@post('/api/users')
|
|
async def api_register_user(*, email, name, passwd):
|
|
if not name or not name.strip():
|
|
raise APIValueError('name')
|
|
if not email or not _RE_EMAIL.match(email):
|
|
raise APIValueError('email')
|
|
if not passwd or not _RE_SHA1.match(passwd):
|
|
raise APIValueError('passwd')
|
|
users = await User.findAll('email=?', [email])
|
|
if len(users) > 0:
|
|
raise APIError('register:failed', 'email', 'Email is already in use.')
|
|
uid = next_id()
|
|
sha1_passwd = '%s:%s' % (uid, passwd)
|
|
user = User(id=uid, name=name.strip(), email=email, passwd=hashlib.sha1(sha1_passwd.encode('utf-8')).hexdigest(), image='http://www.gravatar.com/avatar/%s?d=mm&s=120' % hashlib.md5(email.encode('utf-8')).hexdigest())
|
|
await user.save()
|
|
# make session cookie:
|
|
r = web.Response()
|
|
r.set_cookie(COOKIE_NAME, user2cookie(user, 86400), max_age=86400, httponly=True)
|
|
user.passwd = '******'
|
|
r.content_type = 'application/json'
|
|
r.body = json.dumps(user, ensure_ascii=False).encode('utf-8')
|
|
return r
|
|
|
|
|
|
# 解密cookie:
|
|
@asyncio.coroutine
|
|
def cookie2user(cookie_str):
|
|
'''
|
|
Parse cookie and load user if cookie is valid.
|
|
'''
|
|
if not cookie_str:
|
|
return None
|
|
try:
|
|
L = cookie_str.split('-')
|
|
if len(L) != 3:
|
|
return None
|
|
uid, expires, sha1 = L
|
|
if int(expires) < time.time():
|
|
return None
|
|
user = yield from User.find(uid)
|
|
if user is None:
|
|
return None
|
|
s = '%s-%s-%s-%s' % (uid, user.passwd, expires, _COOKIE_KEY)
|
|
if sha1 != hashlib.sha1(s.encode('utf-8')).hexdigest():
|
|
logging.info('invalid sha1')
|
|
return None
|
|
user.passwd = '******'
|
|
return user
|
|
except Exception as e:
|
|
logging.exception(e)
|
|
return None
|
|
|
|
@asyncio.coroutine
|
|
def auth_factory(app, handler):
|
|
@asyncio.coroutine
|
|
def auth(request):
|
|
logging.info('check user: %s %s' % (request.method, request.path))
|
|
request.__user__ = None
|
|
cookie_str = request.cookies.get(COOKIE_NAME)
|
|
if cookie_str:
|
|
user = yield from cookie2user(cookie_str)
|
|
if user:
|
|
logging.info('set current user: %s' % user.email)
|
|
request.__user__ = user
|
|
return (yield from handler(request))
|
|
return auth |