mirror of https://gitlab.com/bashrc2/epicyon
Merge branch 'main' of ssh://code.freedombone.net:2222/bashrc/epicyon
commit
bd46688305
422
daemon.py
422
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
|
||||
|
|
@ -312,6 +312,18 @@ def saveDomainQrcode(baseDir: str, httpPrefix: str,
|
|||
class PubServer(BaseHTTPRequestHandler):
|
||||
protocol_version = 'HTTP/1.1'
|
||||
|
||||
def _getSpoofedCity(self, baseDir: str, nickname: str, domain: str) -> str:
|
||||
"""Returns the name of the city to use as a GPS spoofing location for
|
||||
image metadata
|
||||
"""
|
||||
city = self.server.city
|
||||
cityFilename = baseDir + '/accounts/' + \
|
||||
nickname + '@' + domain + '/city.txt'
|
||||
if os.path.isfile(cityFilename):
|
||||
with open(cityFilename, 'r') as fp:
|
||||
city = fp.read().replace('\n', '')
|
||||
return city
|
||||
|
||||
def _getInstalceUrl(self, callingDomain: str) -> str:
|
||||
"""Returns the URL for this instance
|
||||
"""
|
||||
|
|
@ -420,6 +432,9 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
eventDate = None
|
||||
eventTime = None
|
||||
location = None
|
||||
city = self._getSpoofedCity(self.server.baseDir,
|
||||
nickname, self.server.domain)
|
||||
|
||||
messageJson = \
|
||||
createPublicPost(self.server.baseDir,
|
||||
nickname,
|
||||
|
|
@ -428,7 +443,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
answer, False, False, False,
|
||||
commentsEnabled,
|
||||
attachImageFilename, mediaType,
|
||||
imageDescription,
|
||||
imageDescription, city,
|
||||
inReplyTo,
|
||||
inReplyToAtomUri,
|
||||
subject,
|
||||
|
|
@ -1144,9 +1159,13 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
Client to server message post
|
||||
https://www.w3.org/TR/activitypub/#client-to-server-outbox-delivery
|
||||
"""
|
||||
city = self.server.city
|
||||
|
||||
if postToNickname:
|
||||
print('Posting to nickname ' + postToNickname)
|
||||
self.postToNickname = postToNickname
|
||||
city = self._getSpoofedCity(self.server.baseDir,
|
||||
postToNickname, self.server.domain)
|
||||
|
||||
return postMessageToOutbox(self.server.session,
|
||||
self.server.translate,
|
||||
|
|
@ -1170,7 +1189,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.debug,
|
||||
self.server.YTReplacementDomain,
|
||||
self.server.showPublishedDateOnly,
|
||||
self.server.allowLocalNetworkAccess)
|
||||
self.server.allowLocalNetworkAccess,
|
||||
city)
|
||||
|
||||
def _postToOutboxThread(self, messageJson: {}) -> bool:
|
||||
"""Creates a thread to send a post
|
||||
|
|
@ -4075,7 +4095,11 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
os.remove(postImageFilename + '.etag')
|
||||
except BaseException:
|
||||
pass
|
||||
removeMetaData(filename, postImageFilename)
|
||||
|
||||
city = self._getSpoofedCity(baseDir, nickname, domain)
|
||||
|
||||
processMetaData(baseDir, nickname, domain,
|
||||
filename, postImageFilename, city)
|
||||
if os.path.isfile(postImageFilename):
|
||||
print('profile update POST ' + mType +
|
||||
' image or font saved to ' + postImageFilename)
|
||||
|
|
@ -4226,6 +4250,13 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
nickname,
|
||||
pwd)
|
||||
|
||||
# change city
|
||||
if fields.get('cityDropdown'):
|
||||
cityFilename = baseDir + '/accounts/' + \
|
||||
nickname + '@' + domain + '/city.txt'
|
||||
with open(cityFilename, 'w+') as fp:
|
||||
fp.write(fields['cityDropdown'])
|
||||
|
||||
# change displayed name
|
||||
if fields.get('displayNickname'):
|
||||
if fields['displayNickname'] != actorJson['name']:
|
||||
|
|
@ -4244,118 +4275,175 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
if checkNameAndBio:
|
||||
redirectPath = 'previewAvatar'
|
||||
|
||||
# change media instance status
|
||||
if fields.get('mediaInstance'):
|
||||
self.server.mediaInstance = False
|
||||
self.server.defaultTimeline = 'inbox'
|
||||
if fields['mediaInstance'] == 'on':
|
||||
self.server.mediaInstance = True
|
||||
self.server.blogsInstance = False
|
||||
self.server.newsInstance = False
|
||||
self.server.defaultTimeline = 'tlmedia'
|
||||
setConfigParam(baseDir,
|
||||
"mediaInstance",
|
||||
self.server.mediaInstance)
|
||||
setConfigParam(baseDir,
|
||||
"blogsInstance",
|
||||
self.server.blogsInstance)
|
||||
setConfigParam(baseDir,
|
||||
"newsInstance",
|
||||
self.server.newsInstance)
|
||||
else:
|
||||
if self.server.mediaInstance:
|
||||
if nickname == adminNickname:
|
||||
# change media instance status
|
||||
if fields.get('mediaInstance'):
|
||||
self.server.mediaInstance = False
|
||||
self.server.defaultTimeline = 'inbox'
|
||||
if fields['mediaInstance'] == 'on':
|
||||
self.server.mediaInstance = True
|
||||
self.server.blogsInstance = False
|
||||
self.server.newsInstance = False
|
||||
self.server.defaultTimeline = 'tlmedia'
|
||||
setConfigParam(baseDir,
|
||||
"mediaInstance",
|
||||
self.server.mediaInstance)
|
||||
|
||||
# is this a news theme?
|
||||
if isNewsThemeName(self.server.baseDir,
|
||||
self.server.themeName):
|
||||
fields['newsInstance'] = 'on'
|
||||
|
||||
# change news instance status
|
||||
if fields.get('newsInstance'):
|
||||
self.server.newsInstance = False
|
||||
self.server.defaultTimeline = 'inbox'
|
||||
if fields['newsInstance'] == 'on':
|
||||
self.server.newsInstance = True
|
||||
self.server.blogsInstance = False
|
||||
self.server.mediaInstance = False
|
||||
self.server.defaultTimeline = 'tlfeatures'
|
||||
setConfigParam(baseDir,
|
||||
"mediaInstance",
|
||||
self.server.mediaInstance)
|
||||
setConfigParam(baseDir,
|
||||
"blogsInstance",
|
||||
self.server.blogsInstance)
|
||||
setConfigParam(baseDir,
|
||||
"newsInstance",
|
||||
self.server.newsInstance)
|
||||
else:
|
||||
if self.server.newsInstance:
|
||||
self.server.newsInstance = False
|
||||
self.server.defaultTimeline = 'inbox'
|
||||
setConfigParam(baseDir,
|
||||
"newsInstance",
|
||||
self.server.mediaInstance)
|
||||
|
||||
# change blog instance status
|
||||
if fields.get('blogsInstance'):
|
||||
self.server.blogsInstance = False
|
||||
self.server.defaultTimeline = 'inbox'
|
||||
if fields['blogsInstance'] == 'on':
|
||||
self.server.blogsInstance = True
|
||||
self.server.mediaInstance = False
|
||||
self.server.newsInstance = False
|
||||
self.server.defaultTimeline = 'tlblogs'
|
||||
setConfigParam(baseDir,
|
||||
"blogsInstance",
|
||||
self.server.blogsInstance)
|
||||
setConfigParam(baseDir,
|
||||
"mediaInstance",
|
||||
self.server.mediaInstance)
|
||||
setConfigParam(baseDir,
|
||||
"newsInstance",
|
||||
self.server.newsInstance)
|
||||
else:
|
||||
if self.server.blogsInstance:
|
||||
self.server.blogsInstance = False
|
||||
self.server.defaultTimeline = 'inbox'
|
||||
setConfigParam(baseDir,
|
||||
"blogsInstance",
|
||||
self.server.blogsInstance)
|
||||
setConfigParam(baseDir,
|
||||
"newsInstance",
|
||||
self.server.newsInstance)
|
||||
else:
|
||||
if self.server.mediaInstance:
|
||||
self.server.mediaInstance = False
|
||||
self.server.defaultTimeline = 'inbox'
|
||||
setConfigParam(baseDir,
|
||||
"mediaInstance",
|
||||
self.server.mediaInstance)
|
||||
|
||||
# change theme
|
||||
if fields.get('themeDropdown'):
|
||||
self.server.themeName = fields['themeDropdown']
|
||||
setTheme(baseDir, self.server.themeName, domain,
|
||||
allowLocalNetworkAccess, systemLanguage)
|
||||
self.server.textModeBanner = \
|
||||
getTextModeBanner(self.server.baseDir)
|
||||
self.server.iconsCache = {}
|
||||
self.server.fontsCache = {}
|
||||
self.server.showPublishAsIcon = \
|
||||
getConfigParam(self.server.baseDir,
|
||||
'showPublishAsIcon')
|
||||
self.server.fullWidthTimelineButtonHeader = \
|
||||
getConfigParam(self.server.baseDir,
|
||||
'fullWidthTimelineButtonHeader')
|
||||
self.server.iconsAsButtons = \
|
||||
getConfigParam(self.server.baseDir,
|
||||
'iconsAsButtons')
|
||||
self.server.rssIconAtTop = \
|
||||
getConfigParam(self.server.baseDir,
|
||||
'rssIconAtTop')
|
||||
self.server.publishButtonAtTop = \
|
||||
getConfigParam(self.server.baseDir,
|
||||
'publishButtonAtTop')
|
||||
setNewsAvatar(baseDir,
|
||||
fields['themeDropdown'],
|
||||
httpPrefix,
|
||||
domain,
|
||||
domainFull)
|
||||
# is this a news theme?
|
||||
if isNewsThemeName(self.server.baseDir,
|
||||
self.server.themeName):
|
||||
fields['newsInstance'] = 'on'
|
||||
|
||||
# change news instance status
|
||||
if fields.get('newsInstance'):
|
||||
self.server.newsInstance = False
|
||||
self.server.defaultTimeline = 'inbox'
|
||||
if fields['newsInstance'] == 'on':
|
||||
self.server.newsInstance = True
|
||||
self.server.blogsInstance = False
|
||||
self.server.mediaInstance = False
|
||||
self.server.defaultTimeline = 'tlfeatures'
|
||||
setConfigParam(baseDir,
|
||||
"mediaInstance",
|
||||
self.server.mediaInstance)
|
||||
setConfigParam(baseDir,
|
||||
"blogsInstance",
|
||||
self.server.blogsInstance)
|
||||
setConfigParam(baseDir,
|
||||
"newsInstance",
|
||||
self.server.newsInstance)
|
||||
else:
|
||||
if self.server.newsInstance:
|
||||
self.server.newsInstance = False
|
||||
self.server.defaultTimeline = 'inbox'
|
||||
setConfigParam(baseDir,
|
||||
"newsInstance",
|
||||
self.server.mediaInstance)
|
||||
|
||||
# change blog instance status
|
||||
if fields.get('blogsInstance'):
|
||||
self.server.blogsInstance = False
|
||||
self.server.defaultTimeline = 'inbox'
|
||||
if fields['blogsInstance'] == 'on':
|
||||
self.server.blogsInstance = True
|
||||
self.server.mediaInstance = False
|
||||
self.server.newsInstance = False
|
||||
self.server.defaultTimeline = 'tlblogs'
|
||||
setConfigParam(baseDir,
|
||||
"blogsInstance",
|
||||
self.server.blogsInstance)
|
||||
setConfigParam(baseDir,
|
||||
"mediaInstance",
|
||||
self.server.mediaInstance)
|
||||
setConfigParam(baseDir,
|
||||
"newsInstance",
|
||||
self.server.newsInstance)
|
||||
else:
|
||||
if self.server.blogsInstance:
|
||||
self.server.blogsInstance = False
|
||||
self.server.defaultTimeline = 'inbox'
|
||||
setConfigParam(baseDir,
|
||||
"blogsInstance",
|
||||
self.server.blogsInstance)
|
||||
|
||||
# change theme
|
||||
if fields.get('themeDropdown'):
|
||||
self.server.themeName = fields['themeDropdown']
|
||||
setTheme(baseDir, self.server.themeName, domain,
|
||||
allowLocalNetworkAccess, systemLanguage)
|
||||
self.server.textModeBanner = \
|
||||
getTextModeBanner(self.server.baseDir)
|
||||
self.server.iconsCache = {}
|
||||
self.server.fontsCache = {}
|
||||
self.server.showPublishAsIcon = \
|
||||
getConfigParam(self.server.baseDir,
|
||||
'showPublishAsIcon')
|
||||
self.server.fullWidthTimelineButtonHeader = \
|
||||
getConfigParam(self.server.baseDir,
|
||||
'fullWidthTimelineButtonHeader')
|
||||
self.server.iconsAsButtons = \
|
||||
getConfigParam(self.server.baseDir,
|
||||
'iconsAsButtons')
|
||||
self.server.rssIconAtTop = \
|
||||
getConfigParam(self.server.baseDir,
|
||||
'rssIconAtTop')
|
||||
self.server.publishButtonAtTop = \
|
||||
getConfigParam(self.server.baseDir,
|
||||
'publishButtonAtTop')
|
||||
setNewsAvatar(baseDir,
|
||||
fields['themeDropdown'],
|
||||
httpPrefix,
|
||||
domain,
|
||||
domainFull)
|
||||
|
||||
# change instance title
|
||||
if fields.get('instanceTitle'):
|
||||
currInstanceTitle = \
|
||||
getConfigParam(baseDir, 'instanceTitle')
|
||||
if fields['instanceTitle'] != currInstanceTitle:
|
||||
setConfigParam(baseDir, 'instanceTitle',
|
||||
fields['instanceTitle'])
|
||||
|
||||
# change YouTube alternate domain
|
||||
if fields.get('ytdomain'):
|
||||
currYTDomain = self.server.YTReplacementDomain
|
||||
if fields['ytdomain'] != currYTDomain:
|
||||
newYTDomain = fields['ytdomain']
|
||||
if '://' in newYTDomain:
|
||||
newYTDomain = newYTDomain.split('://')[1]
|
||||
if '/' in newYTDomain:
|
||||
newYTDomain = newYTDomain.split('/')[0]
|
||||
if '.' in newYTDomain:
|
||||
setConfigParam(baseDir,
|
||||
'youtubedomain',
|
||||
newYTDomain)
|
||||
self.server.YTReplacementDomain = \
|
||||
newYTDomain
|
||||
else:
|
||||
setConfigParam(baseDir,
|
||||
'youtubedomain', '')
|
||||
self.server.YTReplacementDomain = None
|
||||
|
||||
# change instance description
|
||||
currInstanceDescriptionShort = \
|
||||
getConfigParam(baseDir,
|
||||
'instanceDescriptionShort')
|
||||
if fields.get('instanceDescriptionShort'):
|
||||
if fields['instanceDescriptionShort'] != \
|
||||
currInstanceDescriptionShort:
|
||||
iDesc = fields['instanceDescriptionShort']
|
||||
setConfigParam(baseDir,
|
||||
'instanceDescriptionShort',
|
||||
iDesc)
|
||||
else:
|
||||
if currInstanceDescriptionShort:
|
||||
setConfigParam(baseDir,
|
||||
'instanceDescriptionShort', '')
|
||||
currInstanceDescription = \
|
||||
getConfigParam(baseDir, 'instanceDescription')
|
||||
if fields.get('instanceDescription'):
|
||||
if fields['instanceDescription'] != \
|
||||
currInstanceDescription:
|
||||
setConfigParam(baseDir,
|
||||
'instanceDescription',
|
||||
fields['instanceDescription'])
|
||||
else:
|
||||
if currInstanceDescription:
|
||||
setConfigParam(baseDir,
|
||||
'instanceDescription', '')
|
||||
|
||||
# change email address
|
||||
currentEmailAddress = getEmailAddress(actorJson)
|
||||
|
|
@ -4536,62 +4624,6 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
del actorJson['alsoKnownAs']
|
||||
actorChanged = True
|
||||
|
||||
# change instance title
|
||||
if fields.get('instanceTitle'):
|
||||
currInstanceTitle = \
|
||||
getConfigParam(baseDir, 'instanceTitle')
|
||||
if fields['instanceTitle'] != currInstanceTitle:
|
||||
setConfigParam(baseDir, 'instanceTitle',
|
||||
fields['instanceTitle'])
|
||||
|
||||
# change YouTube alternate domain
|
||||
if fields.get('ytdomain'):
|
||||
currYTDomain = self.server.YTReplacementDomain
|
||||
if fields['ytdomain'] != currYTDomain:
|
||||
newYTDomain = fields['ytdomain']
|
||||
if '://' in newYTDomain:
|
||||
newYTDomain = newYTDomain.split('://')[1]
|
||||
if '/' in newYTDomain:
|
||||
newYTDomain = newYTDomain.split('/')[0]
|
||||
if '.' in newYTDomain:
|
||||
setConfigParam(baseDir,
|
||||
'youtubedomain',
|
||||
newYTDomain)
|
||||
self.server.YTReplacementDomain = \
|
||||
newYTDomain
|
||||
else:
|
||||
setConfigParam(baseDir,
|
||||
'youtubedomain', '')
|
||||
self.server.YTReplacementDomain = None
|
||||
|
||||
# change instance description
|
||||
currInstanceDescriptionShort = \
|
||||
getConfigParam(baseDir,
|
||||
'instanceDescriptionShort')
|
||||
if fields.get('instanceDescriptionShort'):
|
||||
if fields['instanceDescriptionShort'] != \
|
||||
currInstanceDescriptionShort:
|
||||
iDesc = fields['instanceDescriptionShort']
|
||||
setConfigParam(baseDir,
|
||||
'instanceDescriptionShort',
|
||||
iDesc)
|
||||
else:
|
||||
if currInstanceDescriptionShort:
|
||||
setConfigParam(baseDir,
|
||||
'instanceDescriptionShort', '')
|
||||
currInstanceDescription = \
|
||||
getConfigParam(baseDir, 'instanceDescription')
|
||||
if fields.get('instanceDescription'):
|
||||
if fields['instanceDescription'] != \
|
||||
currInstanceDescription:
|
||||
setConfigParam(baseDir,
|
||||
'instanceDescription',
|
||||
fields['instanceDescription'])
|
||||
else:
|
||||
if currInstanceDescription:
|
||||
setConfigParam(baseDir,
|
||||
'instanceDescription', '')
|
||||
|
||||
# change user bio
|
||||
if fields.get('bio'):
|
||||
if fields['bio'] != actorJson['summary']:
|
||||
|
|
@ -10293,6 +10325,11 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
"""
|
||||
if '/users/' in path and path.endswith('/editprofile'):
|
||||
peertubeInstances = self.server.peertubeInstances
|
||||
nickname = getNicknameFromActor(path)
|
||||
if nickname:
|
||||
city = self._getSpoofedCity(baseDir, nickname, domain)
|
||||
else:
|
||||
city = self.server.city
|
||||
msg = htmlEditProfile(self.server.cssCache,
|
||||
translate,
|
||||
baseDir,
|
||||
|
|
@ -10302,7 +10339,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.defaultTimeline,
|
||||
self.server.themeName,
|
||||
peertubeInstances,
|
||||
self.server.textModeBanner).encode('utf-8')
|
||||
self.server.textModeBanner,
|
||||
city).encode('utf-8')
|
||||
if msg:
|
||||
msglen = len(msg)
|
||||
self._set_headers('text/html', msglen,
|
||||
|
|
@ -13053,7 +13091,11 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
filename.endswith('.gif'):
|
||||
postImageFilename = filename.replace('.temp', '')
|
||||
print('Removing metadata from ' + postImageFilename)
|
||||
removeMetaData(filename, postImageFilename)
|
||||
city = self._getSpoofedCity(self.server.baseDir,
|
||||
nickname, self.server.domain)
|
||||
processMetaData(self.server.baseDir,
|
||||
nickname, self.server.domain,
|
||||
filename, postImageFilename, city)
|
||||
if os.path.isfile(postImageFilename):
|
||||
print('POST media saved to ' + postImageFilename)
|
||||
else:
|
||||
|
|
@ -13158,6 +13200,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
nickname, self.server.domain)
|
||||
return 1
|
||||
|
||||
city = self._getSpoofedCity(self.server.baseDir,
|
||||
nickname, self.server.domain)
|
||||
messageJson = \
|
||||
createPublicPost(self.server.baseDir,
|
||||
nickname,
|
||||
|
|
@ -13168,6 +13212,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
False, False, False, commentsEnabled,
|
||||
filename, attachmentMediaType,
|
||||
fields['imageDescription'],
|
||||
city,
|
||||
fields['replyTo'], fields['replyTo'],
|
||||
fields['subject'], fields['schedulePost'],
|
||||
fields['eventDate'], fields['eventTime'],
|
||||
|
|
@ -13304,15 +13349,20 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
imgDescription = fields['imageDescription']
|
||||
|
||||
if filename:
|
||||
city = self._getSpoofedCity(self.server.baseDir,
|
||||
nickname,
|
||||
self.server.domain)
|
||||
postJsonObject['object'] = \
|
||||
attachMedia(self.server.baseDir,
|
||||
self.server.httpPrefix,
|
||||
nickname,
|
||||
self.server.domain,
|
||||
self.server.port,
|
||||
postJsonObject['object'],
|
||||
filename,
|
||||
attachmentMediaType,
|
||||
imgDescription)
|
||||
imgDescription,
|
||||
city)
|
||||
|
||||
replaceYouTube(postJsonObject,
|
||||
self.server.YTReplacementDomain)
|
||||
|
|
@ -13334,6 +13384,9 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
str(fields['postUrl']))
|
||||
return -1
|
||||
elif postType == 'newunlisted':
|
||||
city = self._getSpoofedCity(self.server.baseDir,
|
||||
nickname,
|
||||
self.server.domain)
|
||||
messageJson = \
|
||||
createUnlistedPost(self.server.baseDir,
|
||||
nickname,
|
||||
|
|
@ -13343,6 +13396,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
False, False, False, commentsEnabled,
|
||||
filename, attachmentMediaType,
|
||||
fields['imageDescription'],
|
||||
city,
|
||||
fields['replyTo'],
|
||||
fields['replyTo'],
|
||||
fields['subject'],
|
||||
|
|
@ -13364,6 +13418,9 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
else:
|
||||
return -1
|
||||
elif postType == 'newfollowers':
|
||||
city = self._getSpoofedCity(self.server.baseDir,
|
||||
nickname,
|
||||
self.server.domain)
|
||||
messageJson = \
|
||||
createFollowersOnlyPost(self.server.baseDir,
|
||||
nickname,
|
||||
|
|
@ -13375,6 +13432,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
commentsEnabled,
|
||||
filename, attachmentMediaType,
|
||||
fields['imageDescription'],
|
||||
city,
|
||||
fields['replyTo'],
|
||||
fields['replyTo'],
|
||||
fields['subject'],
|
||||
|
|
@ -13416,6 +13474,9 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
maximumAttendeeCapacity = \
|
||||
int(fields['maximumAttendeeCapacity'])
|
||||
|
||||
city = self._getSpoofedCity(self.server.baseDir,
|
||||
nickname,
|
||||
self.server.domain)
|
||||
messageJson = \
|
||||
createEventPost(self.server.baseDir,
|
||||
nickname,
|
||||
|
|
@ -13427,6 +13488,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
False, False, commentsEnabled,
|
||||
filename, attachmentMediaType,
|
||||
fields['imageDescription'],
|
||||
city,
|
||||
fields['subject'],
|
||||
fields['schedulePost'],
|
||||
fields['eventDate'],
|
||||
|
|
@ -13452,6 +13514,9 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
messageJson = None
|
||||
print('A DM was posted')
|
||||
if '@' in mentionsStr:
|
||||
city = self._getSpoofedCity(self.server.baseDir,
|
||||
nickname,
|
||||
self.server.domain)
|
||||
messageJson = \
|
||||
createDirectMessagePost(self.server.baseDir,
|
||||
nickname,
|
||||
|
|
@ -13464,6 +13529,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
commentsEnabled,
|
||||
filename, attachmentMediaType,
|
||||
fields['imageDescription'],
|
||||
city,
|
||||
fields['replyTo'],
|
||||
fields['replyTo'],
|
||||
fields['subject'],
|
||||
|
|
@ -13492,6 +13558,9 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
print('A reminder was posted for ' + handle)
|
||||
if '@' + handle not in mentionsStr:
|
||||
mentionsStr = '@' + handle + ' ' + mentionsStr
|
||||
city = self._getSpoofedCity(self.server.baseDir,
|
||||
nickname,
|
||||
self.server.domain)
|
||||
messageJson = \
|
||||
createDirectMessagePost(self.server.baseDir,
|
||||
nickname,
|
||||
|
|
@ -13502,6 +13571,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
True, False, False, False,
|
||||
filename, attachmentMediaType,
|
||||
fields['imageDescription'],
|
||||
city,
|
||||
None, None,
|
||||
fields['subject'],
|
||||
True, fields['schedulePost'],
|
||||
|
|
@ -13525,6 +13595,9 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
# and not accounts being reported we disable any
|
||||
# included fediverse addresses by replacing '@' with '-at-'
|
||||
fields['message'] = fields['message'].replace('@', '-at-')
|
||||
city = self._getSpoofedCity(self.server.baseDir,
|
||||
nickname,
|
||||
self.server.domain)
|
||||
messageJson = \
|
||||
createReportPost(self.server.baseDir,
|
||||
nickname,
|
||||
|
|
@ -13534,6 +13607,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
True, False, False, True,
|
||||
filename, attachmentMediaType,
|
||||
fields['imageDescription'],
|
||||
city,
|
||||
self.server.debug, fields['subject'])
|
||||
if messageJson:
|
||||
if self._postToOutbox(messageJson, __version__, nickname):
|
||||
|
|
@ -13553,6 +13627,9 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
str(questionCtr)])
|
||||
if not qOptions:
|
||||
return -1
|
||||
city = self._getSpoofedCity(self.server.baseDir,
|
||||
nickname,
|
||||
self.server.domain)
|
||||
messageJson = \
|
||||
createQuestionPost(self.server.baseDir,
|
||||
nickname,
|
||||
|
|
@ -13564,6 +13641,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
commentsEnabled,
|
||||
filename, attachmentMediaType,
|
||||
fields['imageDescription'],
|
||||
city,
|
||||
fields['subject'],
|
||||
int(fields['duration']))
|
||||
if messageJson:
|
||||
|
|
@ -13588,6 +13666,9 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
if durationStr:
|
||||
if ' ' not in durationStr:
|
||||
durationStr = durationStr + ' days'
|
||||
city = self._getSpoofedCity(self.server.baseDir,
|
||||
nickname,
|
||||
self.server.domain)
|
||||
addShare(self.server.baseDir,
|
||||
self.server.httpPrefix,
|
||||
nickname,
|
||||
|
|
@ -13599,7 +13680,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
fields['category'],
|
||||
fields['location'],
|
||||
durationStr,
|
||||
self.server.debug)
|
||||
self.server.debug,
|
||||
city)
|
||||
if filename:
|
||||
if os.path.isfile(filename):
|
||||
os.remove(filename)
|
||||
|
|
@ -14661,7 +14743,8 @@ def loadTokens(baseDir: str, tokensDict: {}, tokensLookup: {}) -> None:
|
|||
break
|
||||
|
||||
|
||||
def runDaemon(showNodeInfoAccounts: bool,
|
||||
def runDaemon(city: str,
|
||||
showNodeInfoAccounts: bool,
|
||||
showNodeInfoVersion: bool,
|
||||
brochMode: bool,
|
||||
verifyAllSignatures: bool,
|
||||
|
|
@ -14819,6 +14902,9 @@ def runDaemon(showNodeInfoAccounts: bool,
|
|||
print('ERROR: no translations were loaded')
|
||||
sys.exit()
|
||||
|
||||
# spoofed city for gps location misdirection
|
||||
httpd.city = city
|
||||
|
||||
# For moderated newswire feeds this is the amount of time allowed
|
||||
# for voting after the post arrives
|
||||
httpd.votingTimeMins = votingTimeMins
|
||||
|
|
|
|||
|
|
@ -458,6 +458,7 @@ def _desktopReplyToPost(session, postId: str,
|
|||
isArticle = False
|
||||
subject = None
|
||||
commentsEnabled = True
|
||||
city = 'London, England'
|
||||
sayStr = 'Sending reply'
|
||||
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
|
||||
if sendPostViaServer(__version__,
|
||||
|
|
@ -466,7 +467,7 @@ def _desktopReplyToPost(session, postId: str,
|
|||
toNickname, toDomain, toPort, ccUrl,
|
||||
httpPrefix, replyMessage, followersOnly,
|
||||
commentsEnabled, attach, mediaType,
|
||||
attachedImageDescription,
|
||||
attachedImageDescription, city,
|
||||
cachedWebfingers, personCache, isArticle,
|
||||
debug, postId, postId, subject) == 0:
|
||||
sayStr = 'Reply sent'
|
||||
|
|
@ -514,6 +515,7 @@ def _desktopNewPost(session,
|
|||
attach = None
|
||||
mediaType = None
|
||||
attachedImageDescription = None
|
||||
city = 'London, England'
|
||||
isArticle = False
|
||||
subject = None
|
||||
commentsEnabled = True
|
||||
|
|
@ -526,7 +528,7 @@ def _desktopNewPost(session,
|
|||
None, '#Public', port, ccUrl,
|
||||
httpPrefix, newMessage, followersOnly,
|
||||
commentsEnabled, attach, mediaType,
|
||||
attachedImageDescription,
|
||||
attachedImageDescription, city,
|
||||
cachedWebfingers, personCache, isArticle,
|
||||
debug, None, None, subject) == 0:
|
||||
sayStr = 'Post sent'
|
||||
|
|
@ -1158,6 +1160,7 @@ def _desktopNewDMbase(session, toHandle: str,
|
|||
attach = None
|
||||
mediaType = None
|
||||
attachedImageDescription = None
|
||||
city = 'London, England'
|
||||
isArticle = False
|
||||
subject = None
|
||||
commentsEnabled = True
|
||||
|
|
@ -1206,7 +1209,7 @@ def _desktopNewDMbase(session, toHandle: str,
|
|||
toNickname, toDomain, toPort, ccUrl,
|
||||
httpPrefix, newMessage, followersOnly,
|
||||
commentsEnabled, attach, mediaType,
|
||||
attachedImageDescription,
|
||||
attachedImageDescription, city,
|
||||
cachedWebfingers, personCache, isArticle,
|
||||
debug, None, None, subject) == 0:
|
||||
sayStr = 'Direct message sent'
|
||||
|
|
|
|||
|
|
@ -762,5 +762,6 @@
|
|||
"talkingemote2": "talkingEmote2",
|
||||
"veryhappyemote": "veryHappyEmote",
|
||||
"worriedemote": "worriedEmote",
|
||||
"tor": "tor"
|
||||
"tor": "tor",
|
||||
"pine64": "pine64"
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
43
epicyon.py
43
epicyon.py
|
|
@ -464,6 +464,9 @@ parser.add_argument('--attach', dest='attach', type=str,
|
|||
default=None, help='File to attach to a post')
|
||||
parser.add_argument('--imagedescription', dest='imageDescription', type=str,
|
||||
default=None, help='Description of an attached image')
|
||||
parser.add_argument('--city', dest='city', type=str,
|
||||
default='London, England',
|
||||
help='Spoofed city for image metadata misdirection')
|
||||
parser.add_argument('--warning', '--warn', '--cwsubject', '--subject',
|
||||
dest='subject', type=str, default=None,
|
||||
help='Subject of content warning')
|
||||
|
|
@ -1110,6 +1113,7 @@ if args.message:
|
|||
followersOnly = args.followersonly
|
||||
clientToServer = args.client
|
||||
attachedImageDescription = args.imageDescription
|
||||
city = 'London, England'
|
||||
sendThreads = []
|
||||
postLog = []
|
||||
personCache = {}
|
||||
|
|
@ -1130,7 +1134,7 @@ if args.message:
|
|||
toNickname, toDomain, toPort, ccUrl,
|
||||
httpPrefix, sendMessage, followersOnly,
|
||||
args.commentsEnabled, attach, mediaType,
|
||||
attachedImageDescription,
|
||||
attachedImageDescription, city,
|
||||
cachedWebfingers, personCache, isArticle,
|
||||
args.debug, replyTo, replyTo, subject)
|
||||
for i in range(10):
|
||||
|
|
@ -1959,8 +1963,9 @@ if args.avatar:
|
|||
if not args.nickname:
|
||||
print('Specify a nickname with --nickname [name]')
|
||||
sys.exit()
|
||||
city = 'London, England'
|
||||
if setProfileImage(baseDir, httpPrefix, args.nickname, domain,
|
||||
port, args.avatar, 'avatar', '128x128'):
|
||||
port, args.avatar, 'avatar', '128x128', city):
|
||||
print('Avatar added for ' + args.nickname)
|
||||
else:
|
||||
print('Avatar was not added for ' + args.nickname)
|
||||
|
|
@ -1973,8 +1978,10 @@ if args.backgroundImage:
|
|||
if not args.nickname:
|
||||
print('Specify a nickname with --nickname [name]')
|
||||
sys.exit()
|
||||
city = 'London, England'
|
||||
if setProfileImage(baseDir, httpPrefix, args.nickname, domain,
|
||||
port, args.backgroundImage, 'background', '256x256'):
|
||||
port, args.backgroundImage, 'background',
|
||||
'256x256', city):
|
||||
print('Background image added for ' + args.nickname)
|
||||
else:
|
||||
print('Background image was not added for ' + args.nickname)
|
||||
|
|
@ -2347,6 +2354,7 @@ if args.unfilterStr:
|
|||
sys.exit()
|
||||
|
||||
if args.testdata:
|
||||
city = 'London, England'
|
||||
nickname = 'testuser567'
|
||||
password = 'boringpassword'
|
||||
print('Generating some test data for user: ' + nickname)
|
||||
|
|
@ -2394,7 +2402,7 @@ if args.testdata:
|
|||
"mechanical",
|
||||
"City",
|
||||
"2 months",
|
||||
debug)
|
||||
debug, city)
|
||||
addShare(baseDir,
|
||||
httpPrefix, nickname, domain, port,
|
||||
"witch hat",
|
||||
|
|
@ -2404,7 +2412,7 @@ if args.testdata:
|
|||
"clothing",
|
||||
"City",
|
||||
"3 months",
|
||||
debug)
|
||||
debug, city)
|
||||
|
||||
deleteAllPosts(baseDir, nickname, domain, 'inbox')
|
||||
deleteAllPosts(baseDir, nickname, domain, 'outbox')
|
||||
|
|
@ -2416,6 +2424,7 @@ if args.testdata:
|
|||
testAttachImageFilename = None
|
||||
testMediaType = None
|
||||
testImageDescription = None
|
||||
testCity = 'London, England'
|
||||
|
||||
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
|
||||
"like this is totally just a #test man",
|
||||
|
|
@ -2424,7 +2433,7 @@ if args.testdata:
|
|||
testC2S,
|
||||
testCommentsEnabled,
|
||||
testAttachImageFilename,
|
||||
testMediaType, testImageDescription)
|
||||
testMediaType, testImageDescription, testCity)
|
||||
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
|
||||
"Zoiks!!!",
|
||||
testFollowersOnly,
|
||||
|
|
@ -2432,7 +2441,7 @@ if args.testdata:
|
|||
testC2S,
|
||||
testCommentsEnabled,
|
||||
testAttachImageFilename,
|
||||
testMediaType, testImageDescription)
|
||||
testMediaType, testImageDescription, testCity)
|
||||
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
|
||||
"Hey scoob we need like a hundred more #milkshakes",
|
||||
testFollowersOnly,
|
||||
|
|
@ -2440,7 +2449,7 @@ if args.testdata:
|
|||
testC2S,
|
||||
testCommentsEnabled,
|
||||
testAttachImageFilename,
|
||||
testMediaType, testImageDescription)
|
||||
testMediaType, testImageDescription, testCity)
|
||||
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
|
||||
"Getting kinda spooky around here",
|
||||
testFollowersOnly,
|
||||
|
|
@ -2448,7 +2457,7 @@ if args.testdata:
|
|||
testC2S,
|
||||
testCommentsEnabled,
|
||||
testAttachImageFilename,
|
||||
testMediaType, testImageDescription,
|
||||
testMediaType, testImageDescription, testCity,
|
||||
'someone')
|
||||
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
|
||||
"And they would have gotten away with it too" +
|
||||
|
|
@ -2458,7 +2467,7 @@ if args.testdata:
|
|||
testC2S,
|
||||
testCommentsEnabled,
|
||||
'img/logo.png', 'image/png',
|
||||
'Description of image')
|
||||
'Description of image', testCity)
|
||||
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
|
||||
"man these centralized sites are like the worst!",
|
||||
testFollowersOnly,
|
||||
|
|
@ -2466,7 +2475,7 @@ if args.testdata:
|
|||
testC2S,
|
||||
testCommentsEnabled,
|
||||
testAttachImageFilename,
|
||||
testMediaType, testImageDescription)
|
||||
testMediaType, testImageDescription, testCity)
|
||||
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
|
||||
"another mystery solved #test",
|
||||
testFollowersOnly,
|
||||
|
|
@ -2474,7 +2483,7 @@ if args.testdata:
|
|||
testC2S,
|
||||
testCommentsEnabled,
|
||||
testAttachImageFilename,
|
||||
testMediaType, testImageDescription)
|
||||
testMediaType, testImageDescription, testCity)
|
||||
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
|
||||
"let's go bowling",
|
||||
testFollowersOnly,
|
||||
|
|
@ -2482,7 +2491,7 @@ if args.testdata:
|
|||
testC2S,
|
||||
testCommentsEnabled,
|
||||
testAttachImageFilename,
|
||||
testMediaType, testImageDescription)
|
||||
testMediaType, testImageDescription, testCity)
|
||||
|
||||
domainFull = domain + ':' + str(port)
|
||||
clearFollows(baseDir, nickname, domain)
|
||||
|
|
@ -2620,6 +2629,11 @@ showNodeInfoVersion = \
|
|||
if showNodeInfoVersion is not None:
|
||||
args.showNodeInfoVersion = bool(showNodeInfoVersion)
|
||||
|
||||
city = \
|
||||
getConfigParam(baseDir, 'city')
|
||||
if city is not None:
|
||||
args.city = city
|
||||
|
||||
YTDomain = getConfigParam(baseDir, 'youtubedomain')
|
||||
if YTDomain:
|
||||
if '://' in YTDomain:
|
||||
|
|
@ -2634,7 +2648,8 @@ if setTheme(baseDir, themeName, domain,
|
|||
print('Theme set to ' + themeName)
|
||||
|
||||
if __name__ == "__main__":
|
||||
runDaemon(args.showNodeInfoAccounts,
|
||||
runDaemon(args.city,
|
||||
args.showNodeInfoAccounts,
|
||||
args.showNodeInfoVersion,
|
||||
args.brochMode,
|
||||
args.verifyAllSignatures,
|
||||
|
|
|
|||
3
inbox.py
3
inbox.py
|
|
@ -2183,6 +2183,7 @@ def _bounceDM(senderPostId: str, session, httpPrefix: str,
|
|||
attachImageFilename = None
|
||||
mediaType = None
|
||||
imageDescription = ''
|
||||
city = 'London, England'
|
||||
inReplyTo = removeIdEnding(senderPostId)
|
||||
inReplyToAtomUri = None
|
||||
schedulePost = False
|
||||
|
|
@ -2195,7 +2196,7 @@ def _bounceDM(senderPostId: str, session, httpPrefix: str,
|
|||
saveToFile, clientToServer,
|
||||
commentsEnabled,
|
||||
attachImageFilename, mediaType,
|
||||
imageDescription,
|
||||
imageDescription, city,
|
||||
inReplyTo, inReplyToAtomUri,
|
||||
subject, debug, schedulePost,
|
||||
eventDate, eventTime, location)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
209
media.py
209
media.py
|
|
@ -8,6 +8,9 @@ __status__ = "Production"
|
|||
|
||||
import os
|
||||
import datetime
|
||||
import random
|
||||
import math
|
||||
from random import randint
|
||||
from hashlib import sha1
|
||||
from auth import createPassword
|
||||
from utils import getFullDomain
|
||||
|
|
@ -37,7 +40,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 +56,201 @@ def removeMetaData(imageFilename: str, outputFilename: str) -> None:
|
|||
os.system('/usr/bin/mogrify -strip ' + outputFilename) # nosec
|
||||
|
||||
|
||||
def _getCityPulse(currTimeOfDay, decoySeed: int) -> (float, float):
|
||||
"""The data decoy
|
||||
This simulates expected average patterns of movement in a city.
|
||||
Jane or Joe average lives and works in the city, commuting in
|
||||
and out of the central district for work. They have a unique
|
||||
life pattern, which machine learning can latch onto.
|
||||
This returns a polar coordinate:
|
||||
Distance from the city centre is in the range 0.0 - 1.0
|
||||
Angle is in radians
|
||||
"""
|
||||
randgen = random.Random(decoySeed)
|
||||
variance = 3
|
||||
busyStates = ("work", "shop", "play", "party")
|
||||
dataDecoyState = "sleep"
|
||||
dataDecoyIndex = 0
|
||||
weekday = currTimeOfDay.weekday()
|
||||
minHour = 7 + randint(0, variance)
|
||||
maxHour = 17 + randint(0, variance)
|
||||
if currTimeOfDay.hour > minHour:
|
||||
if currTimeOfDay.hour <= maxHour:
|
||||
if weekday < 5:
|
||||
dataDecoyState = "work"
|
||||
dataDecoyIndex = 1
|
||||
elif weekday == 5:
|
||||
dataDecoyState = "shop"
|
||||
dataDecoyIndex = 2
|
||||
else:
|
||||
dataDecoyState = "play"
|
||||
dataDecoyIndex = 3
|
||||
else:
|
||||
if weekday < 5:
|
||||
dataDecoyState = "evening"
|
||||
dataDecoyIndex = 4
|
||||
else:
|
||||
dataDecoyState = "party"
|
||||
dataDecoyIndex = 5
|
||||
angleRadians = \
|
||||
(randgen.randint(0, 100000 - 5 + dataDecoyIndex) / 100000) * \
|
||||
2 * math.pi
|
||||
# some people are quite random, others have more predictable habits
|
||||
decoyRandomness = randgen.randint(1, 3)
|
||||
# occasionally throw in a wildcard to keep the machine learning guessing
|
||||
if randint(0, 100) < decoyRandomness:
|
||||
distanceFromCityCenter = (randint(0, 100000) / 100000)
|
||||
angleRadians = (randint(0, 100000) / 100000) * 2 * math.pi
|
||||
else:
|
||||
# what consitutes the central district is fuzzy
|
||||
centralDistrictFuzz = (randgen.randint(0, 100000) / 100000) * 0.1
|
||||
busyRadius = 0.3 + centralDistrictFuzz
|
||||
if dataDecoyState in busyStates:
|
||||
# if we are busy then we're somewhere in the city center
|
||||
distanceFromCityCenter = \
|
||||
(randgen.randint(0, 100000) / 100000) * busyRadius
|
||||
else:
|
||||
# otherwise we're in the burbs
|
||||
distanceFromCityCenter = busyRadius + \
|
||||
((1.0 - busyRadius) * (randgen.randint(0, 100000) / 100000))
|
||||
return distanceFromCityCenter, angleRadians
|
||||
|
||||
|
||||
def spoofGeolocation(baseDir: str,
|
||||
city: str, currTime, decoySeed: int,
|
||||
citiesList: []) -> (float, float, str, str):
|
||||
"""Given a city and the current time spoofs the location
|
||||
for an image
|
||||
returns latitude, longitude, N/S, E/W
|
||||
"""
|
||||
locationsFilename = baseDir + '/custom_locations.txt'
|
||||
if not os.path.isfile(locationsFilename):
|
||||
locationsFilename = baseDir + '/locations.txt'
|
||||
cityRadius = 0.1
|
||||
variance = 0.001
|
||||
default_latitude = 51.8744
|
||||
default_longitude = 0.368333
|
||||
default_latdirection = 'N'
|
||||
default_longdirection = 'W'
|
||||
|
||||
if citiesList:
|
||||
cities = citiesList
|
||||
else:
|
||||
if not os.path.isfile(locationsFilename):
|
||||
return (default_latitude, default_longitude,
|
||||
default_latdirection, default_longdirection)
|
||||
cities = []
|
||||
with open(locationsFilename, "r") as f:
|
||||
cities = f.readlines()
|
||||
|
||||
city = city.lower()
|
||||
for cityName in cities:
|
||||
if city in cityName.lower():
|
||||
latitude = cityName.split(':')[1]
|
||||
longitude = cityName.split(':')[2]
|
||||
latdirection = 'N'
|
||||
longdirection = 'E'
|
||||
if 'S' in latitude:
|
||||
latdirection = 'S'
|
||||
latitude = latitude.replace('S', '')
|
||||
if 'W' in longitude:
|
||||
longdirection = 'W'
|
||||
longitude = longitude.replace('W', '')
|
||||
latitude = float(latitude)
|
||||
longitude = float(longitude)
|
||||
# get the time of day at the city
|
||||
approxTimeZone = int(longitude / 15.0)
|
||||
if longdirection == 'E':
|
||||
approxTimeZone = -approxTimeZone
|
||||
currTimeAdjusted = currTime - \
|
||||
datetime.timedelta(hours=approxTimeZone)
|
||||
# patterns of activity change in the city over time
|
||||
(distanceFromCityCenter, angleRadians) = \
|
||||
_getCityPulse(currTimeAdjusted, decoySeed)
|
||||
# Get the position within the city, with some randomness added
|
||||
latitude += \
|
||||
distanceFromCityCenter * cityRadius * math.cos(angleRadians)
|
||||
# add a small amount of variance around the location
|
||||
fraction = randint(0, 100000) / 100000
|
||||
latitude += (fraction * fraction * variance) - (variance / 2.0)
|
||||
|
||||
longitude += \
|
||||
distanceFromCityCenter * cityRadius * math.sin(angleRadians)
|
||||
# add a small amount of variance around the location
|
||||
fraction = randint(0, 100000) / 100000
|
||||
longitude += (fraction * fraction * variance) - (variance / 2.0)
|
||||
|
||||
# gps locations aren't transcendental, so round to a fixed
|
||||
# number of decimal places
|
||||
latitude = int(latitude * 10000) / 10000.0
|
||||
longitude = int(longitude * 10000) / 10000.0
|
||||
return latitude, longitude, latdirection, longdirection
|
||||
|
||||
return (default_latitude, default_longitude,
|
||||
default_latdirection, default_longdirection)
|
||||
|
||||
|
||||
def _spoofMetaData(baseDir: str, nickname: str, domain: str,
|
||||
outputFilename: str, spoofCity: str) -> None:
|
||||
"""Spoof image metadata using a decoy model for a given city
|
||||
"""
|
||||
if not os.path.isfile(outputFilename):
|
||||
print('ERROR: unable to spoof metadata within ' + outputFilename)
|
||||
return
|
||||
|
||||
# get the random seed used to generate a unique pattern for this account
|
||||
decoySeedFilename = \
|
||||
baseDir + '/accounts/' + nickname + '@' + domain + '/decoyseed'
|
||||
decoySeed = 63725
|
||||
if os.path.isfile(decoySeedFilename):
|
||||
with open(decoySeedFilename, 'r') as fp:
|
||||
decoySeed = int(fp.read())
|
||||
else:
|
||||
decoySeed = randint(10000, 10000000000000000)
|
||||
try:
|
||||
with open(decoySeedFilename, 'w+') as fp:
|
||||
fp.write(str(decoySeed))
|
||||
except BaseException:
|
||||
pass
|
||||
|
||||
if os.path.isfile('/usr/bin/exiftool'):
|
||||
print('Spoofing metadata in ' + outputFilename + ' using exiftool')
|
||||
currTimeAdjusted = \
|
||||
datetime.datetime.utcnow() - \
|
||||
datetime.timedelta(minutes=randint(2, 120))
|
||||
published = currTimeAdjusted.strftime("%Y:%m:%d %H:%M:%S+00:00")
|
||||
(latitude, longitude, latitudeRef, longitudeRef) = \
|
||||
spoofGeolocation(baseDir, spoofCity, currTimeAdjusted,
|
||||
decoySeed, None)
|
||||
os.system('exiftool -artist="' + nickname + '" ' +
|
||||
'-DateTimeOriginal="' + published + '" ' +
|
||||
'-FileModifyDate="' + published + '" ' +
|
||||
'-CreateDate="' + published + '" ' +
|
||||
'-GPSLongitudeRef=' + longitudeRef + ' ' +
|
||||
'-GPSAltitude=0 ' +
|
||||
'-GPSLongitude=' + str(longitude) + ' ' +
|
||||
'-GPSLatitudeRef=' + latitudeRef + ' ' +
|
||||
'-GPSLatitude=' + str(latitude) + ' ' +
|
||||
'-Comment="" ' +
|
||||
outputFilename) # nosec
|
||||
else:
|
||||
print('ERROR: exiftool is not installed')
|
||||
return
|
||||
|
||||
|
||||
def processMetaData(baseDir: str, nickname: str, domain: str,
|
||||
imageFilename: str, outputFilename: str,
|
||||
city: str) -> None:
|
||||
"""Handles image metadata. This tries to spoof the metadata
|
||||
if possible, but otherwise just removes it
|
||||
"""
|
||||
# first remove the metadata
|
||||
_removeMetaData(imageFilename, outputFilename)
|
||||
|
||||
# now add some spoofed data to misdirect surveillance capitalists
|
||||
_spoofMetaData(baseDir, nickname, domain, outputFilename, city)
|
||||
|
||||
|
||||
def _isMedia(imageFilename: str) -> bool:
|
||||
"""Is the given file a media file?
|
||||
"""
|
||||
|
|
@ -131,9 +329,11 @@ 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) -> {}:
|
||||
mediaType: str, description: str,
|
||||
city: str) -> {}:
|
||||
"""Attaches media to a json object post
|
||||
The description can be None
|
||||
"""
|
||||
|
|
@ -179,7 +379,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, city)
|
||||
else:
|
||||
copyfile(imageFilename, mediaFilename)
|
||||
_updateEtag(mediaFilename)
|
||||
|
|
|
|||
|
|
@ -527,11 +527,17 @@ def _convertRSStoActivityPub(baseDir: str, httpPrefix: str,
|
|||
# NOTE: the id when the post is created will not be
|
||||
# consistent (it's based on the current time, not the
|
||||
# published time), so we change that later
|
||||
saveToFile = False
|
||||
attachImageFilename = None
|
||||
mediaType = None
|
||||
imageDescription = None
|
||||
city = 'London, England'
|
||||
blog = createNewsPost(baseDir,
|
||||
domain, port, httpPrefix,
|
||||
rssDescription,
|
||||
followersOnly, False,
|
||||
None, None, None,
|
||||
followersOnly, saveToFile,
|
||||
attachImageFilename, mediaType,
|
||||
imageDescription, city,
|
||||
rssTitle)
|
||||
if not blog:
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -176,7 +176,8 @@ def postMessageToOutbox(session, translate: {},
|
|||
proxyType: str, version: str, debug: bool,
|
||||
YTReplacementDomain: str,
|
||||
showPublishedDateOnly: bool,
|
||||
allowLocalNetworkAccess: bool) -> bool:
|
||||
allowLocalNetworkAccess: bool,
|
||||
city: str) -> bool:
|
||||
"""post is received by the outbox
|
||||
Client to server message post
|
||||
https://www.w3.org/TR/activitypub/#client-to-server-outbox-delivery
|
||||
|
|
@ -545,7 +546,7 @@ def postMessageToOutbox(session, translate: {},
|
|||
print('DEBUG: handle share uploads')
|
||||
outboxShareUpload(baseDir, httpPrefix,
|
||||
postToNickname, domain,
|
||||
port, messageJson, debug)
|
||||
port, messageJson, debug, city)
|
||||
|
||||
if debug:
|
||||
print('DEBUG: handle undo share uploads')
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -74,7 +74,7 @@ def generateRSAKey() -> (str, str):
|
|||
|
||||
def setProfileImage(baseDir: str, httpPrefix: str, nickname: str, domain: str,
|
||||
port: int, imageFilename: str, imageType: str,
|
||||
resolution: str) -> bool:
|
||||
resolution: str, city: str) -> bool:
|
||||
"""Saves the given image file as an avatar or background
|
||||
image for the given person
|
||||
"""
|
||||
|
|
@ -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, city)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
|
|
|||
77
posts.py
77
posts.py
|
|
@ -867,7 +867,7 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
|
|||
followersOnly: bool, saveToFile: bool,
|
||||
clientToServer: bool, commentsEnabled: bool,
|
||||
attachImageFilename: str,
|
||||
mediaType: str, imageDescription: str,
|
||||
mediaType: str, imageDescription: str, city: str,
|
||||
isModerationReport: bool,
|
||||
isArticle: bool,
|
||||
inReplyTo=None,
|
||||
|
|
@ -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,9 +1105,9 @@ 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)
|
||||
mediaType, imageDescription, city)
|
||||
_appendEventFields(newPost['object'], eventUUID, eventStatus,
|
||||
anonymousParticipationEnabled,
|
||||
repliesModerationOption,
|
||||
|
|
@ -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,9 +1155,9 @@ 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)
|
||||
mediaType, imageDescription, city)
|
||||
_appendEventFields(newPost, eventUUID, eventStatus,
|
||||
anonymousParticipationEnabled,
|
||||
repliesModerationOption,
|
||||
|
|
@ -1391,7 +1397,7 @@ def createPublicPost(baseDir: str,
|
|||
content: str, followersOnly: bool, saveToFile: bool,
|
||||
clientToServer: bool, commentsEnabled: bool,
|
||||
attachImageFilename: str, mediaType: str,
|
||||
imageDescription: str,
|
||||
imageDescription: str, city: str,
|
||||
inReplyTo=None, inReplyToAtomUri=None, subject=None,
|
||||
schedulePost=False,
|
||||
eventDate=None, eventTime=None, location=None,
|
||||
|
|
@ -1417,7 +1423,7 @@ def createPublicPost(baseDir: str,
|
|||
httpPrefix, content, followersOnly, saveToFile,
|
||||
clientToServer, commentsEnabled,
|
||||
attachImageFilename, mediaType,
|
||||
imageDescription,
|
||||
imageDescription, city,
|
||||
isModerationReport, isArticle,
|
||||
inReplyTo, inReplyToAtomUri, subject,
|
||||
schedulePost, eventDate, eventTime, location,
|
||||
|
|
@ -1464,7 +1470,7 @@ def createBlogPost(baseDir: str,
|
|||
content: str, followersOnly: bool, saveToFile: bool,
|
||||
clientToServer: bool, commentsEnabled: bool,
|
||||
attachImageFilename: str, mediaType: str,
|
||||
imageDescription: str,
|
||||
imageDescription: str, city: str,
|
||||
inReplyTo=None, inReplyToAtomUri=None, subject=None,
|
||||
schedulePost=False,
|
||||
eventDate=None, eventTime=None, location=None) -> {}:
|
||||
|
|
@ -1474,7 +1480,7 @@ def createBlogPost(baseDir: str,
|
|||
content, followersOnly, saveToFile,
|
||||
clientToServer, commentsEnabled,
|
||||
attachImageFilename, mediaType,
|
||||
imageDescription,
|
||||
imageDescription, city,
|
||||
inReplyTo, inReplyToAtomUri, subject,
|
||||
schedulePost,
|
||||
eventDate, eventTime, location, True)
|
||||
|
|
@ -1489,7 +1495,7 @@ def createNewsPost(baseDir: str,
|
|||
domain: str, port: int, httpPrefix: str,
|
||||
content: str, followersOnly: bool, saveToFile: bool,
|
||||
attachImageFilename: str, mediaType: str,
|
||||
imageDescription: str,
|
||||
imageDescription: str, city: str,
|
||||
subject: str) -> {}:
|
||||
clientToServer = False
|
||||
inReplyTo = None
|
||||
|
|
@ -1504,7 +1510,7 @@ def createNewsPost(baseDir: str,
|
|||
content, followersOnly, saveToFile,
|
||||
clientToServer, False,
|
||||
attachImageFilename, mediaType,
|
||||
imageDescription,
|
||||
imageDescription, city,
|
||||
inReplyTo, inReplyToAtomUri, subject,
|
||||
schedulePost,
|
||||
eventDate, eventTime, location, True)
|
||||
|
|
@ -1518,7 +1524,7 @@ def createQuestionPost(baseDir: str,
|
|||
followersOnly: bool, saveToFile: bool,
|
||||
clientToServer: bool, commentsEnabled: bool,
|
||||
attachImageFilename: str, mediaType: str,
|
||||
imageDescription: str,
|
||||
imageDescription: str, city: str,
|
||||
subject: str, durationDays: int) -> {}:
|
||||
"""Question post with multiple choice options
|
||||
"""
|
||||
|
|
@ -1531,7 +1537,7 @@ def createQuestionPost(baseDir: str,
|
|||
httpPrefix, content, followersOnly, saveToFile,
|
||||
clientToServer, commentsEnabled,
|
||||
attachImageFilename, mediaType,
|
||||
imageDescription,
|
||||
imageDescription, city,
|
||||
False, False, None, None, subject,
|
||||
False, None, None, None, None, None,
|
||||
None, None, None,
|
||||
|
|
@ -1562,7 +1568,7 @@ def createUnlistedPost(baseDir: str,
|
|||
content: str, followersOnly: bool, saveToFile: bool,
|
||||
clientToServer: bool, commentsEnabled: bool,
|
||||
attachImageFilename: str, mediaType: str,
|
||||
imageDescription: str,
|
||||
imageDescription: str, city: str,
|
||||
inReplyTo=None, inReplyToAtomUri=None, subject=None,
|
||||
schedulePost=False,
|
||||
eventDate=None, eventTime=None, location=None) -> {}:
|
||||
|
|
@ -1576,8 +1582,9 @@ def createUnlistedPost(baseDir: str,
|
|||
httpPrefix, content, followersOnly, saveToFile,
|
||||
clientToServer, commentsEnabled,
|
||||
attachImageFilename, mediaType,
|
||||
imageDescription,
|
||||
False, False, inReplyTo, inReplyToAtomUri, subject,
|
||||
imageDescription, city,
|
||||
False, False,
|
||||
inReplyTo, inReplyToAtomUri, subject,
|
||||
schedulePost, eventDate, eventTime, location,
|
||||
None, None, None, None, None,
|
||||
None, None, None, None, None)
|
||||
|
|
@ -1590,7 +1597,7 @@ def createFollowersOnlyPost(baseDir: str,
|
|||
saveToFile: bool,
|
||||
clientToServer: bool, commentsEnabled: bool,
|
||||
attachImageFilename: str, mediaType: str,
|
||||
imageDescription: str,
|
||||
imageDescription: str, city: str,
|
||||
inReplyTo=None, inReplyToAtomUri=None,
|
||||
subject=None, schedulePost=False,
|
||||
eventDate=None, eventTime=None,
|
||||
|
|
@ -1605,8 +1612,9 @@ def createFollowersOnlyPost(baseDir: str,
|
|||
httpPrefix, content, followersOnly, saveToFile,
|
||||
clientToServer, commentsEnabled,
|
||||
attachImageFilename, mediaType,
|
||||
imageDescription,
|
||||
False, False, inReplyTo, inReplyToAtomUri, subject,
|
||||
imageDescription, city,
|
||||
False, False,
|
||||
inReplyTo, inReplyToAtomUri, subject,
|
||||
schedulePost, eventDate, eventTime, location,
|
||||
None, None, None, None, None,
|
||||
None, None, None, None, None)
|
||||
|
|
@ -1619,7 +1627,7 @@ def createEventPost(baseDir: str,
|
|||
saveToFile: bool,
|
||||
clientToServer: bool, commentsEnabled: bool,
|
||||
attachImageFilename: str, mediaType: str,
|
||||
imageDescription: str,
|
||||
imageDescription: str, city: str,
|
||||
subject=None, schedulePost=False,
|
||||
eventDate=None, eventTime=None,
|
||||
location=None, category=None, joinMode=None,
|
||||
|
|
@ -1652,7 +1660,7 @@ def createEventPost(baseDir: str,
|
|||
httpPrefix, content, followersOnly, saveToFile,
|
||||
clientToServer, commentsEnabled,
|
||||
attachImageFilename, mediaType,
|
||||
imageDescription,
|
||||
imageDescription, city,
|
||||
False, False, None, None, subject,
|
||||
schedulePost, eventDate, eventTime, location,
|
||||
eventUUID, category, joinMode,
|
||||
|
|
@ -1704,7 +1712,7 @@ def createDirectMessagePost(baseDir: str,
|
|||
saveToFile: bool, clientToServer: bool,
|
||||
commentsEnabled: bool,
|
||||
attachImageFilename: str, mediaType: str,
|
||||
imageDescription: str,
|
||||
imageDescription: str, city: str,
|
||||
inReplyTo=None, inReplyToAtomUri=None,
|
||||
subject=None, debug=False,
|
||||
schedulePost=False,
|
||||
|
|
@ -1727,8 +1735,9 @@ def createDirectMessagePost(baseDir: str,
|
|||
httpPrefix, content, followersOnly, saveToFile,
|
||||
clientToServer, commentsEnabled,
|
||||
attachImageFilename, mediaType,
|
||||
imageDescription,
|
||||
False, False, inReplyTo, inReplyToAtomUri, subject,
|
||||
imageDescription, city,
|
||||
False, False,
|
||||
inReplyTo, inReplyToAtomUri, subject,
|
||||
schedulePost, eventDate, eventTime, location,
|
||||
None, None, None, None, None,
|
||||
None, None, None, None, None)
|
||||
|
|
@ -1748,7 +1757,7 @@ def createReportPost(baseDir: str,
|
|||
content: str, followersOnly: bool, saveToFile: bool,
|
||||
clientToServer: bool, commentsEnabled: bool,
|
||||
attachImageFilename: str, mediaType: str,
|
||||
imageDescription: str,
|
||||
imageDescription: str, city: str,
|
||||
debug: bool, subject=None) -> {}:
|
||||
"""Send a report to moderators
|
||||
"""
|
||||
|
|
@ -1817,7 +1826,7 @@ def createReportPost(baseDir: str,
|
|||
httpPrefix, content, followersOnly, saveToFile,
|
||||
clientToServer, commentsEnabled,
|
||||
attachImageFilename, mediaType,
|
||||
imageDescription,
|
||||
imageDescription, city,
|
||||
True, False, None, None, subject,
|
||||
False, None, None, None, None, None,
|
||||
None, None, None,
|
||||
|
|
@ -1902,7 +1911,7 @@ def sendPost(projectVersion: str,
|
|||
saveToFile: bool, clientToServer: bool,
|
||||
commentsEnabled: bool,
|
||||
attachImageFilename: str, mediaType: str,
|
||||
imageDescription: str,
|
||||
imageDescription: str, city: str,
|
||||
federationList: [], sendThreads: [], postLog: [],
|
||||
cachedWebfingers: {}, personCache: {},
|
||||
isArticle: bool,
|
||||
|
|
@ -1961,7 +1970,7 @@ def sendPost(projectVersion: str,
|
|||
followersOnly, saveToFile, clientToServer,
|
||||
commentsEnabled,
|
||||
attachImageFilename, mediaType,
|
||||
imageDescription,
|
||||
imageDescription, city,
|
||||
False, isArticle, inReplyTo,
|
||||
inReplyToAtomUri, subject,
|
||||
False, None, None, None, None, None,
|
||||
|
|
@ -2023,7 +2032,7 @@ def sendPostViaServer(projectVersion: str,
|
|||
httpPrefix: str, content: str, followersOnly: bool,
|
||||
commentsEnabled: bool,
|
||||
attachImageFilename: str, mediaType: str,
|
||||
imageDescription: str,
|
||||
imageDescription: str, city: str,
|
||||
cachedWebfingers: {}, personCache: {},
|
||||
isArticle: bool, debug=False, inReplyTo=None,
|
||||
inReplyToAtomUri=None, subject=None) -> int:
|
||||
|
|
@ -2100,7 +2109,7 @@ def sendPostViaServer(projectVersion: str,
|
|||
followersOnly, saveToFile, clientToServer,
|
||||
commentsEnabled,
|
||||
attachImageFilename, mediaType,
|
||||
imageDescription,
|
||||
imageDescription, city,
|
||||
False, isArticle, inReplyTo,
|
||||
inReplyToAtomUri, subject,
|
||||
False, None, None, None, None, None,
|
||||
|
|
|
|||
|
|
@ -108,7 +108,8 @@ def _updatePostSchedule(baseDir: str, handle: str, httpd,
|
|||
httpd.debug,
|
||||
httpd.YTReplacementDomain,
|
||||
httpd.showPublishedDateOnly,
|
||||
httpd.allowLocalNetworkAccess):
|
||||
httpd.allowLocalNetworkAccess,
|
||||
httpd.city):
|
||||
indexLines.remove(line)
|
||||
os.remove(postFilename)
|
||||
continue
|
||||
|
|
|
|||
12
shares.py
12
shares.py
|
|
@ -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:
|
||||
|
|
@ -73,7 +73,7 @@ def addShare(baseDir: str,
|
|||
httpPrefix: str, nickname: str, domain: str, port: int,
|
||||
displayName: str, summary: str, imageFilename: str,
|
||||
itemType: str, itemCategory: str, location: str,
|
||||
duration: str, debug: bool) -> None:
|
||||
duration: str, debug: bool, city: str) -> None:
|
||||
"""Adds a new share
|
||||
"""
|
||||
sharesFilename = baseDir + '/accounts/' + \
|
||||
|
|
@ -129,7 +129,9 @@ 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,
|
||||
city)
|
||||
if moveImage:
|
||||
os.remove(imageFilename)
|
||||
imageUrl = \
|
||||
|
|
@ -512,7 +514,7 @@ def sendUndoShareViaServer(baseDir: str, session,
|
|||
|
||||
def outboxShareUpload(baseDir: str, httpPrefix: str,
|
||||
nickname: str, domain: str, port: int,
|
||||
messageJson: {}, debug: bool) -> None:
|
||||
messageJson: {}, debug: bool, city: str) -> None:
|
||||
""" When a shared item is received by the outbox from c2s
|
||||
"""
|
||||
if not messageJson.get('type'):
|
||||
|
|
@ -564,7 +566,7 @@ def outboxShareUpload(baseDir: str, httpPrefix: str,
|
|||
messageJson['object']['itemCategory'],
|
||||
messageJson['object']['location'],
|
||||
messageJson['object']['duration'],
|
||||
debug)
|
||||
debug, city)
|
||||
if debug:
|
||||
print('DEBUG: shared item received via c2s')
|
||||
|
||||
|
|
|
|||
128
tests.py
128
tests.py
|
|
@ -10,6 +10,8 @@ import time
|
|||
import os
|
||||
import shutil
|
||||
import json
|
||||
import datetime
|
||||
from random import randint
|
||||
from time import gmtime, strftime
|
||||
from pprint import pprint
|
||||
from httpsig import signPostHeaders
|
||||
|
|
@ -75,6 +77,7 @@ from like import likePost
|
|||
from like import sendLikeViaServer
|
||||
from announce import announcePublic
|
||||
from announce import sendAnnounceViaServer
|
||||
from media import spoofGeolocation
|
||||
from media import getMediaPath
|
||||
from media import getAttachmentMediaType
|
||||
from delete import sendDeleteViaServer
|
||||
|
|
@ -463,6 +466,7 @@ def createServerAlice(path: str, domain: str, port: int,
|
|||
testAttachImageFilename = None
|
||||
testMediaType = None
|
||||
testImageDescription = None
|
||||
testCity = 'London, England'
|
||||
createPublicPost(path, nickname, domain, port, httpPrefix,
|
||||
"No wise fish would go anywhere without a porpoise",
|
||||
testFollowersOnly,
|
||||
|
|
@ -471,7 +475,7 @@ def createServerAlice(path: str, domain: str, port: int,
|
|||
testCommentsEnabled,
|
||||
testAttachImageFilename,
|
||||
testMediaType,
|
||||
testImageDescription)
|
||||
testImageDescription, testCity)
|
||||
createPublicPost(path, nickname, domain, port, httpPrefix,
|
||||
"Curiouser and curiouser!",
|
||||
testFollowersOnly,
|
||||
|
|
@ -480,7 +484,7 @@ def createServerAlice(path: str, domain: str, port: int,
|
|||
testCommentsEnabled,
|
||||
testAttachImageFilename,
|
||||
testMediaType,
|
||||
testImageDescription)
|
||||
testImageDescription, testCity)
|
||||
createPublicPost(path, nickname, domain, port, httpPrefix,
|
||||
"In the gardens of memory, in the palace " +
|
||||
"of dreams, that is where you and I shall meet",
|
||||
|
|
@ -490,7 +494,7 @@ def createServerAlice(path: str, domain: str, port: int,
|
|||
testCommentsEnabled,
|
||||
testAttachImageFilename,
|
||||
testMediaType,
|
||||
testImageDescription)
|
||||
testImageDescription, testCity)
|
||||
global testServerAliceRunning
|
||||
testServerAliceRunning = True
|
||||
maxMentions = 10
|
||||
|
|
@ -506,8 +510,10 @@ def createServerAlice(path: str, domain: str, port: int,
|
|||
brochMode = False
|
||||
showNodeInfoAccounts = True
|
||||
showNodeInfoVersion = True
|
||||
city = 'London, England'
|
||||
print('Server running: Alice')
|
||||
runDaemon(showNodeInfoAccounts,
|
||||
runDaemon(city,
|
||||
showNodeInfoAccounts,
|
||||
showNodeInfoVersion,
|
||||
brochMode,
|
||||
verifyAllSignatures,
|
||||
|
|
@ -564,6 +570,7 @@ def createServerBob(path: str, domain: str, port: int,
|
|||
testAttachImageFilename = None
|
||||
testImageDescription = None
|
||||
testMediaType = None
|
||||
testCity = 'London, England'
|
||||
createPublicPost(path, nickname, domain, port, httpPrefix,
|
||||
"It's your life, live it your way.",
|
||||
testFollowersOnly,
|
||||
|
|
@ -572,7 +579,7 @@ def createServerBob(path: str, domain: str, port: int,
|
|||
testCommentsEnabled,
|
||||
testAttachImageFilename,
|
||||
testMediaType,
|
||||
testImageDescription)
|
||||
testImageDescription, testCity)
|
||||
createPublicPost(path, nickname, domain, port, httpPrefix,
|
||||
"One of the things I've realised is that " +
|
||||
"I am very simple",
|
||||
|
|
@ -582,7 +589,7 @@ def createServerBob(path: str, domain: str, port: int,
|
|||
testCommentsEnabled,
|
||||
testAttachImageFilename,
|
||||
testMediaType,
|
||||
testImageDescription)
|
||||
testImageDescription, testCity)
|
||||
createPublicPost(path, nickname, domain, port, httpPrefix,
|
||||
"Quantum physics is a bit of a passion of mine",
|
||||
testFollowersOnly,
|
||||
|
|
@ -591,7 +598,7 @@ def createServerBob(path: str, domain: str, port: int,
|
|||
testCommentsEnabled,
|
||||
testAttachImageFilename,
|
||||
testMediaType,
|
||||
testImageDescription)
|
||||
testImageDescription, testCity)
|
||||
global testServerBobRunning
|
||||
testServerBobRunning = True
|
||||
maxMentions = 10
|
||||
|
|
@ -607,8 +614,10 @@ def createServerBob(path: str, domain: str, port: int,
|
|||
brochMode = False
|
||||
showNodeInfoAccounts = True
|
||||
showNodeInfoVersion = True
|
||||
city = 'London, England'
|
||||
print('Server running: Bob')
|
||||
runDaemon(showNodeInfoAccounts,
|
||||
runDaemon(city,
|
||||
showNodeInfoAccounts,
|
||||
showNodeInfoVersion,
|
||||
brochMode,
|
||||
verifyAllSignatures,
|
||||
|
|
@ -662,8 +671,10 @@ def createServerEve(path: str, domain: str, port: int, federationList: [],
|
|||
brochMode = False
|
||||
showNodeInfoAccounts = True
|
||||
showNodeInfoVersion = True
|
||||
city = 'London, England'
|
||||
print('Server running: Eve')
|
||||
runDaemon(showNodeInfoAccounts,
|
||||
runDaemon(city,
|
||||
showNodeInfoAccounts,
|
||||
showNodeInfoVersion,
|
||||
brochMode,
|
||||
verifyAllSignatures,
|
||||
|
|
@ -768,6 +779,7 @@ def testPostMessageBetweenServers():
|
|||
mediaType = getAttachmentMediaType(attachedImageFilename)
|
||||
attachedImageDescription = 'Logo'
|
||||
isArticle = False
|
||||
city = 'London, England'
|
||||
# nothing in Alice's outbox
|
||||
outboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/outbox'
|
||||
assert len([name for name in os.listdir(outboxPath)
|
||||
|
|
@ -782,7 +794,7 @@ def testPostMessageBetweenServers():
|
|||
followersOnly,
|
||||
saveToFile, clientToServer, True,
|
||||
attachedImageFilename, mediaType,
|
||||
attachedImageDescription, federationList,
|
||||
attachedImageDescription, city, federationList,
|
||||
aliceSendThreads, alicePostLog, aliceCachedWebfingers,
|
||||
alicePersonCache, isArticle, inReplyTo,
|
||||
inReplyToAtomUri, subject)
|
||||
|
|
@ -1085,13 +1097,14 @@ def testFollowBetweenServers():
|
|||
aliceCachedWebfingers = {}
|
||||
alicePostLog = []
|
||||
isArticle = False
|
||||
city = 'London, England'
|
||||
sendResult = \
|
||||
sendPost(__version__,
|
||||
sessionAlice, aliceDir, 'alice', aliceDomain, alicePort,
|
||||
'bob', bobDomain, bobPort, ccUrl,
|
||||
httpPrefix, 'Alice message', followersOnly, saveToFile,
|
||||
clientToServer, True,
|
||||
None, None, None, federationList,
|
||||
None, None, None, city, federationList,
|
||||
aliceSendThreads, alicePostLog, aliceCachedWebfingers,
|
||||
alicePersonCache, isArticle, inReplyTo,
|
||||
inReplyToAtomUri, subject)
|
||||
|
|
@ -1390,7 +1403,7 @@ def testCreatePerson():
|
|||
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
|
||||
"G'day world!", False, True, clientToServer,
|
||||
True, None, None, None, None,
|
||||
'Not suitable for Vogons')
|
||||
'Not suitable for Vogons', 'London, England')
|
||||
|
||||
os.chdir(currDir)
|
||||
shutil.rmtree(baseDir)
|
||||
|
|
@ -1593,6 +1606,7 @@ def testClientToServer():
|
|||
attachedImageFilename = baseDir + '/img/logo.png'
|
||||
mediaType = getAttachmentMediaType(attachedImageFilename)
|
||||
attachedImageDescription = 'Logo'
|
||||
city = 'London, England'
|
||||
isArticle = False
|
||||
cachedWebfingers = {}
|
||||
personCache = {}
|
||||
|
|
@ -1611,7 +1625,7 @@ def testClientToServer():
|
|||
httpPrefix, 'Sent from my ActivityPub client',
|
||||
followersOnly, True,
|
||||
attachedImageFilename, mediaType,
|
||||
attachedImageDescription,
|
||||
attachedImageDescription, city,
|
||||
cachedWebfingers, personCache, isArticle,
|
||||
True, None, None, None)
|
||||
print('sendResult: ' + str(sendResult))
|
||||
|
|
@ -2822,11 +2836,21 @@ def testReplyToPublicPost() -> None:
|
|||
port = 443
|
||||
httpPrefix = 'https'
|
||||
postId = httpPrefix + '://rat.site/users/ninjarodent/statuses/63746173435'
|
||||
content = "@ninjarodent@rat.site This is a test."
|
||||
followersOnly = False
|
||||
saveToFile = False
|
||||
clientToServer = False
|
||||
commentsEnabled = True
|
||||
attachImageFilename = None
|
||||
mediaType = None
|
||||
imageDescription = 'Some description'
|
||||
city = 'London, England'
|
||||
reply = \
|
||||
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
|
||||
"@ninjarodent@rat.site This is a test.",
|
||||
False, False, False, True,
|
||||
None, None, False, postId)
|
||||
content, followersOnly, saveToFile,
|
||||
clientToServer, commentsEnabled,
|
||||
attachImageFilename, mediaType,
|
||||
imageDescription, city, postId)
|
||||
# print(str(reply))
|
||||
assert reply['object']['content'] == \
|
||||
'<p><span class=\"h-card\">' + \
|
||||
|
|
@ -3244,11 +3268,20 @@ def testLinksWithinPost() -> None:
|
|||
httpPrefix = 'https'
|
||||
content = 'This is a test post with links.\n\n' + \
|
||||
'ftp://ftp.ncdc.noaa.gov/pub/data/ghcn/v4/\n\nhttps://freedombone.net'
|
||||
followersOnly = False
|
||||
saveToFile = False
|
||||
clientToServer = False
|
||||
commentsEnabled = True
|
||||
mediaType = None
|
||||
imageDescription = None
|
||||
city = 'London, England'
|
||||
|
||||
postJsonObject = \
|
||||
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
|
||||
content,
|
||||
False, False, False, True,
|
||||
None, None, False, None)
|
||||
content, followersOnly, saveToFile,
|
||||
clientToServer, commentsEnabled,
|
||||
mediaType, imageDescription, city,
|
||||
False, None)
|
||||
assert postJsonObject['object']['content'] == \
|
||||
'<p>This is a test post with links.<br><br>' + \
|
||||
'<a href="ftp://ftp.ncdc.noaa.gov/pub/data/ghcn/v4/" ' + \
|
||||
|
|
@ -3636,9 +3669,66 @@ def testRemovePostInteractions() -> None:
|
|||
assert not removePostInteractions(postJsonObject, False)
|
||||
|
||||
|
||||
def testSpoofGeolocation() -> None:
|
||||
print('testSpoofGeolocation')
|
||||
citiesList = [
|
||||
'NEW YORK, USA:40.6397:W73.7789',
|
||||
'LOS ANGELES, USA:33.9425:W118.408',
|
||||
'HOUSTON, USA:29.9803:W95.3397',
|
||||
'MANCHESTER, ENGLAND:53.4794892:W2.2451148'
|
||||
]
|
||||
currTime = datetime.datetime.utcnow()
|
||||
decoySeed = 7634681
|
||||
cityRadius = 0.1
|
||||
coords = spoofGeolocation('', 'los angeles', currTime,
|
||||
decoySeed, citiesList)
|
||||
assert coords[0] >= 33.9425 - cityRadius
|
||||
assert coords[0] <= 33.9425 + cityRadius
|
||||
assert coords[1] >= 118.408 - cityRadius
|
||||
assert coords[1] <= 118.408 + cityRadius
|
||||
assert coords[2] == 'N'
|
||||
assert coords[3] == 'W'
|
||||
coords = spoofGeolocation('', 'unknown', currTime,
|
||||
decoySeed, citiesList)
|
||||
assert coords[0] >= 51.8744 - cityRadius
|
||||
assert coords[0] <= 51.8744 + cityRadius
|
||||
assert coords[1] >= 0.368333 - cityRadius
|
||||
assert coords[1] <= 0.368333 + cityRadius
|
||||
assert coords[2] == 'N'
|
||||
assert coords[3] == 'W'
|
||||
kmlStr = '<?xml version="1.0" encoding="UTF-8"?>\n'
|
||||
kmlStr += '<kml xmlns="http://www.opengis.net/kml/2.2">\n'
|
||||
kmlStr += '<Document>\n'
|
||||
for i in range(1000):
|
||||
dayNumber = randint(10, 30)
|
||||
hour = randint(1, 23)
|
||||
hourStr = str(hour)
|
||||
if hour < 10:
|
||||
hourStr = '0' + hourStr
|
||||
currTime = datetime.datetime.strptime("2021-05-" + str(dayNumber) +
|
||||
" " + hourStr + ":14",
|
||||
"%Y-%m-%d %H:%M")
|
||||
coords = spoofGeolocation('', 'manchester, england', currTime,
|
||||
decoySeed, citiesList)
|
||||
kmlStr += '<Placemark id="' + str(i) + '">\n'
|
||||
kmlStr += ' <name>' + str(i) + '</name>\n'
|
||||
kmlStr += ' <Point>\n'
|
||||
kmlStr += ' <coordinates>' + str(-coords[1]) + ',' + \
|
||||
str(coords[0]) + ',0</coordinates>\n'
|
||||
kmlStr += ' </Point>\n'
|
||||
kmlStr += '</Placemark>\n'
|
||||
kmlStr += '</Document>\n'
|
||||
kmlStr += '</kml>'
|
||||
kmlFile = open('unittest_decoy.kml', 'w+')
|
||||
if kmlFile:
|
||||
kmlFile.write(kmlStr)
|
||||
kmlFile.close()
|
||||
|
||||
|
||||
def runAllTests():
|
||||
print('Running tests...')
|
||||
testFunctions()
|
||||
testSpoofGeolocation()
|
||||
testRemovePostInteractions()
|
||||
testExtractPGPPublicKey()
|
||||
testEmojiImages()
|
||||
|
|
|
|||
|
|
@ -440,5 +440,6 @@
|
|||
"These access keys may be used": "قد يتم استخدام مفاتيح الوصول هذه، عادة مع مفتاح ALT + SHIFT + مفتاح ALT +",
|
||||
"Show numbers of accounts within instance metadata": "إظهار عدد الحسابات داخل البيانات الوصفية للمثيلات",
|
||||
"Show version number within instance metadata": "إظهار رقم الإصدار داخل البيانات الوصفية للمثيل",
|
||||
"Joined": "تاريخ الانضمام"
|
||||
"Joined": "تاريخ الانضمام",
|
||||
"City for spoofed GPS image metadata": "مدينة للبيانات الوصفية لصور GPS المخادعة"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,5 +440,6 @@
|
|||
"These access keys may be used": "Es poden utilitzar aquestes tecles d'accés, típicament amb Alt + Maj + tecla o Alt + clau",
|
||||
"Show numbers of accounts within instance metadata": "Mostra el nombre de comptes a les metadades de la instància",
|
||||
"Show version number within instance metadata": "Mostra el número de versió a les metadades de la instància",
|
||||
"Joined": "Data d'unió"
|
||||
"Joined": "Data d'unió",
|
||||
"City for spoofed GPS image metadata": "Ciutat per a metadades d'imatges GPS falsificades"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,5 +440,6 @@
|
|||
"These access keys may be used": "Gellir defnyddio'r allweddi mynediad hyn, fel arfer gyda ALT + Shift + Allwedd Allwedd neu ALT +",
|
||||
"Show numbers of accounts within instance metadata": "Dangos nifer y cyfrifon o fewn metadata",
|
||||
"Show version number within instance metadata": "Dangos rhif y fersiwn o fewn metadata",
|
||||
"Joined": "Dyddiad ymuno"
|
||||
"Joined": "Dyddiad ymuno",
|
||||
"City for spoofed GPS image metadata": "Dinas ar gyfer metadata delwedd GPS spoofed"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,5 +440,6 @@
|
|||
"These access keys may be used": "Diese Zugriffstasten können verwendet werden, typischerweise mit ALT + SHIFT + -Taste oder ALT + -Taste",
|
||||
"Show numbers of accounts within instance metadata": "Anzahl der Konten in Instanzmetadaten anzeigen",
|
||||
"Show version number within instance metadata": "Versionsnummer in Instanzmetadaten anzeigen",
|
||||
"Joined": "Verbundenes Datum"
|
||||
"Joined": "Verbundenes Datum",
|
||||
"City for spoofed GPS image metadata": "Stadt für gefälschte GPS-Bildmetadaten"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,5 +440,6 @@
|
|||
"These access keys may be used": "These access keys may be used, typically with ALT + SHIFT + key or ALT + key",
|
||||
"Show numbers of accounts within instance metadata": "Show numbers of accounts within instance metadata",
|
||||
"Show version number within instance metadata": "Show version number within instance metadata",
|
||||
"Joined": "Joined"
|
||||
"Joined": "Joined",
|
||||
"City for spoofed GPS image metadata": "City for spoofed GPS image metadata"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,5 +440,6 @@
|
|||
"These access keys may be used": "Se pueden usar estas teclas de acceso, típicamente con teclas ALT + MAYÚS + teclas o ALT +",
|
||||
"Show numbers of accounts within instance metadata": "Muestra el número de cuentas dentro de los metadatos de la instancia.",
|
||||
"Show version number within instance metadata": "Mostrar el número de versión dentro de los metadatos de la instancia",
|
||||
"Joined": "Fecha unida"
|
||||
"Joined": "Fecha unida",
|
||||
"City for spoofed GPS image metadata": "Ciudad para metadatos de imagen GPS falsificados"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,5 +440,6 @@
|
|||
"These access keys may be used": "Ces touches d'accès peuvent être utilisées typiquement avec une touche Alt + Maj + ou Alt +",
|
||||
"Show numbers of accounts within instance metadata": "Afficher le nombre de comptes dans les métadonnées de l'instance",
|
||||
"Show version number within instance metadata": "Afficher le numéro de version dans les métadonnées de l'instance",
|
||||
"Joined": "Joint"
|
||||
"Joined": "Joint",
|
||||
"City for spoofed GPS image metadata": "Ville pour les métadonnées d'image GPS falsifiées"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,5 +440,6 @@
|
|||
"These access keys may be used": "Is féidir na heochracha rochtana seo a úsáid, de ghnáth le Alt + Shift + Eochair nó Alt + Eochair",
|
||||
"Show numbers of accounts within instance metadata": "Taispeáin líon na gcuntas laistigh de mheiteashonraí",
|
||||
"Show version number within instance metadata": "Taispeáin uimhir an leagain laistigh de mheiteashonraí",
|
||||
"Joined": "Dáta comhcheangailte"
|
||||
"Joined": "Dáta comhcheangailte",
|
||||
"City for spoofed GPS image metadata": "Cathair le haghaidh meiteashonraí íomhá GPS spoofed"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,5 +440,6 @@
|
|||
"These access keys may be used": "इन एक्सेस कुंजियों का उपयोग किया जा सकता है, आमतौर पर Alt + Shift + कुंजी या Alt + कुंजी के साथ",
|
||||
"Show numbers of accounts within instance metadata": "उदाहरण मेटाडेटा के भीतर खातों की संख्या दिखाएं",
|
||||
"Show version number within instance metadata": "उदाहरण मेटाडेटा के भीतर संस्करण संख्या दिखाएं",
|
||||
"Joined": "दिनांक"
|
||||
"Joined": "दिनांक",
|
||||
"City for spoofed GPS image metadata": "स्पूफ जीपीएस जीपीएस मेटाडेटा के लिए शहर"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,5 +440,6 @@
|
|||
"These access keys may be used": "Questi tasti di accesso possono essere utilizzati, in genere con tasto ALT + MAIUSC + o ALT + Key",
|
||||
"Show numbers of accounts within instance metadata": "Mostra il numero di account all'interno dei metadati dell'istanza",
|
||||
"Show version number within instance metadata": "Mostra il numero di versione nei metadati dell'istanza",
|
||||
"Joined": "Unito"
|
||||
"Joined": "Unito",
|
||||
"City for spoofed GPS image metadata": "Città per metadati di immagini GPS falsificate"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,5 +440,6 @@
|
|||
"These access keys may be used": "これらのアクセスキーは、通常はAlt + Shift +キーまたはAlt +キーを使用して使用できます。",
|
||||
"Show numbers of accounts within instance metadata": "インスタンスメタデータ内のアカウント数を表示する",
|
||||
"Show version number within instance metadata": "インスタンスメタデータ内にバージョン番号を表示する",
|
||||
"Joined": "参加日"
|
||||
"Joined": "参加日",
|
||||
"City for spoofed GPS image metadata": "なりすましGPS画像メタデータの都市"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,5 +440,6 @@
|
|||
"These access keys may be used": "Dibe ku ev keysên gihîştinê bikar bînin, bi gelemperî bi alt + shift + key an alt + key",
|
||||
"Show numbers of accounts within instance metadata": "Di nav metadata mînakê de hejmarên hesaban nîşan bidin",
|
||||
"Show version number within instance metadata": "Di nav metadata mînakê de nimreya guhertoyê nîşan bide",
|
||||
"Joined": "Beşdarbûna Dîrokê"
|
||||
"Joined": "Beşdarbûna Dîrokê",
|
||||
"City for spoofed GPS image metadata": "Bajar ji bo metadata wêneya GPS ya xapînok"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -436,5 +436,6 @@
|
|||
"These access keys may be used": "These access keys may be used, typically with ALT + SHIFT + key or ALT + key",
|
||||
"Show numbers of accounts within instance metadata": "Show numbers of accounts within instance metadata",
|
||||
"Show version number within instance metadata": "Show version number within instance metadata",
|
||||
"Joined": "Joined"
|
||||
"Joined": "Joined",
|
||||
"City for spoofed GPS image metadata": "City for spoofed GPS image metadata"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,5 +440,6 @@
|
|||
"These access keys may be used": "Essas teclas de acesso podem ser usadas, normalmente com tecla Alt + Shift + Key ou Alt +",
|
||||
"Show numbers of accounts within instance metadata": "Mostra o número de contas nos metadados da instância",
|
||||
"Show version number within instance metadata": "Mostrar o número da versão nos metadados da instância",
|
||||
"Joined": "Data juntada"
|
||||
"Joined": "Data juntada",
|
||||
"City for spoofed GPS image metadata": "Cidade para metadados de imagem GPS falsificados"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,5 +440,6 @@
|
|||
"These access keys may be used": "Эти ключевые ключи доступа могут быть использованы, обычно с ALT + Shift + Key или Alt + Key",
|
||||
"Show numbers of accounts within instance metadata": "Показать количество учетных записей в метаданных экземпляра",
|
||||
"Show version number within instance metadata": "Показать номер версии в метаданных экземпляра",
|
||||
"Joined": "Присоединенная дата"
|
||||
"Joined": "Присоединенная дата",
|
||||
"City for spoofed GPS image metadata": "Город для поддельных метаданных изображения GPS"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,5 +440,6 @@
|
|||
"These access keys may be used": "可以使用这些访问密钥,通常使用Alt + Shift +键或ALT +键",
|
||||
"Show numbers of accounts within instance metadata": "显示实例元数据中的帐户数",
|
||||
"Show version number within instance metadata": "在实例元数据中显示版本号",
|
||||
"Joined": "加入日期"
|
||||
"Joined": "加入日期",
|
||||
"City for spoofed GPS image metadata": "欺骗性GPS影像元数据的城市"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1068,7 +1068,7 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
|
|||
domain: str, port: int, httpPrefix: str,
|
||||
defaultTimeline: str, theme: str,
|
||||
peertubeInstances: [],
|
||||
textModeBanner: str) -> str:
|
||||
textModeBanner: str, city: str) -> str:
|
||||
"""Shows the edit profile screen
|
||||
"""
|
||||
imageFormats = getImageFormats()
|
||||
|
|
@ -1770,6 +1770,41 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
|
|||
editProfileForm += '<details><summary class="cw">' + \
|
||||
translate['Filtering and Blocking'] + '</summary>\n'
|
||||
editProfileForm += ' <div class="container">\n'
|
||||
|
||||
editProfileForm += \
|
||||
'<label class="labels">' + \
|
||||
translate['City for spoofed GPS image metadata'] + \
|
||||
'</label><br>\n'
|
||||
|
||||
cityFilename = baseDir + '/accounts/' + \
|
||||
nickname + '@' + domain + '/city.txt'
|
||||
if os.path.isfile(cityFilename):
|
||||
with open(cityFilename, 'r') as fp:
|
||||
city = fp.read().replace('\n', '')
|
||||
locationsFilename = baseDir + '/custom_locations.txt'
|
||||
if not os.path.isfile(locationsFilename):
|
||||
locationsFilename = baseDir + '/locations.txt'
|
||||
cities = []
|
||||
with open(locationsFilename, "r") as f:
|
||||
cities = f.readlines()
|
||||
cities.sort()
|
||||
editProfileForm += ' <select id="cityDropdown" ' + \
|
||||
'name="cityDropdown" class="theme">\n'
|
||||
city = city.lower()
|
||||
for cityName in cities:
|
||||
if ':' not in cityName:
|
||||
continue
|
||||
citySelected = ''
|
||||
cityName = cityName.split(':')[0]
|
||||
cityName = cityName.lower()
|
||||
if city in cityName:
|
||||
citySelected = ' selected'
|
||||
editProfileForm += \
|
||||
' <option value="' + cityName + \
|
||||
'"' + citySelected.title() + '>' + \
|
||||
cityName + '</option>\n'
|
||||
editProfileForm += ' </select><br>\n'
|
||||
|
||||
editProfileForm += \
|
||||
' <b><label class="labels">' + \
|
||||
translate['Filtered words'] + '</label></b>\n'
|
||||
|
|
|
|||
|
|
@ -543,6 +543,8 @@ def getPersonAvatarUrl(baseDir: str, personUrl: str, personCache: {},
|
|||
return None
|
||||
|
||||
# get from locally stored image
|
||||
if not personJson.get('id'):
|
||||
return None
|
||||
actorStr = personJson['id'].replace('/', '-')
|
||||
avatarImagePath = baseDir + '/cache/avatars/' + actorStr
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue