From 79bc4a5224d5fda32bbf851fb5ecc1d053c1864e Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 24 Jul 2019 23:38:42 +0100 Subject: [PATCH] Start of login screen --- daemon.py | 46 ++++++++++++++++++- img/login.png | Bin 0 -> 37211 bytes webinterface.py | 116 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 img/login.png diff --git a/daemon.py b/daemon.py index 96f586d50..9ff9756c7 100644 --- a/daemon.py +++ b/daemon.py @@ -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') diff --git a/img/login.png b/img/login.png new file mode 100644 index 0000000000000000000000000000000000000000..dc11479ef798f397f717de217de0746a1ce16ddd GIT binary patch literal 37211 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 literal 0 HcmV?d00001 diff --git a/webinterface.py b/webinterface.py index 4691e38e9..1263168ed 100644 --- a/webinterface.py +++ b/webinterface.py @@ -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 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+= \ + '
' \ + '
' \ + ' login image' \ + '
' \ + '' \ + '
' \ + ' ' \ + ' ' \ + '' \ + ' ' \ + ' ' \ + '' \ + ' ' \ + '
' \ + '
' + loginForm+=htmlFooter() + return loginForm + def htmlHeader(css=None,lang='en') -> str: if not css: htmlStr= \