Option to spoof image metadata

merge-requests/30/head
Bob Mottram 2021-05-09 13:17:55 +01:00
parent 572d338943
commit d8b882c10f
5 changed files with 93 additions and 16 deletions

View File

@ -239,7 +239,7 @@ from content import addHtmlTags
from content import extractMediaInFormPOST
from content import saveMediaInFormPOST
from content import extractTextFieldsInPOST
from media import removeMetaData
from media import processMetaData
from cache import checkForChangedActor
from cache import storePersonInCache
from cache import getPersonFromCache
@ -4075,7 +4075,8 @@ class PubServer(BaseHTTPRequestHandler):
os.remove(postImageFilename + '.etag')
except BaseException:
pass
removeMetaData(filename, postImageFilename)
processMetaData(baseDir, nickname, domain,
filename, postImageFilename)
if os.path.isfile(postImageFilename):
print('profile update POST ' + mType +
' image or font saved to ' + postImageFilename)
@ -13053,7 +13054,9 @@ class PubServer(BaseHTTPRequestHandler):
filename.endswith('.gif'):
postImageFilename = filename.replace('.temp', '')
print('Removing metadata from ' + postImageFilename)
removeMetaData(filename, postImageFilename)
processMetaData(self.server.baseDir,
nickname, self.server.domain,
filename, postImageFilename)
if os.path.isfile(postImageFilename):
print('POST media saved to ' + postImageFilename)
else:
@ -13307,6 +13310,7 @@ class PubServer(BaseHTTPRequestHandler):
postJsonObject['object'] = \
attachMedia(self.server.baseDir,
self.server.httpPrefix,
nickname,
self.server.domain,
self.server.port,
postJsonObject['object'],

View File

@ -8,6 +8,7 @@ __status__ = "Production"
import os
import datetime
from random import randint
from hashlib import sha1
from auth import createPassword
from utils import getFullDomain
@ -37,7 +38,7 @@ def replaceYouTube(postJsonObject: {}, replacementDomain: str) -> None:
replacementDomain)
def removeMetaData(imageFilename: str, outputFilename: str) -> None:
def _removeMetaData(imageFilename: str, outputFilename: str) -> None:
"""Attempts to do this with pure python didn't work well,
so better to use a dedicated tool if one is installed
"""
@ -53,6 +54,68 @@ def removeMetaData(imageFilename: str, outputFilename: str) -> None:
os.system('/usr/bin/mogrify -strip ' + outputFilename) # nosec
def _spoofMetaData(imageFilename: str, outputFilename: str,
spoofFilename: str) -> None:
"""Use reference images to spoof the metadata
"""
copyfile(imageFilename, outputFilename)
if not os.path.isfile(outputFilename):
print('ERROR: unable to spoof metadata from ' + imageFilename)
return
if not os.path.isfile(spoofFilename):
print('ERROR: No spoof reference image ' + spoofFilename)
return
if os.path.isfile('/usr/bin/exiftool'):
print('Spoofing metadata in ' + outputFilename + ' using exiftool')
os.system('exiftool -TagsFromFile ' +
spoofFilename + ' ' + outputFilename) # nosec
else:
print('ERROR: exiftool is not installed')
return
def processMetaData(baseDir: str, nickname: str, domain: str,
imageFilename: str, outputFilename: str) -> None:
"""Handles image metadata. This tries to spoof the metadata
if possible, but otherwise just removes it
"""
accountDir = baseDir + '/accounts/' + nickname + '@' + domain
spoofImagesDir = accountDir + '/ref/images'
if os.path.isdir(spoofImagesDir):
imageTypes = getImageExtensions()
# get the format of the target image
ext = None
for mType in imageTypes:
if outputFilename.endswith('.' + mType):
ext = mType
break
if ext:
spoofList = []
for subdir, dirs, files in os.walk(baseDir + '/accounts'):
for f in files:
filename = os.path.join(spoofImagesDir, f)
# what is the format of this file?
currExt = None
for mType in imageTypes:
if filename.endswith('.' + mType):
currExt = mType
break
# if this the same format as the target?
if currExt:
if currExt == ext:
spoofList.append(filename)
break
if spoofList:
# choose a reference at random
index = randint(0, len(spoofList))
spoofFilename = spoofList[index]
_spoofMetaData(imageFilename, outputFilename,
spoofFilename)
return
# if we can't spoof then just remove metadata
_removeMetaData(imageFilename, outputFilename)
def _isMedia(imageFilename: str) -> bool:
"""Is the given file a media file?
"""
@ -131,7 +194,8 @@ def _updateEtag(mediaFilename: str) -> None:
pass
def attachMedia(baseDir: str, httpPrefix: str, domain: str, port: int,
def attachMedia(baseDir: str, httpPrefix: str,
nickname: str, domain: str, port: int,
postJson: {}, imageFilename: str,
mediaType: str, description: str) -> {}:
"""Attaches media to a json object post
@ -179,7 +243,8 @@ def attachMedia(baseDir: str, httpPrefix: str, domain: str, port: int,
if baseDir:
if mediaType.startswith('image/'):
removeMetaData(imageFilename, mediaFilename)
processMetaData(baseDir, nickname, domain,
imageFilename, mediaFilename)
else:
copyfile(imageFilename, mediaFilename)
_updateEtag(mediaFilename)

View File

@ -34,7 +34,7 @@ from posts import createModeration
from auth import storeBasicCredentials
from auth import removePassword
from roles import setRole
from media import removeMetaData
from media import processMetaData
from utils import getStatusNumber
from utils import getFullDomain
from utils import validNickname
@ -135,7 +135,8 @@ def setProfileImage(baseDir: str, httpPrefix: str, nickname: str, domain: str,
'/usr/bin/convert ' + imageFilename + ' -size ' + \
resolution + ' -quality 50 ' + profileFilename
subprocess.call(cmd, shell=True)
removeMetaData(profileFilename, profileFilename)
processMetaData(baseDir, nickname, domain,
profileFilename, profileFilename)
return True
return False

View File

@ -1059,6 +1059,10 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
idStr = \
httpPrefix + '://' + domain + '/users/' + nickname + \
'/statuses/' + statusNumber + '/replies'
newPostUrl = \
httpPrefix + '://' + domain + '/@' + nickname + '/'+statusNumber
newPostAttributedTo = \
httpPrefix + '://' + domain + '/users/' + nickname
newPost = {
'@context': postContext,
'id': newPostId + '/activity',
@ -1073,8 +1077,8 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
'summary': summary,
'inReplyTo': inReplyTo,
'published': published,
'url': httpPrefix+'://'+domain+'/@'+nickname+'/'+statusNumber,
'attributedTo': httpPrefix+'://'+domain+'/users/'+nickname,
'url': newPostUrl,
'attributedTo': newPostAttributedTo,
'to': toRecipients,
'cc': toCC,
'sensitive': sensitive,
@ -1101,7 +1105,7 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
}
if attachImageFilename:
newPost['object'] = \
attachMedia(baseDir, httpPrefix, domain, port,
attachMedia(baseDir, httpPrefix, nickname, domain, port,
newPost['object'], attachImageFilename,
mediaType, imageDescription)
_appendEventFields(newPost['object'], eventUUID, eventStatus,
@ -1115,6 +1119,8 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
idStr = \
httpPrefix + '://' + domain + '/users/' + nickname + \
'/statuses/' + statusNumber + '/replies'
newPostUrl = \
httpPrefix + '://' + domain + '/@' + nickname+'/' + statusNumber
newPost = {
"@context": postContext,
'id': newPostId,
@ -1122,8 +1128,8 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
'summary': summary,
'inReplyTo': inReplyTo,
'published': published,
'url': httpPrefix+'://'+domain+'/@'+nickname+'/'+statusNumber,
'attributedTo': httpPrefix+'://'+domain+'/users/'+nickname,
'url': newPostUrl,
'attributedTo': httpPrefix + '://' + domain + '/users/' + nickname,
'to': toRecipients,
'cc': toCC,
'sensitive': sensitive,
@ -1149,7 +1155,7 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
}
if attachImageFilename:
newPost = \
attachMedia(baseDir, httpPrefix, domain, port,
attachMedia(baseDir, httpPrefix, nickname, domain, port,
newPost, attachImageFilename,
mediaType, imageDescription)
_appendEventFields(newPost, eventUUID, eventStatus,

View File

@ -18,7 +18,7 @@ from utils import validNickname
from utils import loadJson
from utils import saveJson
from utils import getImageExtensions
from media import removeMetaData
from media import processMetaData
def getValidSharedItemID(displayName: str) -> str:
@ -129,7 +129,8 @@ def addShare(baseDir: str,
formats = getImageExtensions()
for ext in formats:
if imageFilename.endswith('.' + ext):
removeMetaData(imageFilename, itemIDfile + '.' + ext)
processMetaData(baseDir, nickname, domain,
imageFilename, itemIDfile + '.' + ext)
if moveImage:
os.remove(imageFilename)
imageUrl = \