Merge branch 'main' of ssh://code.freedombone.net:2222/bashrc/epicyon

main
Bob Mottram 2021-05-10 16:56:12 +01:00
commit bd46688305
33 changed files with 4902 additions and 274 deletions

216
daemon.py
View File

@ -239,7 +239,7 @@ from content import addHtmlTags
from content import extractMediaInFormPOST from content import extractMediaInFormPOST
from content import saveMediaInFormPOST from content import saveMediaInFormPOST
from content import extractTextFieldsInPOST from content import extractTextFieldsInPOST
from media import removeMetaData from media import processMetaData
from cache import checkForChangedActor from cache import checkForChangedActor
from cache import storePersonInCache from cache import storePersonInCache
from cache import getPersonFromCache from cache import getPersonFromCache
@ -312,6 +312,18 @@ def saveDomainQrcode(baseDir: str, httpPrefix: str,
class PubServer(BaseHTTPRequestHandler): class PubServer(BaseHTTPRequestHandler):
protocol_version = 'HTTP/1.1' 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: def _getInstalceUrl(self, callingDomain: str) -> str:
"""Returns the URL for this instance """Returns the URL for this instance
""" """
@ -420,6 +432,9 @@ class PubServer(BaseHTTPRequestHandler):
eventDate = None eventDate = None
eventTime = None eventTime = None
location = None location = None
city = self._getSpoofedCity(self.server.baseDir,
nickname, self.server.domain)
messageJson = \ messageJson = \
createPublicPost(self.server.baseDir, createPublicPost(self.server.baseDir,
nickname, nickname,
@ -428,7 +443,7 @@ class PubServer(BaseHTTPRequestHandler):
answer, False, False, False, answer, False, False, False,
commentsEnabled, commentsEnabled,
attachImageFilename, mediaType, attachImageFilename, mediaType,
imageDescription, imageDescription, city,
inReplyTo, inReplyTo,
inReplyToAtomUri, inReplyToAtomUri,
subject, subject,
@ -1144,9 +1159,13 @@ class PubServer(BaseHTTPRequestHandler):
Client to server message post Client to server message post
https://www.w3.org/TR/activitypub/#client-to-server-outbox-delivery https://www.w3.org/TR/activitypub/#client-to-server-outbox-delivery
""" """
city = self.server.city
if postToNickname: if postToNickname:
print('Posting to nickname ' + postToNickname) print('Posting to nickname ' + postToNickname)
self.postToNickname = postToNickname self.postToNickname = postToNickname
city = self._getSpoofedCity(self.server.baseDir,
postToNickname, self.server.domain)
return postMessageToOutbox(self.server.session, return postMessageToOutbox(self.server.session,
self.server.translate, self.server.translate,
@ -1170,7 +1189,8 @@ class PubServer(BaseHTTPRequestHandler):
self.server.debug, self.server.debug,
self.server.YTReplacementDomain, self.server.YTReplacementDomain,
self.server.showPublishedDateOnly, self.server.showPublishedDateOnly,
self.server.allowLocalNetworkAccess) self.server.allowLocalNetworkAccess,
city)
def _postToOutboxThread(self, messageJson: {}) -> bool: def _postToOutboxThread(self, messageJson: {}) -> bool:
"""Creates a thread to send a post """Creates a thread to send a post
@ -4075,7 +4095,11 @@ class PubServer(BaseHTTPRequestHandler):
os.remove(postImageFilename + '.etag') os.remove(postImageFilename + '.etag')
except BaseException: except BaseException:
pass pass
removeMetaData(filename, postImageFilename)
city = self._getSpoofedCity(baseDir, nickname, domain)
processMetaData(baseDir, nickname, domain,
filename, postImageFilename, city)
if os.path.isfile(postImageFilename): if os.path.isfile(postImageFilename):
print('profile update POST ' + mType + print('profile update POST ' + mType +
' image or font saved to ' + postImageFilename) ' image or font saved to ' + postImageFilename)
@ -4226,6 +4250,13 @@ class PubServer(BaseHTTPRequestHandler):
nickname, nickname,
pwd) 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 # change displayed name
if fields.get('displayNickname'): if fields.get('displayNickname'):
if fields['displayNickname'] != actorJson['name']: if fields['displayNickname'] != actorJson['name']:
@ -4244,6 +4275,7 @@ class PubServer(BaseHTTPRequestHandler):
if checkNameAndBio: if checkNameAndBio:
redirectPath = 'previewAvatar' redirectPath = 'previewAvatar'
if nickname == adminNickname:
# change media instance status # change media instance status
if fields.get('mediaInstance'): if fields.get('mediaInstance'):
self.server.mediaInstance = False self.server.mediaInstance = False
@ -4357,6 +4389,62 @@ class PubServer(BaseHTTPRequestHandler):
domain, domain,
domainFull) 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 # change email address
currentEmailAddress = getEmailAddress(actorJson) currentEmailAddress = getEmailAddress(actorJson)
if fields.get('email'): if fields.get('email'):
@ -4536,62 +4624,6 @@ class PubServer(BaseHTTPRequestHandler):
del actorJson['alsoKnownAs'] del actorJson['alsoKnownAs']
actorChanged = True 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 # change user bio
if fields.get('bio'): if fields.get('bio'):
if fields['bio'] != actorJson['summary']: if fields['bio'] != actorJson['summary']:
@ -10293,6 +10325,11 @@ class PubServer(BaseHTTPRequestHandler):
""" """
if '/users/' in path and path.endswith('/editprofile'): if '/users/' in path and path.endswith('/editprofile'):
peertubeInstances = self.server.peertubeInstances 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, msg = htmlEditProfile(self.server.cssCache,
translate, translate,
baseDir, baseDir,
@ -10302,7 +10339,8 @@ class PubServer(BaseHTTPRequestHandler):
self.server.defaultTimeline, self.server.defaultTimeline,
self.server.themeName, self.server.themeName,
peertubeInstances, peertubeInstances,
self.server.textModeBanner).encode('utf-8') self.server.textModeBanner,
city).encode('utf-8')
if msg: if msg:
msglen = len(msg) msglen = len(msg)
self._set_headers('text/html', msglen, self._set_headers('text/html', msglen,
@ -13053,7 +13091,11 @@ class PubServer(BaseHTTPRequestHandler):
filename.endswith('.gif'): filename.endswith('.gif'):
postImageFilename = filename.replace('.temp', '') postImageFilename = filename.replace('.temp', '')
print('Removing metadata from ' + postImageFilename) 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): if os.path.isfile(postImageFilename):
print('POST media saved to ' + postImageFilename) print('POST media saved to ' + postImageFilename)
else: else:
@ -13158,6 +13200,8 @@ class PubServer(BaseHTTPRequestHandler):
nickname, self.server.domain) nickname, self.server.domain)
return 1 return 1
city = self._getSpoofedCity(self.server.baseDir,
nickname, self.server.domain)
messageJson = \ messageJson = \
createPublicPost(self.server.baseDir, createPublicPost(self.server.baseDir,
nickname, nickname,
@ -13168,6 +13212,7 @@ class PubServer(BaseHTTPRequestHandler):
False, False, False, commentsEnabled, False, False, False, commentsEnabled,
filename, attachmentMediaType, filename, attachmentMediaType,
fields['imageDescription'], fields['imageDescription'],
city,
fields['replyTo'], fields['replyTo'], fields['replyTo'], fields['replyTo'],
fields['subject'], fields['schedulePost'], fields['subject'], fields['schedulePost'],
fields['eventDate'], fields['eventTime'], fields['eventDate'], fields['eventTime'],
@ -13304,15 +13349,20 @@ class PubServer(BaseHTTPRequestHandler):
imgDescription = fields['imageDescription'] imgDescription = fields['imageDescription']
if filename: if filename:
city = self._getSpoofedCity(self.server.baseDir,
nickname,
self.server.domain)
postJsonObject['object'] = \ postJsonObject['object'] = \
attachMedia(self.server.baseDir, attachMedia(self.server.baseDir,
self.server.httpPrefix, self.server.httpPrefix,
nickname,
self.server.domain, self.server.domain,
self.server.port, self.server.port,
postJsonObject['object'], postJsonObject['object'],
filename, filename,
attachmentMediaType, attachmentMediaType,
imgDescription) imgDescription,
city)
replaceYouTube(postJsonObject, replaceYouTube(postJsonObject,
self.server.YTReplacementDomain) self.server.YTReplacementDomain)
@ -13334,6 +13384,9 @@ class PubServer(BaseHTTPRequestHandler):
str(fields['postUrl'])) str(fields['postUrl']))
return -1 return -1
elif postType == 'newunlisted': elif postType == 'newunlisted':
city = self._getSpoofedCity(self.server.baseDir,
nickname,
self.server.domain)
messageJson = \ messageJson = \
createUnlistedPost(self.server.baseDir, createUnlistedPost(self.server.baseDir,
nickname, nickname,
@ -13343,6 +13396,7 @@ class PubServer(BaseHTTPRequestHandler):
False, False, False, commentsEnabled, False, False, False, commentsEnabled,
filename, attachmentMediaType, filename, attachmentMediaType,
fields['imageDescription'], fields['imageDescription'],
city,
fields['replyTo'], fields['replyTo'],
fields['replyTo'], fields['replyTo'],
fields['subject'], fields['subject'],
@ -13364,6 +13418,9 @@ class PubServer(BaseHTTPRequestHandler):
else: else:
return -1 return -1
elif postType == 'newfollowers': elif postType == 'newfollowers':
city = self._getSpoofedCity(self.server.baseDir,
nickname,
self.server.domain)
messageJson = \ messageJson = \
createFollowersOnlyPost(self.server.baseDir, createFollowersOnlyPost(self.server.baseDir,
nickname, nickname,
@ -13375,6 +13432,7 @@ class PubServer(BaseHTTPRequestHandler):
commentsEnabled, commentsEnabled,
filename, attachmentMediaType, filename, attachmentMediaType,
fields['imageDescription'], fields['imageDescription'],
city,
fields['replyTo'], fields['replyTo'],
fields['replyTo'], fields['replyTo'],
fields['subject'], fields['subject'],
@ -13416,6 +13474,9 @@ class PubServer(BaseHTTPRequestHandler):
maximumAttendeeCapacity = \ maximumAttendeeCapacity = \
int(fields['maximumAttendeeCapacity']) int(fields['maximumAttendeeCapacity'])
city = self._getSpoofedCity(self.server.baseDir,
nickname,
self.server.domain)
messageJson = \ messageJson = \
createEventPost(self.server.baseDir, createEventPost(self.server.baseDir,
nickname, nickname,
@ -13427,6 +13488,7 @@ class PubServer(BaseHTTPRequestHandler):
False, False, commentsEnabled, False, False, commentsEnabled,
filename, attachmentMediaType, filename, attachmentMediaType,
fields['imageDescription'], fields['imageDescription'],
city,
fields['subject'], fields['subject'],
fields['schedulePost'], fields['schedulePost'],
fields['eventDate'], fields['eventDate'],
@ -13452,6 +13514,9 @@ class PubServer(BaseHTTPRequestHandler):
messageJson = None messageJson = None
print('A DM was posted') print('A DM was posted')
if '@' in mentionsStr: if '@' in mentionsStr:
city = self._getSpoofedCity(self.server.baseDir,
nickname,
self.server.domain)
messageJson = \ messageJson = \
createDirectMessagePost(self.server.baseDir, createDirectMessagePost(self.server.baseDir,
nickname, nickname,
@ -13464,6 +13529,7 @@ class PubServer(BaseHTTPRequestHandler):
commentsEnabled, commentsEnabled,
filename, attachmentMediaType, filename, attachmentMediaType,
fields['imageDescription'], fields['imageDescription'],
city,
fields['replyTo'], fields['replyTo'],
fields['replyTo'], fields['replyTo'],
fields['subject'], fields['subject'],
@ -13492,6 +13558,9 @@ class PubServer(BaseHTTPRequestHandler):
print('A reminder was posted for ' + handle) print('A reminder was posted for ' + handle)
if '@' + handle not in mentionsStr: if '@' + handle not in mentionsStr:
mentionsStr = '@' + handle + ' ' + mentionsStr mentionsStr = '@' + handle + ' ' + mentionsStr
city = self._getSpoofedCity(self.server.baseDir,
nickname,
self.server.domain)
messageJson = \ messageJson = \
createDirectMessagePost(self.server.baseDir, createDirectMessagePost(self.server.baseDir,
nickname, nickname,
@ -13502,6 +13571,7 @@ class PubServer(BaseHTTPRequestHandler):
True, False, False, False, True, False, False, False,
filename, attachmentMediaType, filename, attachmentMediaType,
fields['imageDescription'], fields['imageDescription'],
city,
None, None, None, None,
fields['subject'], fields['subject'],
True, fields['schedulePost'], True, fields['schedulePost'],
@ -13525,6 +13595,9 @@ class PubServer(BaseHTTPRequestHandler):
# and not accounts being reported we disable any # and not accounts being reported we disable any
# included fediverse addresses by replacing '@' with '-at-' # included fediverse addresses by replacing '@' with '-at-'
fields['message'] = fields['message'].replace('@', '-at-') fields['message'] = fields['message'].replace('@', '-at-')
city = self._getSpoofedCity(self.server.baseDir,
nickname,
self.server.domain)
messageJson = \ messageJson = \
createReportPost(self.server.baseDir, createReportPost(self.server.baseDir,
nickname, nickname,
@ -13534,6 +13607,7 @@ class PubServer(BaseHTTPRequestHandler):
True, False, False, True, True, False, False, True,
filename, attachmentMediaType, filename, attachmentMediaType,
fields['imageDescription'], fields['imageDescription'],
city,
self.server.debug, fields['subject']) self.server.debug, fields['subject'])
if messageJson: if messageJson:
if self._postToOutbox(messageJson, __version__, nickname): if self._postToOutbox(messageJson, __version__, nickname):
@ -13553,6 +13627,9 @@ class PubServer(BaseHTTPRequestHandler):
str(questionCtr)]) str(questionCtr)])
if not qOptions: if not qOptions:
return -1 return -1
city = self._getSpoofedCity(self.server.baseDir,
nickname,
self.server.domain)
messageJson = \ messageJson = \
createQuestionPost(self.server.baseDir, createQuestionPost(self.server.baseDir,
nickname, nickname,
@ -13564,6 +13641,7 @@ class PubServer(BaseHTTPRequestHandler):
commentsEnabled, commentsEnabled,
filename, attachmentMediaType, filename, attachmentMediaType,
fields['imageDescription'], fields['imageDescription'],
city,
fields['subject'], fields['subject'],
int(fields['duration'])) int(fields['duration']))
if messageJson: if messageJson:
@ -13588,6 +13666,9 @@ class PubServer(BaseHTTPRequestHandler):
if durationStr: if durationStr:
if ' ' not in durationStr: if ' ' not in durationStr:
durationStr = durationStr + ' days' durationStr = durationStr + ' days'
city = self._getSpoofedCity(self.server.baseDir,
nickname,
self.server.domain)
addShare(self.server.baseDir, addShare(self.server.baseDir,
self.server.httpPrefix, self.server.httpPrefix,
nickname, nickname,
@ -13599,7 +13680,8 @@ class PubServer(BaseHTTPRequestHandler):
fields['category'], fields['category'],
fields['location'], fields['location'],
durationStr, durationStr,
self.server.debug) self.server.debug,
city)
if filename: if filename:
if os.path.isfile(filename): if os.path.isfile(filename):
os.remove(filename) os.remove(filename)
@ -14661,7 +14743,8 @@ def loadTokens(baseDir: str, tokensDict: {}, tokensLookup: {}) -> None:
break break
def runDaemon(showNodeInfoAccounts: bool, def runDaemon(city: str,
showNodeInfoAccounts: bool,
showNodeInfoVersion: bool, showNodeInfoVersion: bool,
brochMode: bool, brochMode: bool,
verifyAllSignatures: bool, verifyAllSignatures: bool,
@ -14819,6 +14902,9 @@ def runDaemon(showNodeInfoAccounts: bool,
print('ERROR: no translations were loaded') print('ERROR: no translations were loaded')
sys.exit() sys.exit()
# spoofed city for gps location misdirection
httpd.city = city
# For moderated newswire feeds this is the amount of time allowed # For moderated newswire feeds this is the amount of time allowed
# for voting after the post arrives # for voting after the post arrives
httpd.votingTimeMins = votingTimeMins httpd.votingTimeMins = votingTimeMins

View File

@ -458,6 +458,7 @@ def _desktopReplyToPost(session, postId: str,
isArticle = False isArticle = False
subject = None subject = None
commentsEnabled = True commentsEnabled = True
city = 'London, England'
sayStr = 'Sending reply' sayStr = 'Sending reply'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak) _sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
if sendPostViaServer(__version__, if sendPostViaServer(__version__,
@ -466,7 +467,7 @@ def _desktopReplyToPost(session, postId: str,
toNickname, toDomain, toPort, ccUrl, toNickname, toDomain, toPort, ccUrl,
httpPrefix, replyMessage, followersOnly, httpPrefix, replyMessage, followersOnly,
commentsEnabled, attach, mediaType, commentsEnabled, attach, mediaType,
attachedImageDescription, attachedImageDescription, city,
cachedWebfingers, personCache, isArticle, cachedWebfingers, personCache, isArticle,
debug, postId, postId, subject) == 0: debug, postId, postId, subject) == 0:
sayStr = 'Reply sent' sayStr = 'Reply sent'
@ -514,6 +515,7 @@ def _desktopNewPost(session,
attach = None attach = None
mediaType = None mediaType = None
attachedImageDescription = None attachedImageDescription = None
city = 'London, England'
isArticle = False isArticle = False
subject = None subject = None
commentsEnabled = True commentsEnabled = True
@ -526,7 +528,7 @@ def _desktopNewPost(session,
None, '#Public', port, ccUrl, None, '#Public', port, ccUrl,
httpPrefix, newMessage, followersOnly, httpPrefix, newMessage, followersOnly,
commentsEnabled, attach, mediaType, commentsEnabled, attach, mediaType,
attachedImageDescription, attachedImageDescription, city,
cachedWebfingers, personCache, isArticle, cachedWebfingers, personCache, isArticle,
debug, None, None, subject) == 0: debug, None, None, subject) == 0:
sayStr = 'Post sent' sayStr = 'Post sent'
@ -1158,6 +1160,7 @@ def _desktopNewDMbase(session, toHandle: str,
attach = None attach = None
mediaType = None mediaType = None
attachedImageDescription = None attachedImageDescription = None
city = 'London, England'
isArticle = False isArticle = False
subject = None subject = None
commentsEnabled = True commentsEnabled = True
@ -1206,7 +1209,7 @@ def _desktopNewDMbase(session, toHandle: str,
toNickname, toDomain, toPort, ccUrl, toNickname, toDomain, toPort, ccUrl,
httpPrefix, newMessage, followersOnly, httpPrefix, newMessage, followersOnly,
commentsEnabled, attach, mediaType, commentsEnabled, attach, mediaType,
attachedImageDescription, attachedImageDescription, city,
cachedWebfingers, personCache, isArticle, cachedWebfingers, personCache, isArticle,
debug, None, None, subject) == 0: debug, None, None, subject) == 0:
sayStr = 'Direct message sent' sayStr = 'Direct message sent'

View File

@ -762,5 +762,6 @@
"talkingemote2": "talkingEmote2", "talkingemote2": "talkingEmote2",
"veryhappyemote": "veryHappyEmote", "veryhappyemote": "veryHappyEmote",
"worriedemote": "worriedEmote", "worriedemote": "worriedEmote",
"tor": "tor" "tor": "tor",
"pine64": "pine64"
} }

BIN
emoji/pine64.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -464,6 +464,9 @@ parser.add_argument('--attach', dest='attach', type=str,
default=None, help='File to attach to a post') default=None, help='File to attach to a post')
parser.add_argument('--imagedescription', dest='imageDescription', type=str, parser.add_argument('--imagedescription', dest='imageDescription', type=str,
default=None, help='Description of an attached image') 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', parser.add_argument('--warning', '--warn', '--cwsubject', '--subject',
dest='subject', type=str, default=None, dest='subject', type=str, default=None,
help='Subject of content warning') help='Subject of content warning')
@ -1110,6 +1113,7 @@ if args.message:
followersOnly = args.followersonly followersOnly = args.followersonly
clientToServer = args.client clientToServer = args.client
attachedImageDescription = args.imageDescription attachedImageDescription = args.imageDescription
city = 'London, England'
sendThreads = [] sendThreads = []
postLog = [] postLog = []
personCache = {} personCache = {}
@ -1130,7 +1134,7 @@ if args.message:
toNickname, toDomain, toPort, ccUrl, toNickname, toDomain, toPort, ccUrl,
httpPrefix, sendMessage, followersOnly, httpPrefix, sendMessage, followersOnly,
args.commentsEnabled, attach, mediaType, args.commentsEnabled, attach, mediaType,
attachedImageDescription, attachedImageDescription, city,
cachedWebfingers, personCache, isArticle, cachedWebfingers, personCache, isArticle,
args.debug, replyTo, replyTo, subject) args.debug, replyTo, replyTo, subject)
for i in range(10): for i in range(10):
@ -1959,8 +1963,9 @@ if args.avatar:
if not args.nickname: if not args.nickname:
print('Specify a nickname with --nickname [name]') print('Specify a nickname with --nickname [name]')
sys.exit() sys.exit()
city = 'London, England'
if setProfileImage(baseDir, httpPrefix, args.nickname, domain, if setProfileImage(baseDir, httpPrefix, args.nickname, domain,
port, args.avatar, 'avatar', '128x128'): port, args.avatar, 'avatar', '128x128', city):
print('Avatar added for ' + args.nickname) print('Avatar added for ' + args.nickname)
else: else:
print('Avatar was not added for ' + args.nickname) print('Avatar was not added for ' + args.nickname)
@ -1973,8 +1978,10 @@ if args.backgroundImage:
if not args.nickname: if not args.nickname:
print('Specify a nickname with --nickname [name]') print('Specify a nickname with --nickname [name]')
sys.exit() sys.exit()
city = 'London, England'
if setProfileImage(baseDir, httpPrefix, args.nickname, domain, 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) print('Background image added for ' + args.nickname)
else: else:
print('Background image was not added for ' + args.nickname) print('Background image was not added for ' + args.nickname)
@ -2347,6 +2354,7 @@ if args.unfilterStr:
sys.exit() sys.exit()
if args.testdata: if args.testdata:
city = 'London, England'
nickname = 'testuser567' nickname = 'testuser567'
password = 'boringpassword' password = 'boringpassword'
print('Generating some test data for user: ' + nickname) print('Generating some test data for user: ' + nickname)
@ -2394,7 +2402,7 @@ if args.testdata:
"mechanical", "mechanical",
"City", "City",
"2 months", "2 months",
debug) debug, city)
addShare(baseDir, addShare(baseDir,
httpPrefix, nickname, domain, port, httpPrefix, nickname, domain, port,
"witch hat", "witch hat",
@ -2404,7 +2412,7 @@ if args.testdata:
"clothing", "clothing",
"City", "City",
"3 months", "3 months",
debug) debug, city)
deleteAllPosts(baseDir, nickname, domain, 'inbox') deleteAllPosts(baseDir, nickname, domain, 'inbox')
deleteAllPosts(baseDir, nickname, domain, 'outbox') deleteAllPosts(baseDir, nickname, domain, 'outbox')
@ -2416,6 +2424,7 @@ if args.testdata:
testAttachImageFilename = None testAttachImageFilename = None
testMediaType = None testMediaType = None
testImageDescription = None testImageDescription = None
testCity = 'London, England'
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"like this is totally just a #test man", "like this is totally just a #test man",
@ -2424,7 +2433,7 @@ if args.testdata:
testC2S, testC2S,
testCommentsEnabled, testCommentsEnabled,
testAttachImageFilename, testAttachImageFilename,
testMediaType, testImageDescription) testMediaType, testImageDescription, testCity)
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"Zoiks!!!", "Zoiks!!!",
testFollowersOnly, testFollowersOnly,
@ -2432,7 +2441,7 @@ if args.testdata:
testC2S, testC2S,
testCommentsEnabled, testCommentsEnabled,
testAttachImageFilename, testAttachImageFilename,
testMediaType, testImageDescription) testMediaType, testImageDescription, testCity)
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"Hey scoob we need like a hundred more #milkshakes", "Hey scoob we need like a hundred more #milkshakes",
testFollowersOnly, testFollowersOnly,
@ -2440,7 +2449,7 @@ if args.testdata:
testC2S, testC2S,
testCommentsEnabled, testCommentsEnabled,
testAttachImageFilename, testAttachImageFilename,
testMediaType, testImageDescription) testMediaType, testImageDescription, testCity)
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"Getting kinda spooky around here", "Getting kinda spooky around here",
testFollowersOnly, testFollowersOnly,
@ -2448,7 +2457,7 @@ if args.testdata:
testC2S, testC2S,
testCommentsEnabled, testCommentsEnabled,
testAttachImageFilename, testAttachImageFilename,
testMediaType, testImageDescription, testMediaType, testImageDescription, testCity,
'someone') 'someone')
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"And they would have gotten away with it too" + "And they would have gotten away with it too" +
@ -2458,7 +2467,7 @@ if args.testdata:
testC2S, testC2S,
testCommentsEnabled, testCommentsEnabled,
'img/logo.png', 'image/png', 'img/logo.png', 'image/png',
'Description of image') 'Description of image', testCity)
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"man these centralized sites are like the worst!", "man these centralized sites are like the worst!",
testFollowersOnly, testFollowersOnly,
@ -2466,7 +2475,7 @@ if args.testdata:
testC2S, testC2S,
testCommentsEnabled, testCommentsEnabled,
testAttachImageFilename, testAttachImageFilename,
testMediaType, testImageDescription) testMediaType, testImageDescription, testCity)
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"another mystery solved #test", "another mystery solved #test",
testFollowersOnly, testFollowersOnly,
@ -2474,7 +2483,7 @@ if args.testdata:
testC2S, testC2S,
testCommentsEnabled, testCommentsEnabled,
testAttachImageFilename, testAttachImageFilename,
testMediaType, testImageDescription) testMediaType, testImageDescription, testCity)
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"let's go bowling", "let's go bowling",
testFollowersOnly, testFollowersOnly,
@ -2482,7 +2491,7 @@ if args.testdata:
testC2S, testC2S,
testCommentsEnabled, testCommentsEnabled,
testAttachImageFilename, testAttachImageFilename,
testMediaType, testImageDescription) testMediaType, testImageDescription, testCity)
domainFull = domain + ':' + str(port) domainFull = domain + ':' + str(port)
clearFollows(baseDir, nickname, domain) clearFollows(baseDir, nickname, domain)
@ -2620,6 +2629,11 @@ showNodeInfoVersion = \
if showNodeInfoVersion is not None: if showNodeInfoVersion is not None:
args.showNodeInfoVersion = bool(showNodeInfoVersion) args.showNodeInfoVersion = bool(showNodeInfoVersion)
city = \
getConfigParam(baseDir, 'city')
if city is not None:
args.city = city
YTDomain = getConfigParam(baseDir, 'youtubedomain') YTDomain = getConfigParam(baseDir, 'youtubedomain')
if YTDomain: if YTDomain:
if '://' in YTDomain: if '://' in YTDomain:
@ -2634,7 +2648,8 @@ if setTheme(baseDir, themeName, domain,
print('Theme set to ' + themeName) print('Theme set to ' + themeName)
if __name__ == "__main__": if __name__ == "__main__":
runDaemon(args.showNodeInfoAccounts, runDaemon(args.city,
args.showNodeInfoAccounts,
args.showNodeInfoVersion, args.showNodeInfoVersion,
args.brochMode, args.brochMode,
args.verifyAllSignatures, args.verifyAllSignatures,

View File

@ -2183,6 +2183,7 @@ def _bounceDM(senderPostId: str, session, httpPrefix: str,
attachImageFilename = None attachImageFilename = None
mediaType = None mediaType = None
imageDescription = '' imageDescription = ''
city = 'London, England'
inReplyTo = removeIdEnding(senderPostId) inReplyTo = removeIdEnding(senderPostId)
inReplyToAtomUri = None inReplyToAtomUri = None
schedulePost = False schedulePost = False
@ -2195,7 +2196,7 @@ def _bounceDM(senderPostId: str, session, httpPrefix: str,
saveToFile, clientToServer, saveToFile, clientToServer,
commentsEnabled, commentsEnabled,
attachImageFilename, mediaType, attachImageFilename, mediaType,
imageDescription, imageDescription, city,
inReplyTo, inReplyToAtomUri, inReplyTo, inReplyToAtomUri,
subject, debug, schedulePost, subject, debug, schedulePost,
eventDate, eventTime, location) eventDate, eventTime, location)

4158
locations.txt 100644

File diff suppressed because it is too large Load Diff

209
media.py
View File

@ -8,6 +8,9 @@ __status__ = "Production"
import os import os
import datetime import datetime
import random
import math
from random import randint
from hashlib import sha1 from hashlib import sha1
from auth import createPassword from auth import createPassword
from utils import getFullDomain from utils import getFullDomain
@ -37,7 +40,7 @@ def replaceYouTube(postJsonObject: {}, replacementDomain: str) -> None:
replacementDomain) 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, """Attempts to do this with pure python didn't work well,
so better to use a dedicated tool if one is installed 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 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: def _isMedia(imageFilename: str) -> bool:
"""Is the given file a media file? """Is the given file a media file?
""" """
@ -131,9 +329,11 @@ def _updateEtag(mediaFilename: str) -> None:
pass 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, postJson: {}, imageFilename: str,
mediaType: str, description: str) -> {}: mediaType: str, description: str,
city: str) -> {}:
"""Attaches media to a json object post """Attaches media to a json object post
The description can be None The description can be None
""" """
@ -179,7 +379,8 @@ def attachMedia(baseDir: str, httpPrefix: str, domain: str, port: int,
if baseDir: if baseDir:
if mediaType.startswith('image/'): if mediaType.startswith('image/'):
removeMetaData(imageFilename, mediaFilename) processMetaData(baseDir, nickname, domain,
imageFilename, mediaFilename, city)
else: else:
copyfile(imageFilename, mediaFilename) copyfile(imageFilename, mediaFilename)
_updateEtag(mediaFilename) _updateEtag(mediaFilename)

View File

@ -527,11 +527,17 @@ def _convertRSStoActivityPub(baseDir: str, httpPrefix: str,
# NOTE: the id when the post is created will not be # NOTE: the id when the post is created will not be
# consistent (it's based on the current time, not the # consistent (it's based on the current time, not the
# published time), so we change that later # published time), so we change that later
saveToFile = False
attachImageFilename = None
mediaType = None
imageDescription = None
city = 'London, England'
blog = createNewsPost(baseDir, blog = createNewsPost(baseDir,
domain, port, httpPrefix, domain, port, httpPrefix,
rssDescription, rssDescription,
followersOnly, False, followersOnly, saveToFile,
None, None, None, attachImageFilename, mediaType,
imageDescription, city,
rssTitle) rssTitle)
if not blog: if not blog:
continue continue

View File

@ -176,7 +176,8 @@ def postMessageToOutbox(session, translate: {},
proxyType: str, version: str, debug: bool, proxyType: str, version: str, debug: bool,
YTReplacementDomain: str, YTReplacementDomain: str,
showPublishedDateOnly: bool, showPublishedDateOnly: bool,
allowLocalNetworkAccess: bool) -> bool: allowLocalNetworkAccess: bool,
city: str) -> bool:
"""post is received by the outbox """post is received by the outbox
Client to server message post Client to server message post
https://www.w3.org/TR/activitypub/#client-to-server-outbox-delivery https://www.w3.org/TR/activitypub/#client-to-server-outbox-delivery
@ -545,7 +546,7 @@ def postMessageToOutbox(session, translate: {},
print('DEBUG: handle share uploads') print('DEBUG: handle share uploads')
outboxShareUpload(baseDir, httpPrefix, outboxShareUpload(baseDir, httpPrefix,
postToNickname, domain, postToNickname, domain,
port, messageJson, debug) port, messageJson, debug, city)
if debug: if debug:
print('DEBUG: handle undo share uploads') print('DEBUG: handle undo share uploads')

View File

@ -34,7 +34,7 @@ from posts import createModeration
from auth import storeBasicCredentials from auth import storeBasicCredentials
from auth import removePassword from auth import removePassword
from roles import setRole from roles import setRole
from media import removeMetaData from media import processMetaData
from utils import getStatusNumber from utils import getStatusNumber
from utils import getFullDomain from utils import getFullDomain
from utils import validNickname from utils import validNickname
@ -74,7 +74,7 @@ def generateRSAKey() -> (str, str):
def setProfileImage(baseDir: str, httpPrefix: str, nickname: str, domain: str, def setProfileImage(baseDir: str, httpPrefix: str, nickname: str, domain: str,
port: int, imageFilename: str, imageType: 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 """Saves the given image file as an avatar or background
image for the given person image for the given person
""" """
@ -135,7 +135,8 @@ def setProfileImage(baseDir: str, httpPrefix: str, nickname: str, domain: str,
'/usr/bin/convert ' + imageFilename + ' -size ' + \ '/usr/bin/convert ' + imageFilename + ' -size ' + \
resolution + ' -quality 50 ' + profileFilename resolution + ' -quality 50 ' + profileFilename
subprocess.call(cmd, shell=True) subprocess.call(cmd, shell=True)
removeMetaData(profileFilename, profileFilename) processMetaData(baseDir, nickname, domain,
profileFilename, profileFilename, city)
return True return True
return False return False

View File

@ -867,7 +867,7 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
followersOnly: bool, saveToFile: bool, followersOnly: bool, saveToFile: bool,
clientToServer: bool, commentsEnabled: bool, clientToServer: bool, commentsEnabled: bool,
attachImageFilename: str, attachImageFilename: str,
mediaType: str, imageDescription: str, mediaType: str, imageDescription: str, city: str,
isModerationReport: bool, isModerationReport: bool,
isArticle: bool, isArticle: bool,
inReplyTo=None, inReplyTo=None,
@ -1059,6 +1059,10 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
idStr = \ idStr = \
httpPrefix + '://' + domain + '/users/' + nickname + \ httpPrefix + '://' + domain + '/users/' + nickname + \
'/statuses/' + statusNumber + '/replies' '/statuses/' + statusNumber + '/replies'
newPostUrl = \
httpPrefix + '://' + domain + '/@' + nickname + '/'+statusNumber
newPostAttributedTo = \
httpPrefix + '://' + domain + '/users/' + nickname
newPost = { newPost = {
'@context': postContext, '@context': postContext,
'id': newPostId + '/activity', 'id': newPostId + '/activity',
@ -1073,8 +1077,8 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
'summary': summary, 'summary': summary,
'inReplyTo': inReplyTo, 'inReplyTo': inReplyTo,
'published': published, 'published': published,
'url': httpPrefix+'://'+domain+'/@'+nickname+'/'+statusNumber, 'url': newPostUrl,
'attributedTo': httpPrefix+'://'+domain+'/users/'+nickname, 'attributedTo': newPostAttributedTo,
'to': toRecipients, 'to': toRecipients,
'cc': toCC, 'cc': toCC,
'sensitive': sensitive, 'sensitive': sensitive,
@ -1101,9 +1105,9 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
} }
if attachImageFilename: if attachImageFilename:
newPost['object'] = \ newPost['object'] = \
attachMedia(baseDir, httpPrefix, domain, port, attachMedia(baseDir, httpPrefix, nickname, domain, port,
newPost['object'], attachImageFilename, newPost['object'], attachImageFilename,
mediaType, imageDescription) mediaType, imageDescription, city)
_appendEventFields(newPost['object'], eventUUID, eventStatus, _appendEventFields(newPost['object'], eventUUID, eventStatus,
anonymousParticipationEnabled, anonymousParticipationEnabled,
repliesModerationOption, repliesModerationOption,
@ -1115,6 +1119,8 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
idStr = \ idStr = \
httpPrefix + '://' + domain + '/users/' + nickname + \ httpPrefix + '://' + domain + '/users/' + nickname + \
'/statuses/' + statusNumber + '/replies' '/statuses/' + statusNumber + '/replies'
newPostUrl = \
httpPrefix + '://' + domain + '/@' + nickname+'/' + statusNumber
newPost = { newPost = {
"@context": postContext, "@context": postContext,
'id': newPostId, 'id': newPostId,
@ -1122,7 +1128,7 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
'summary': summary, 'summary': summary,
'inReplyTo': inReplyTo, 'inReplyTo': inReplyTo,
'published': published, 'published': published,
'url': httpPrefix+'://'+domain+'/@'+nickname+'/'+statusNumber, 'url': newPostUrl,
'attributedTo': httpPrefix + '://' + domain + '/users/' + nickname, 'attributedTo': httpPrefix + '://' + domain + '/users/' + nickname,
'to': toRecipients, 'to': toRecipients,
'cc': toCC, 'cc': toCC,
@ -1149,9 +1155,9 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
} }
if attachImageFilename: if attachImageFilename:
newPost = \ newPost = \
attachMedia(baseDir, httpPrefix, domain, port, attachMedia(baseDir, httpPrefix, nickname, domain, port,
newPost, attachImageFilename, newPost, attachImageFilename,
mediaType, imageDescription) mediaType, imageDescription, city)
_appendEventFields(newPost, eventUUID, eventStatus, _appendEventFields(newPost, eventUUID, eventStatus,
anonymousParticipationEnabled, anonymousParticipationEnabled,
repliesModerationOption, repliesModerationOption,
@ -1391,7 +1397,7 @@ def createPublicPost(baseDir: str,
content: str, followersOnly: bool, saveToFile: bool, content: str, followersOnly: bool, saveToFile: bool,
clientToServer: bool, commentsEnabled: bool, clientToServer: bool, commentsEnabled: bool,
attachImageFilename: str, mediaType: str, attachImageFilename: str, mediaType: str,
imageDescription: str, imageDescription: str, city: str,
inReplyTo=None, inReplyToAtomUri=None, subject=None, inReplyTo=None, inReplyToAtomUri=None, subject=None,
schedulePost=False, schedulePost=False,
eventDate=None, eventTime=None, location=None, eventDate=None, eventTime=None, location=None,
@ -1417,7 +1423,7 @@ def createPublicPost(baseDir: str,
httpPrefix, content, followersOnly, saveToFile, httpPrefix, content, followersOnly, saveToFile,
clientToServer, commentsEnabled, clientToServer, commentsEnabled,
attachImageFilename, mediaType, attachImageFilename, mediaType,
imageDescription, imageDescription, city,
isModerationReport, isArticle, isModerationReport, isArticle,
inReplyTo, inReplyToAtomUri, subject, inReplyTo, inReplyToAtomUri, subject,
schedulePost, eventDate, eventTime, location, schedulePost, eventDate, eventTime, location,
@ -1464,7 +1470,7 @@ def createBlogPost(baseDir: str,
content: str, followersOnly: bool, saveToFile: bool, content: str, followersOnly: bool, saveToFile: bool,
clientToServer: bool, commentsEnabled: bool, clientToServer: bool, commentsEnabled: bool,
attachImageFilename: str, mediaType: str, attachImageFilename: str, mediaType: str,
imageDescription: str, imageDescription: str, city: str,
inReplyTo=None, inReplyToAtomUri=None, subject=None, inReplyTo=None, inReplyToAtomUri=None, subject=None,
schedulePost=False, schedulePost=False,
eventDate=None, eventTime=None, location=None) -> {}: eventDate=None, eventTime=None, location=None) -> {}:
@ -1474,7 +1480,7 @@ def createBlogPost(baseDir: str,
content, followersOnly, saveToFile, content, followersOnly, saveToFile,
clientToServer, commentsEnabled, clientToServer, commentsEnabled,
attachImageFilename, mediaType, attachImageFilename, mediaType,
imageDescription, imageDescription, city,
inReplyTo, inReplyToAtomUri, subject, inReplyTo, inReplyToAtomUri, subject,
schedulePost, schedulePost,
eventDate, eventTime, location, True) eventDate, eventTime, location, True)
@ -1489,7 +1495,7 @@ def createNewsPost(baseDir: str,
domain: str, port: int, httpPrefix: str, domain: str, port: int, httpPrefix: str,
content: str, followersOnly: bool, saveToFile: bool, content: str, followersOnly: bool, saveToFile: bool,
attachImageFilename: str, mediaType: str, attachImageFilename: str, mediaType: str,
imageDescription: str, imageDescription: str, city: str,
subject: str) -> {}: subject: str) -> {}:
clientToServer = False clientToServer = False
inReplyTo = None inReplyTo = None
@ -1504,7 +1510,7 @@ def createNewsPost(baseDir: str,
content, followersOnly, saveToFile, content, followersOnly, saveToFile,
clientToServer, False, clientToServer, False,
attachImageFilename, mediaType, attachImageFilename, mediaType,
imageDescription, imageDescription, city,
inReplyTo, inReplyToAtomUri, subject, inReplyTo, inReplyToAtomUri, subject,
schedulePost, schedulePost,
eventDate, eventTime, location, True) eventDate, eventTime, location, True)
@ -1518,7 +1524,7 @@ def createQuestionPost(baseDir: str,
followersOnly: bool, saveToFile: bool, followersOnly: bool, saveToFile: bool,
clientToServer: bool, commentsEnabled: bool, clientToServer: bool, commentsEnabled: bool,
attachImageFilename: str, mediaType: str, attachImageFilename: str, mediaType: str,
imageDescription: str, imageDescription: str, city: str,
subject: str, durationDays: int) -> {}: subject: str, durationDays: int) -> {}:
"""Question post with multiple choice options """Question post with multiple choice options
""" """
@ -1531,7 +1537,7 @@ def createQuestionPost(baseDir: str,
httpPrefix, content, followersOnly, saveToFile, httpPrefix, content, followersOnly, saveToFile,
clientToServer, commentsEnabled, clientToServer, commentsEnabled,
attachImageFilename, mediaType, attachImageFilename, mediaType,
imageDescription, imageDescription, city,
False, False, None, None, subject, False, False, None, None, subject,
False, None, None, None, None, None, False, None, None, None, None, None,
None, None, None, None, None, None,
@ -1562,7 +1568,7 @@ def createUnlistedPost(baseDir: str,
content: str, followersOnly: bool, saveToFile: bool, content: str, followersOnly: bool, saveToFile: bool,
clientToServer: bool, commentsEnabled: bool, clientToServer: bool, commentsEnabled: bool,
attachImageFilename: str, mediaType: str, attachImageFilename: str, mediaType: str,
imageDescription: str, imageDescription: str, city: str,
inReplyTo=None, inReplyToAtomUri=None, subject=None, inReplyTo=None, inReplyToAtomUri=None, subject=None,
schedulePost=False, schedulePost=False,
eventDate=None, eventTime=None, location=None) -> {}: eventDate=None, eventTime=None, location=None) -> {}:
@ -1576,8 +1582,9 @@ def createUnlistedPost(baseDir: str,
httpPrefix, content, followersOnly, saveToFile, httpPrefix, content, followersOnly, saveToFile,
clientToServer, commentsEnabled, clientToServer, commentsEnabled,
attachImageFilename, mediaType, attachImageFilename, mediaType,
imageDescription, imageDescription, city,
False, False, inReplyTo, inReplyToAtomUri, subject, False, False,
inReplyTo, inReplyToAtomUri, subject,
schedulePost, eventDate, eventTime, location, schedulePost, eventDate, eventTime, location,
None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None) None, None, None, None, None)
@ -1590,7 +1597,7 @@ def createFollowersOnlyPost(baseDir: str,
saveToFile: bool, saveToFile: bool,
clientToServer: bool, commentsEnabled: bool, clientToServer: bool, commentsEnabled: bool,
attachImageFilename: str, mediaType: str, attachImageFilename: str, mediaType: str,
imageDescription: str, imageDescription: str, city: str,
inReplyTo=None, inReplyToAtomUri=None, inReplyTo=None, inReplyToAtomUri=None,
subject=None, schedulePost=False, subject=None, schedulePost=False,
eventDate=None, eventTime=None, eventDate=None, eventTime=None,
@ -1605,8 +1612,9 @@ def createFollowersOnlyPost(baseDir: str,
httpPrefix, content, followersOnly, saveToFile, httpPrefix, content, followersOnly, saveToFile,
clientToServer, commentsEnabled, clientToServer, commentsEnabled,
attachImageFilename, mediaType, attachImageFilename, mediaType,
imageDescription, imageDescription, city,
False, False, inReplyTo, inReplyToAtomUri, subject, False, False,
inReplyTo, inReplyToAtomUri, subject,
schedulePost, eventDate, eventTime, location, schedulePost, eventDate, eventTime, location,
None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None) None, None, None, None, None)
@ -1619,7 +1627,7 @@ def createEventPost(baseDir: str,
saveToFile: bool, saveToFile: bool,
clientToServer: bool, commentsEnabled: bool, clientToServer: bool, commentsEnabled: bool,
attachImageFilename: str, mediaType: str, attachImageFilename: str, mediaType: str,
imageDescription: str, imageDescription: str, city: str,
subject=None, schedulePost=False, subject=None, schedulePost=False,
eventDate=None, eventTime=None, eventDate=None, eventTime=None,
location=None, category=None, joinMode=None, location=None, category=None, joinMode=None,
@ -1652,7 +1660,7 @@ def createEventPost(baseDir: str,
httpPrefix, content, followersOnly, saveToFile, httpPrefix, content, followersOnly, saveToFile,
clientToServer, commentsEnabled, clientToServer, commentsEnabled,
attachImageFilename, mediaType, attachImageFilename, mediaType,
imageDescription, imageDescription, city,
False, False, None, None, subject, False, False, None, None, subject,
schedulePost, eventDate, eventTime, location, schedulePost, eventDate, eventTime, location,
eventUUID, category, joinMode, eventUUID, category, joinMode,
@ -1704,7 +1712,7 @@ def createDirectMessagePost(baseDir: str,
saveToFile: bool, clientToServer: bool, saveToFile: bool, clientToServer: bool,
commentsEnabled: bool, commentsEnabled: bool,
attachImageFilename: str, mediaType: str, attachImageFilename: str, mediaType: str,
imageDescription: str, imageDescription: str, city: str,
inReplyTo=None, inReplyToAtomUri=None, inReplyTo=None, inReplyToAtomUri=None,
subject=None, debug=False, subject=None, debug=False,
schedulePost=False, schedulePost=False,
@ -1727,8 +1735,9 @@ def createDirectMessagePost(baseDir: str,
httpPrefix, content, followersOnly, saveToFile, httpPrefix, content, followersOnly, saveToFile,
clientToServer, commentsEnabled, clientToServer, commentsEnabled,
attachImageFilename, mediaType, attachImageFilename, mediaType,
imageDescription, imageDescription, city,
False, False, inReplyTo, inReplyToAtomUri, subject, False, False,
inReplyTo, inReplyToAtomUri, subject,
schedulePost, eventDate, eventTime, location, schedulePost, eventDate, eventTime, location,
None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None) None, None, None, None, None)
@ -1748,7 +1757,7 @@ def createReportPost(baseDir: str,
content: str, followersOnly: bool, saveToFile: bool, content: str, followersOnly: bool, saveToFile: bool,
clientToServer: bool, commentsEnabled: bool, clientToServer: bool, commentsEnabled: bool,
attachImageFilename: str, mediaType: str, attachImageFilename: str, mediaType: str,
imageDescription: str, imageDescription: str, city: str,
debug: bool, subject=None) -> {}: debug: bool, subject=None) -> {}:
"""Send a report to moderators """Send a report to moderators
""" """
@ -1817,7 +1826,7 @@ def createReportPost(baseDir: str,
httpPrefix, content, followersOnly, saveToFile, httpPrefix, content, followersOnly, saveToFile,
clientToServer, commentsEnabled, clientToServer, commentsEnabled,
attachImageFilename, mediaType, attachImageFilename, mediaType,
imageDescription, imageDescription, city,
True, False, None, None, subject, True, False, None, None, subject,
False, None, None, None, None, None, False, None, None, None, None, None,
None, None, None, None, None, None,
@ -1902,7 +1911,7 @@ def sendPost(projectVersion: str,
saveToFile: bool, clientToServer: bool, saveToFile: bool, clientToServer: bool,
commentsEnabled: bool, commentsEnabled: bool,
attachImageFilename: str, mediaType: str, attachImageFilename: str, mediaType: str,
imageDescription: str, imageDescription: str, city: str,
federationList: [], sendThreads: [], postLog: [], federationList: [], sendThreads: [], postLog: [],
cachedWebfingers: {}, personCache: {}, cachedWebfingers: {}, personCache: {},
isArticle: bool, isArticle: bool,
@ -1961,7 +1970,7 @@ def sendPost(projectVersion: str,
followersOnly, saveToFile, clientToServer, followersOnly, saveToFile, clientToServer,
commentsEnabled, commentsEnabled,
attachImageFilename, mediaType, attachImageFilename, mediaType,
imageDescription, imageDescription, city,
False, isArticle, inReplyTo, False, isArticle, inReplyTo,
inReplyToAtomUri, subject, inReplyToAtomUri, subject,
False, None, None, None, None, None, False, None, None, None, None, None,
@ -2023,7 +2032,7 @@ def sendPostViaServer(projectVersion: str,
httpPrefix: str, content: str, followersOnly: bool, httpPrefix: str, content: str, followersOnly: bool,
commentsEnabled: bool, commentsEnabled: bool,
attachImageFilename: str, mediaType: str, attachImageFilename: str, mediaType: str,
imageDescription: str, imageDescription: str, city: str,
cachedWebfingers: {}, personCache: {}, cachedWebfingers: {}, personCache: {},
isArticle: bool, debug=False, inReplyTo=None, isArticle: bool, debug=False, inReplyTo=None,
inReplyToAtomUri=None, subject=None) -> int: inReplyToAtomUri=None, subject=None) -> int:
@ -2100,7 +2109,7 @@ def sendPostViaServer(projectVersion: str,
followersOnly, saveToFile, clientToServer, followersOnly, saveToFile, clientToServer,
commentsEnabled, commentsEnabled,
attachImageFilename, mediaType, attachImageFilename, mediaType,
imageDescription, imageDescription, city,
False, isArticle, inReplyTo, False, isArticle, inReplyTo,
inReplyToAtomUri, subject, inReplyToAtomUri, subject,
False, None, None, None, None, None, False, None, None, None, None, None,

View File

@ -108,7 +108,8 @@ def _updatePostSchedule(baseDir: str, handle: str, httpd,
httpd.debug, httpd.debug,
httpd.YTReplacementDomain, httpd.YTReplacementDomain,
httpd.showPublishedDateOnly, httpd.showPublishedDateOnly,
httpd.allowLocalNetworkAccess): httpd.allowLocalNetworkAccess,
httpd.city):
indexLines.remove(line) indexLines.remove(line)
os.remove(postFilename) os.remove(postFilename)
continue continue

View File

@ -18,7 +18,7 @@ from utils import validNickname
from utils import loadJson from utils import loadJson
from utils import saveJson from utils import saveJson
from utils import getImageExtensions from utils import getImageExtensions
from media import removeMetaData from media import processMetaData
def getValidSharedItemID(displayName: str) -> str: def getValidSharedItemID(displayName: str) -> str:
@ -73,7 +73,7 @@ def addShare(baseDir: str,
httpPrefix: str, nickname: str, domain: str, port: int, httpPrefix: str, nickname: str, domain: str, port: int,
displayName: str, summary: str, imageFilename: str, displayName: str, summary: str, imageFilename: str,
itemType: str, itemCategory: str, location: str, itemType: str, itemCategory: str, location: str,
duration: str, debug: bool) -> None: duration: str, debug: bool, city: str) -> None:
"""Adds a new share """Adds a new share
""" """
sharesFilename = baseDir + '/accounts/' + \ sharesFilename = baseDir + '/accounts/' + \
@ -129,7 +129,9 @@ def addShare(baseDir: str,
formats = getImageExtensions() formats = getImageExtensions()
for ext in formats: for ext in formats:
if imageFilename.endswith('.' + ext): if imageFilename.endswith('.' + ext):
removeMetaData(imageFilename, itemIDfile + '.' + ext) processMetaData(baseDir, nickname, domain,
imageFilename, itemIDfile + '.' + ext,
city)
if moveImage: if moveImage:
os.remove(imageFilename) os.remove(imageFilename)
imageUrl = \ imageUrl = \
@ -512,7 +514,7 @@ def sendUndoShareViaServer(baseDir: str, session,
def outboxShareUpload(baseDir: str, httpPrefix: str, def outboxShareUpload(baseDir: str, httpPrefix: str,
nickname: str, domain: str, port: int, 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 """ When a shared item is received by the outbox from c2s
""" """
if not messageJson.get('type'): if not messageJson.get('type'):
@ -564,7 +566,7 @@ def outboxShareUpload(baseDir: str, httpPrefix: str,
messageJson['object']['itemCategory'], messageJson['object']['itemCategory'],
messageJson['object']['location'], messageJson['object']['location'],
messageJson['object']['duration'], messageJson['object']['duration'],
debug) debug, city)
if debug: if debug:
print('DEBUG: shared item received via c2s') print('DEBUG: shared item received via c2s')

128
tests.py
View File

@ -10,6 +10,8 @@ import time
import os import os
import shutil import shutil
import json import json
import datetime
from random import randint
from time import gmtime, strftime from time import gmtime, strftime
from pprint import pprint from pprint import pprint
from httpsig import signPostHeaders from httpsig import signPostHeaders
@ -75,6 +77,7 @@ from like import likePost
from like import sendLikeViaServer from like import sendLikeViaServer
from announce import announcePublic from announce import announcePublic
from announce import sendAnnounceViaServer from announce import sendAnnounceViaServer
from media import spoofGeolocation
from media import getMediaPath from media import getMediaPath
from media import getAttachmentMediaType from media import getAttachmentMediaType
from delete import sendDeleteViaServer from delete import sendDeleteViaServer
@ -463,6 +466,7 @@ def createServerAlice(path: str, domain: str, port: int,
testAttachImageFilename = None testAttachImageFilename = None
testMediaType = None testMediaType = None
testImageDescription = None testImageDescription = None
testCity = 'London, England'
createPublicPost(path, nickname, domain, port, httpPrefix, createPublicPost(path, nickname, domain, port, httpPrefix,
"No wise fish would go anywhere without a porpoise", "No wise fish would go anywhere without a porpoise",
testFollowersOnly, testFollowersOnly,
@ -471,7 +475,7 @@ def createServerAlice(path: str, domain: str, port: int,
testCommentsEnabled, testCommentsEnabled,
testAttachImageFilename, testAttachImageFilename,
testMediaType, testMediaType,
testImageDescription) testImageDescription, testCity)
createPublicPost(path, nickname, domain, port, httpPrefix, createPublicPost(path, nickname, domain, port, httpPrefix,
"Curiouser and curiouser!", "Curiouser and curiouser!",
testFollowersOnly, testFollowersOnly,
@ -480,7 +484,7 @@ def createServerAlice(path: str, domain: str, port: int,
testCommentsEnabled, testCommentsEnabled,
testAttachImageFilename, testAttachImageFilename,
testMediaType, testMediaType,
testImageDescription) testImageDescription, testCity)
createPublicPost(path, nickname, domain, port, httpPrefix, createPublicPost(path, nickname, domain, port, httpPrefix,
"In the gardens of memory, in the palace " + "In the gardens of memory, in the palace " +
"of dreams, that is where you and I shall meet", "of dreams, that is where you and I shall meet",
@ -490,7 +494,7 @@ def createServerAlice(path: str, domain: str, port: int,
testCommentsEnabled, testCommentsEnabled,
testAttachImageFilename, testAttachImageFilename,
testMediaType, testMediaType,
testImageDescription) testImageDescription, testCity)
global testServerAliceRunning global testServerAliceRunning
testServerAliceRunning = True testServerAliceRunning = True
maxMentions = 10 maxMentions = 10
@ -506,8 +510,10 @@ def createServerAlice(path: str, domain: str, port: int,
brochMode = False brochMode = False
showNodeInfoAccounts = True showNodeInfoAccounts = True
showNodeInfoVersion = True showNodeInfoVersion = True
city = 'London, England'
print('Server running: Alice') print('Server running: Alice')
runDaemon(showNodeInfoAccounts, runDaemon(city,
showNodeInfoAccounts,
showNodeInfoVersion, showNodeInfoVersion,
brochMode, brochMode,
verifyAllSignatures, verifyAllSignatures,
@ -564,6 +570,7 @@ def createServerBob(path: str, domain: str, port: int,
testAttachImageFilename = None testAttachImageFilename = None
testImageDescription = None testImageDescription = None
testMediaType = None testMediaType = None
testCity = 'London, England'
createPublicPost(path, nickname, domain, port, httpPrefix, createPublicPost(path, nickname, domain, port, httpPrefix,
"It's your life, live it your way.", "It's your life, live it your way.",
testFollowersOnly, testFollowersOnly,
@ -572,7 +579,7 @@ def createServerBob(path: str, domain: str, port: int,
testCommentsEnabled, testCommentsEnabled,
testAttachImageFilename, testAttachImageFilename,
testMediaType, testMediaType,
testImageDescription) testImageDescription, testCity)
createPublicPost(path, nickname, domain, port, httpPrefix, createPublicPost(path, nickname, domain, port, httpPrefix,
"One of the things I've realised is that " + "One of the things I've realised is that " +
"I am very simple", "I am very simple",
@ -582,7 +589,7 @@ def createServerBob(path: str, domain: str, port: int,
testCommentsEnabled, testCommentsEnabled,
testAttachImageFilename, testAttachImageFilename,
testMediaType, testMediaType,
testImageDescription) testImageDescription, testCity)
createPublicPost(path, nickname, domain, port, httpPrefix, createPublicPost(path, nickname, domain, port, httpPrefix,
"Quantum physics is a bit of a passion of mine", "Quantum physics is a bit of a passion of mine",
testFollowersOnly, testFollowersOnly,
@ -591,7 +598,7 @@ def createServerBob(path: str, domain: str, port: int,
testCommentsEnabled, testCommentsEnabled,
testAttachImageFilename, testAttachImageFilename,
testMediaType, testMediaType,
testImageDescription) testImageDescription, testCity)
global testServerBobRunning global testServerBobRunning
testServerBobRunning = True testServerBobRunning = True
maxMentions = 10 maxMentions = 10
@ -607,8 +614,10 @@ def createServerBob(path: str, domain: str, port: int,
brochMode = False brochMode = False
showNodeInfoAccounts = True showNodeInfoAccounts = True
showNodeInfoVersion = True showNodeInfoVersion = True
city = 'London, England'
print('Server running: Bob') print('Server running: Bob')
runDaemon(showNodeInfoAccounts, runDaemon(city,
showNodeInfoAccounts,
showNodeInfoVersion, showNodeInfoVersion,
brochMode, brochMode,
verifyAllSignatures, verifyAllSignatures,
@ -662,8 +671,10 @@ def createServerEve(path: str, domain: str, port: int, federationList: [],
brochMode = False brochMode = False
showNodeInfoAccounts = True showNodeInfoAccounts = True
showNodeInfoVersion = True showNodeInfoVersion = True
city = 'London, England'
print('Server running: Eve') print('Server running: Eve')
runDaemon(showNodeInfoAccounts, runDaemon(city,
showNodeInfoAccounts,
showNodeInfoVersion, showNodeInfoVersion,
brochMode, brochMode,
verifyAllSignatures, verifyAllSignatures,
@ -768,6 +779,7 @@ def testPostMessageBetweenServers():
mediaType = getAttachmentMediaType(attachedImageFilename) mediaType = getAttachmentMediaType(attachedImageFilename)
attachedImageDescription = 'Logo' attachedImageDescription = 'Logo'
isArticle = False isArticle = False
city = 'London, England'
# nothing in Alice's outbox # nothing in Alice's outbox
outboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/outbox' outboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/outbox'
assert len([name for name in os.listdir(outboxPath) assert len([name for name in os.listdir(outboxPath)
@ -782,7 +794,7 @@ def testPostMessageBetweenServers():
followersOnly, followersOnly,
saveToFile, clientToServer, True, saveToFile, clientToServer, True,
attachedImageFilename, mediaType, attachedImageFilename, mediaType,
attachedImageDescription, federationList, attachedImageDescription, city, federationList,
aliceSendThreads, alicePostLog, aliceCachedWebfingers, aliceSendThreads, alicePostLog, aliceCachedWebfingers,
alicePersonCache, isArticle, inReplyTo, alicePersonCache, isArticle, inReplyTo,
inReplyToAtomUri, subject) inReplyToAtomUri, subject)
@ -1085,13 +1097,14 @@ def testFollowBetweenServers():
aliceCachedWebfingers = {} aliceCachedWebfingers = {}
alicePostLog = [] alicePostLog = []
isArticle = False isArticle = False
city = 'London, England'
sendResult = \ sendResult = \
sendPost(__version__, sendPost(__version__,
sessionAlice, aliceDir, 'alice', aliceDomain, alicePort, sessionAlice, aliceDir, 'alice', aliceDomain, alicePort,
'bob', bobDomain, bobPort, ccUrl, 'bob', bobDomain, bobPort, ccUrl,
httpPrefix, 'Alice message', followersOnly, saveToFile, httpPrefix, 'Alice message', followersOnly, saveToFile,
clientToServer, True, clientToServer, True,
None, None, None, federationList, None, None, None, city, federationList,
aliceSendThreads, alicePostLog, aliceCachedWebfingers, aliceSendThreads, alicePostLog, aliceCachedWebfingers,
alicePersonCache, isArticle, inReplyTo, alicePersonCache, isArticle, inReplyTo,
inReplyToAtomUri, subject) inReplyToAtomUri, subject)
@ -1390,7 +1403,7 @@ def testCreatePerson():
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"G'day world!", False, True, clientToServer, "G'day world!", False, True, clientToServer,
True, None, None, None, None, True, None, None, None, None,
'Not suitable for Vogons') 'Not suitable for Vogons', 'London, England')
os.chdir(currDir) os.chdir(currDir)
shutil.rmtree(baseDir) shutil.rmtree(baseDir)
@ -1593,6 +1606,7 @@ def testClientToServer():
attachedImageFilename = baseDir + '/img/logo.png' attachedImageFilename = baseDir + '/img/logo.png'
mediaType = getAttachmentMediaType(attachedImageFilename) mediaType = getAttachmentMediaType(attachedImageFilename)
attachedImageDescription = 'Logo' attachedImageDescription = 'Logo'
city = 'London, England'
isArticle = False isArticle = False
cachedWebfingers = {} cachedWebfingers = {}
personCache = {} personCache = {}
@ -1611,7 +1625,7 @@ def testClientToServer():
httpPrefix, 'Sent from my ActivityPub client', httpPrefix, 'Sent from my ActivityPub client',
followersOnly, True, followersOnly, True,
attachedImageFilename, mediaType, attachedImageFilename, mediaType,
attachedImageDescription, attachedImageDescription, city,
cachedWebfingers, personCache, isArticle, cachedWebfingers, personCache, isArticle,
True, None, None, None) True, None, None, None)
print('sendResult: ' + str(sendResult)) print('sendResult: ' + str(sendResult))
@ -2822,11 +2836,21 @@ def testReplyToPublicPost() -> None:
port = 443 port = 443
httpPrefix = 'https' httpPrefix = 'https'
postId = httpPrefix + '://rat.site/users/ninjarodent/statuses/63746173435' 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 = \ reply = \
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"@ninjarodent@rat.site This is a test.", content, followersOnly, saveToFile,
False, False, False, True, clientToServer, commentsEnabled,
None, None, False, postId) attachImageFilename, mediaType,
imageDescription, city, postId)
# print(str(reply)) # print(str(reply))
assert reply['object']['content'] == \ assert reply['object']['content'] == \
'<p><span class=\"h-card\">' + \ '<p><span class=\"h-card\">' + \
@ -3244,11 +3268,20 @@ def testLinksWithinPost() -> None:
httpPrefix = 'https' httpPrefix = 'https'
content = 'This is a test post with links.\n\n' + \ content = 'This is a test post with links.\n\n' + \
'ftp://ftp.ncdc.noaa.gov/pub/data/ghcn/v4/\n\nhttps://freedombone.net' '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 = \ postJsonObject = \
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
content, content, followersOnly, saveToFile,
False, False, False, True, clientToServer, commentsEnabled,
None, None, False, None) mediaType, imageDescription, city,
False, None)
assert postJsonObject['object']['content'] == \ assert postJsonObject['object']['content'] == \
'<p>This is a test post with links.<br><br>' + \ '<p>This is a test post with links.<br><br>' + \
'<a href="ftp://ftp.ncdc.noaa.gov/pub/data/ghcn/v4/" ' + \ '<a href="ftp://ftp.ncdc.noaa.gov/pub/data/ghcn/v4/" ' + \
@ -3636,9 +3669,66 @@ def testRemovePostInteractions() -> None:
assert not removePostInteractions(postJsonObject, False) 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(): def runAllTests():
print('Running tests...') print('Running tests...')
testFunctions() testFunctions()
testSpoofGeolocation()
testRemovePostInteractions() testRemovePostInteractions()
testExtractPGPPublicKey() testExtractPGPPublicKey()
testEmojiImages() testEmojiImages()

View File

@ -440,5 +440,6 @@
"These access keys may be used": "قد يتم استخدام مفاتيح الوصول هذه، عادة مع مفتاح ALT + SHIFT + مفتاح ALT +", "These access keys may be used": "قد يتم استخدام مفاتيح الوصول هذه، عادة مع مفتاح ALT + SHIFT + مفتاح ALT +",
"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": "تاريخ الانضمام",
"City for spoofed GPS image metadata": "مدينة للبيانات الوصفية لصور GPS المخادعة"
} }

View File

@ -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", "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 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", "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"
} }

View File

@ -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 +", "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 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", "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"
} }

View File

@ -440,5 +440,6 @@
"These access keys may be used": "Diese Zugriffstasten können verwendet werden, typischerweise mit ALT + SHIFT + -Taste oder ALT + -Taste", "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 numbers of accounts within instance metadata": "Anzahl der Konten in Instanzmetadaten anzeigen",
"Show version number within instance metadata": "Versionsnummer 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"
} }

View File

@ -440,5 +440,6 @@
"These access keys may be used": "These access keys may be used, typically with ALT + SHIFT + key or ALT + key", "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 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", "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"
} }

View File

@ -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 +", "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 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", "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"
} }

View File

@ -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 +", "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 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", "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"
} }

View File

@ -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", "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 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í", "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"
} }

View File

@ -440,5 +440,6 @@
"These access keys may be used": "इन एक्सेस कुंजियों का उपयोग किया जा सकता है, आमतौर पर Alt + Shift + कुंजी या Alt + कुंजी के साथ", "These access keys may be used": "इन एक्सेस कुंजियों का उपयोग किया जा सकता है, आमतौर पर Alt + Shift + कुंजी या Alt + कुंजी के साथ",
"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": "दिनांक",
"City for spoofed GPS image metadata": "स्पूफ जीपीएस जीपीएस मेटाडेटा के लिए शहर"
} }

View File

@ -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", "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 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", "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"
} }

View File

@ -440,5 +440,6 @@
"These access keys may be used": "これらのアクセスキーは、通常はAlt + Shift +キーまたはAlt +キーを使用して使用できます。", "These access keys may be used": "これらのアクセスキーは、通常はAlt + Shift +キーまたはAlt +キーを使用して使用できます。",
"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": "参加日",
"City for spoofed GPS image metadata": "なりすましGPS画像メタデータの都市"
} }

View File

@ -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", "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 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", "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"
} }

View File

@ -436,5 +436,6 @@
"These access keys may be used": "These access keys may be used, typically with ALT + SHIFT + key or ALT + key", "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 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", "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"
} }

View File

@ -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 +", "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 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", "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"
} }

View File

@ -440,5 +440,6 @@
"These access keys may be used": "Эти ключевые ключи доступа могут быть использованы, обычно с ALT + Shift + Key или Alt + Key", "These access keys may be used": "Эти ключевые ключи доступа могут быть использованы, обычно с ALT + Shift + Key или 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": "Присоединенная дата",
"City for spoofed GPS image metadata": "Город для поддельных метаданных изображения GPS"
} }

View File

@ -440,5 +440,6 @@
"These access keys may be used": "可以使用这些访问密钥通常使用Alt + Shift +键或ALT +键", "These access keys may be used": "可以使用这些访问密钥通常使用Alt + Shift +键或ALT +键",
"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": "加入日期",
"City for spoofed GPS image metadata": "欺骗性GPS影像元数据的城市"
} }

View File

@ -1068,7 +1068,7 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
domain: str, port: int, httpPrefix: str, domain: str, port: int, httpPrefix: str,
defaultTimeline: str, theme: str, defaultTimeline: str, theme: str,
peertubeInstances: [], peertubeInstances: [],
textModeBanner: str) -> str: textModeBanner: str, city: str) -> str:
"""Shows the edit profile screen """Shows the edit profile screen
""" """
imageFormats = getImageFormats() imageFormats = getImageFormats()
@ -1770,6 +1770,41 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
editProfileForm += '<details><summary class="cw">' + \ editProfileForm += '<details><summary class="cw">' + \
translate['Filtering and Blocking'] + '</summary>\n' translate['Filtering and Blocking'] + '</summary>\n'
editProfileForm += ' <div class="container">\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 += \ editProfileForm += \
' <b><label class="labels">' + \ ' <b><label class="labels">' + \
translate['Filtered words'] + '</label></b>\n' translate['Filtered words'] + '</label></b>\n'

View File

@ -543,6 +543,8 @@ def getPersonAvatarUrl(baseDir: str, personUrl: str, personCache: {},
return None return None
# get from locally stored image # get from locally stored image
if not personJson.get('id'):
return None
actorStr = personJson['id'].replace('/', '-') actorStr = personJson['id'].replace('/', '-')
avatarImagePath = baseDir + '/cache/avatars/' + actorStr avatarImagePath = baseDir + '/cache/avatars/' + actorStr