Start of login screen

master
Bob Mottram 2019-07-24 23:38:42 +01:00
parent 1546e6e12d
commit 79bc4a5224
3 changed files with 161 additions and 1 deletions

View File

@ -32,6 +32,8 @@ from follow import getFollowingFeed
from follow import outboxUndoFollow
from auth import authorize
from auth import createPassword
from auth import createBasicAuthHeader
from auth import authorizeBasic
from threads import threadWithTrace
from media import getMediaPath
from media import createMediaDirs
@ -49,6 +51,8 @@ from webinterface import htmlProfile
from webinterface import htmlInbox
from webinterface import htmlOutbox
from webinterface import htmlPostReplies
from webinterface import htmlLogin
from webinterface import htmlGetLoginCredentials
from shares import getSharesFeedForPerson
from shares import outboxShareUpload
from shares import outboxUndoShareUpload
@ -83,6 +87,7 @@ class PubServer(BaseHTTPRequestHandler):
def _set_headers(self,fileFormat: str) -> None:
self.send_response(200)
self.send_header('Content-type', fileFormat)
self.send_header('WWW-Authenticate', 'Basic realm="simple", charset="UTF-8"')
self.end_headers()
def _404(self) -> None:
@ -350,6 +355,16 @@ class PubServer(BaseHTTPRequestHandler):
self._set_headers('text/css')
self.wfile.write(css.encode('utf-8'))
return
# image on login screen
if self.path=='/login.png':
mediaFilename= \
self.server.baseDir+'/accounts/login.png'
if os.path.isfile(mediaFilename):
self._set_headers('image/png')
with open(mediaFilename, 'rb') as avFile:
mediaBinary = avFile.read()
self.wfile.write(mediaBinary)
return
# show media
# Note that this comes before the busy flag to avoid conflicts
if '/media/' in self.path:
@ -444,6 +459,14 @@ class PubServer(BaseHTTPRequestHandler):
if self._webfinger():
self.server.GETbusy=False
return
if self.path.startswith('/login'):
# request basic auth
self._set_headers('text/html')
self.wfile.write(htmlLogin(self.server.baseDir).encode('utf-8'))
self.server.GETbusy=False
return
# get an individual post from the path /@nickname/statusnumber
if '/@' in self.path:
namedStatus=self.path.split('/@')[1]
@ -966,7 +989,27 @@ class PubServer(BaseHTTPRequestHandler):
# if this is a POST to teh outbox then check authentication
self.outboxAuthenticated=False
self.postToNickname=None
if self.path.startswith('/login'):
print("headers: "+str(self.headers))
print("path: "+self.path)
loginNickname,loginPassword=htmlGetLoginCredentials(self.path,self.server.lastLoginTime)
if loginNickname:
self.server.lastLoginTime=int(time.time())
print('Nickname: '+loginNickname)
print('Password: '+loginPassword)
authHeader=createBasicAuthHeader(loginNickname,loginPassword)
if not authorizeBasic(self.server.baseDir,'/users/'+loginNickname+'/outbox',authHeader,False):
self.send_response(401)
self.end_headers()
self.server.POSTbusy=False
return
self.send_response(200)
self.end_headers()
self.server.POSTbusy=False
return
#self.path='/users/'+loginNickname+'/outbox'
if self.path.endswith('/outbox') or self.path.endswith('/shares'):
if '/users/' in self.path:
if self._isAuthorized():
@ -1200,6 +1243,7 @@ def runDaemon(clientToServer: bool,baseDir: str,domain: str, \
httpd.maxMessageLength=5000
httpd.maxImageSize=10*1024*1024
httpd.allowDeletion=allowDeletion
httpd.lastLoginTime=0
httpd.acceptedCaps=["inbox:write","objects:read"]
if noreply:
httpd.acceptedCaps.append('inbox:noreply')

BIN
img/login.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -7,12 +7,128 @@ __email__ = "bob@freedombone.net"
__status__ = "Production"
import json
import time
import os
from shutil import copyfile
from pprint import pprint
from person import personBoxJson
from utils import getNicknameFromActor
from utils import getDomainFromActor
from posts import getPersonBox
def htmlGetLoginCredentials(path: str,lastLoginTime: int) -> (str,str):
"""Receives login credentials via HTTPServer GET
"""
if not path.startswith('/login?'):
return None,None
# minimum time between login attempts
currTime=int(time.time())
if currTime<lastLoginTime+5:
return None,None
loginParams=path.split('?',1)[1]
if '&' not in loginParams:
return None,None
loginArgs=loginParams.split('&')
nickname=None
password=None
for arg in loginArgs:
if '=' in arg:
if arg.split('=',1)[0]=='nickname':
nickname=arg.split('=',1)[1]
elif arg.split('=',1)[0]=='password':
password=arg.split('=',1)[1]
return nickname,password
def htmlLogin(baseDir: str) -> str:
if not os.path.isfile(baseDir+'/accounts/login.png'):
copyfile(baseDir+'/img/login.png',baseDir+'/accounts/login.png')
# /login?nickname=[username]&password=[password]&remember=on
loginCSS= \
'body, html {' \
' height: 100%;' \
' font-family: Arial, Helvetica, sans-serif;' \
' max-width: 60%;' \
' min-width: 600px;' \
' margin: 0 auto;' \
'}' \
'' \
'form {' \
' border: 3px solid #f1f1f1;' \
'}' \
'' \
'input[type=text], input[type=password] {' \
' width: 100%;' \
' padding: 12px 20px;' \
' margin: 8px 0;' \
' display: inline-block;' \
' border: 1px solid #ccc;' \
' box-sizing: border-box;' \
'}' \
'' \
'button {' \
' background-color: #999;' \
' color: white;' \
' padding: 14px 20px;' \
' margin: 8px 0;' \
' border: none;' \
' cursor: pointer;' \
' width: 100%;' \
' font-size: 24px;' \
'}' \
'' \
'button:hover {' \
' opacity: 0.8;' \
'}' \
'' \
'.imgcontainer {' \
' text-align: center;' \
' margin: 24px 0 12px 0;' \
'}' \
'' \
'img.avatar {' \
' width: 40%;' \
' border-radius: 50%;' \
'}' \
'' \
'.container {' \
' padding: 16px;' \
'}' \
'' \
'span.psw {' \
' float: right;' \
' padding-top: 16px;' \
'}' \
'' \
'@media screen and (max-width: 300px) {' \
' span.psw {' \
' display: block;' \
' float: none;' \
' }' \
' .cancelbtn {' \
' width: 100%;' \
' }' \
'}'
loginForm=htmlHeader(loginCSS)
loginForm+= \
' <form method="POST" action="/login">' \
' <div class="imgcontainer">' \
' <img src="login.png" alt="login image" class="loginimage">' \
' </div>' \
'' \
' <div class="container">' \
' <label for="nickname"><b>Nickname</b></label>' \
' <input type="text" placeholder="Enter Nickname" name="nickname" required>' \
'' \
' <label for="password"><b>Password</b></label>' \
' <input type="password" placeholder="Enter Password" name="password" required>' \
'' \
' <button type="submit">Login</button>' \
' </div>' \
'</form>'
loginForm+=htmlFooter()
return loginForm
def htmlHeader(css=None,lang='en') -> str:
if not css:
htmlStr= \