Profile updates supporting utf-8

main
Bob Mottram 2019-11-10 13:31:55 +00:00
parent 246e280231
commit cae6637b24
2 changed files with 71 additions and 92 deletions

View File

@ -420,8 +420,7 @@ def extractMediaInFormPOST(postBytes,boundary,name: str):
# return the media and the before+after bytes # return the media and the before+after bytes
return mediaBytes,postBytes[:imageStartLocation]+remainder return mediaBytes,postBytes[:imageStartLocation]+remainder
def saveMediaInFormPOST(mediaBytes,baseDir: str, \ def saveMediaInFormPOST(mediaBytes,debug: bool, \
nickname: str,domain: str,debug: bool, \
filenameBase=None) -> (str,str): filenameBase=None) -> (str,str):
"""Saves the given media bytes extracted from http form POST """Saves the given media bytes extracted from http form POST
Returns the filename and attachment type Returns the filename and attachment type
@ -449,10 +448,6 @@ def saveMediaInFormPOST(mediaBytes,baseDir: str, \
for extension,contentType in extensionList.items(): for extension,contentType in extensionList.items():
searchStr=b'Content-Type: '+contentType.encode('utf8', 'ignore') searchStr=b'Content-Type: '+contentType.encode('utf8', 'ignore')
mediaLocation=mediaBytes.find(searchStr) mediaLocation=mediaBytes.find(searchStr)
if not filenameBase:
filenameBase= \
baseDir+'/accounts/'+ \
nickname+'@'+domain+'/upload'
if mediaLocation>-1: if mediaLocation>-1:
mediaFound=True mediaFound=True
if extension=='jpeg': if extension=='jpeg':

156
daemon.py
View File

@ -2665,15 +2665,37 @@ class PubServer(BaseHTTPRequestHandler):
print('DEBUG: media was found. '+str(len(mediaBytes))+' bytes') print('DEBUG: media was found. '+str(len(mediaBytes))+' bytes')
else: else:
print('DEBUG: no media was found in POST') print('DEBUG: no media was found in POST')
# Note: a .temp extension is used here so that at no time is
# an image with metadata publicly exposed, even for a few mS
filenameBase= \
self.server.baseDir+'/accounts/'+ \
nickname+'@'+self.server.domain+'/upload.temp'
filename,attachmentMediaType= \ filename,attachmentMediaType= \
saveMediaInFormPOST(mediaBytes,self.server.baseDir, \ saveMediaInFormPOST(mediaBytes,self.server.debug,filenameBase)
nickname,self.server.domain, \
self.server.debug,None)
if self.server.debug: if self.server.debug:
if filename: if filename:
print('DEBUG: POST media filename is '+filename) print('DEBUG: POST media filename is '+filename)
else: else:
print('DEBUG: no media filename in POST') print('DEBUG: no media filename in POST')
if filename:
if filename.endswith('.png') or \
filename.endswith('.jpg') or \
filename.endswith('.gif'):
if self.server.debug:
print('DEBUG: POST media removing metadata')
postImageFilename=filename.replace('.temp','')
removeMetaData(filename,postImageFilename)
if os.path.isfile(postImageFilename):
print('POST media saved to '+postImageFilename)
else:
print('ERROR: POST media could not be saved to '+postImageFilename)
else:
if os.path.isfile(filename):
os.rename(filename,filename.replace('.temp',''))
fields=extractTextFieldsInPOST(postBytes,boundary,self.server.debug) fields=extractTextFieldsInPOST(postBytes,boundary,self.server.debug)
if self.server.debug: if self.server.debug:
if fields: if fields:
@ -3075,95 +3097,57 @@ class PubServer(BaseHTTPRequestHandler):
self.server.POSTbusy=False self.server.POSTbusy=False
return return
# read the bytes of the http form POST
postBytes=self.rfile.read(length) postBytes=self.rfile.read(length)
msg = email.parser.BytesParser().parsebytes(postBytes) # extract each image type
#messageFields=msg.get_payload(decode=True).decode('utf-8').split(boundary) actorChanged=True
messageFields=msg.get_payload(decode=False).split(boundary) profileMediaTypes=['avatar','image','banner']
fields={} for mType in profileMediaTypes:
filename=None if self.server.debug:
lastImageLocation=0 print('DEBUG: profile update extracting '+mType+' image from POST')
actorChanged=False mediaBytes,postBytes=extractMediaInFormPOST(postBytes,boundary,mType)
for f in messageFields: if mediaBytes:
if f=='--': if self.server.debug:
print('DEBUG: profile update '+mType+' image was found. '+str(len(mediaBytes))+' bytes')
else:
if self.server.debug:
print('DEBUG: profile update, no '+mType+' image was found in POST')
continue continue
if ' name="' in f:
postStr=f.split(' name="',1)[1]
if '"' in postStr:
postKey=postStr.split('"',1)[0]
postValueStr=postStr.split('"',1)[1]
if ';' not in postValueStr:
if '\r\n' in postValueStr:
postLines=postValueStr.split('\r\n')
postValue=''
if len(postLines)>2:
for line in range(2,len(postLines)-1):
if line>2:
postValue+='\n'
postValue+=postLines[line]
fields[postKey]=postValue
else:
if 'filename="' not in postStr:
continue
filenameStr=postStr.split('filename="')[1]
if '"' not in filenameStr:
continue
postImageFilename=filenameStr.split('"')[0]
if '.' not in postImageFilename:
continue
# directly search the binary array for the beginning
# of an image
searchStr=b'Content-Type: image/png'
imageLocation=postBytes.find(searchStr,lastImageLocation)
filenameBase= \
self.server.baseDir+'/accounts/'+ \
nickname+'@'+self.server.domain+'/'+postKey
# Note: a .temp extension is used here so that at no time is
# an image with metadata publicly exposed, even for a few mS
if imageLocation>-1:
filename=filenameBase+'.png.temp'
else:
searchStr=b'Content-Type: image/jpeg'
imageLocation= \
postBytes.find(searchStr, \
lastImageLocation)
if imageLocation>-1:
filename=filenameBase+'.jpg.temp'
else:
searchStr=b'Content-Type: image/gif'
imageLocation= \
postBytes.find(searchStr, \
lastImageLocation)
if imageLocation>-1:
filename=filenameBase+'.gif.temp'
if filename and imageLocation>-1:
# locate the beginning of the image, after any
# carriage returns
startPos=imageLocation+len(searchStr)
for offset in range(1,8):
if postBytes[startPos+offset]!=10:
if postBytes[startPos+offset]!=13:
startPos+=offset
break
# look for the end of the image # Note: a .temp extension is used here so that at no time is
imageLocationEnd= \ # an image with metadata publicly exposed, even for a few mS
postBytes.find(b'-------',imageLocation+1) filenameBase= \
self.server.baseDir+'/accounts/'+ \
nickname+'@'+self.server.domain+'/'+mType+'.temp'
fd = open(filename, 'wb') filename,attachmentMediaType= \
if imageLocationEnd>-1: saveMediaInFormPOST(mediaBytes,self.server.debug,filenameBase)
fd.write(postBytes[startPos:][:imageLocationEnd-startPos]) if filename:
else: if self.server.debug:
fd.write(postBytes[startPos:]) print('DEBUG: profile update POST '+mType+' media filename is '+filename)
fd.close() else:
if self.server.debug:
print('DEBUG: profile update, no '+mType+' media filename in POST')
continue
if self.server.debug:
print('DEBUG: POST '+mType+' media removing metadata')
postImageFilename=filename.replace('.temp','')
removeMetaData(filename,postImageFilename)
if os.path.isfile(postImageFilename):
print('profile update POST '+mType+' image saved to '+postImageFilename)
actorChanged=True
else:
print('ERROR: profile update POST '+mType+' image could not be saved to '+postImageFilename)
fields=extractTextFieldsInPOST(postBytes,boundary,self.server.debug)
if self.server.debug:
if fields:
print('DEBUG: profile update text field extracted from POST '+str(fields))
else:
print('WARN: profile update, no text fields could be extracted from POST')
# remove exif/metadata
removeMetaData(filename, \
filename.replace('.temp',''))
os.remove(filename)
lastImageLocation=imageLocation+1
actorChanged=True
actorFilename= \ actorFilename= \
self.server.baseDir+'/accounts/'+ \ self.server.baseDir+'/accounts/'+ \
nickname+'@'+self.server.domain+'.json' nickname+'@'+self.server.domain+'.json'