mirror of https://gitlab.com/bashrc2/epicyon
Option to spoof image metadata
parent
572d338943
commit
d8b882c10f
10
daemon.py
10
daemon.py
|
@ -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'],
|
||||
|
|
71
media.py
71
media.py
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
18
posts.py
18
posts.py
|
@ -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,
|
||||
|
|
|
@ -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 = \
|
||||
|
|
Loading…
Reference in New Issue