diff --git a/daemon.py b/daemon.py index d007ec902..7f16a4f7b 100644 --- a/daemon.py +++ b/daemon.py @@ -6276,6 +6276,11 @@ class PubServer(BaseHTTPRequestHandler): originPathStr = path.split('/followapprove=')[0] followerNickname = originPathStr.replace('/users/', '') followingHandle = path.split('/followapprove=')[1] + if '://' in followingHandle: + handleNickname = getNicknameFromActor(followingHandle) + handleDomain, handlePort = getDomainFromActor(followingHandle) + followingHandle = \ + handleNickname + '@' + getFullDomain(handleDomain, handlePort) if '@' in followingHandle: if not self.server.session: print('Starting new session during follow approval') @@ -6437,6 +6442,11 @@ class PubServer(BaseHTTPRequestHandler): originPathStr = path.split('/followdeny=')[0] followerNickname = originPathStr.replace('/users/', '') followingHandle = path.split('/followdeny=')[1] + if '://' in followingHandle: + handleNickname = getNicknameFromActor(followingHandle) + handleDomain, handlePort = getDomainFromActor(followingHandle) + followingHandle = \ + handleNickname + '@' + getFullDomain(handleDomain, handlePort) if '@' in followingHandle: manualDenyFollowRequest(self.server.session, baseDir, httpPrefix, diff --git a/follow.py b/follow.py index 6c88c1adf..e4d20d815 100644 --- a/follow.py +++ b/follow.py @@ -84,7 +84,7 @@ def _removeFromFollowBase(baseDir: str, nickname: str, domain: str, acceptOrDenyHandle: str, followFile: str, debug: bool) -> None: - """Removes a handle from follow requests or rejects file + """Removes a handle/actor from follow requests or rejects file """ handle = nickname + '@' + domain accountsDir = baseDir + '/accounts/' + handle @@ -94,13 +94,34 @@ def _removeFromFollowBase(baseDir: str, print('WARN: Approve follow requests file ' + approveFollowsFilename + ' not found') return + acceptDenyActor = None if acceptOrDenyHandle not in open(approveFollowsFilename).read(): - return + # is this stored in the file as an actor rather than a handle? + acceptDenyNickname = acceptOrDenyHandle.split('@')[0] + acceptDenyDomain = acceptOrDenyHandle.split('@')[1] + # for each possible users path construct an actor and + # check if it exists in teh file + usersPaths = ('users', 'profile', 'channel', 'accounts', 'u') + actorFound = False + for usersName in usersPaths: + acceptDenyActor = \ + '://' + acceptDenyDomain + '/' + \ + usersName + '/' + acceptDenyNickname + if acceptDenyActor in open(approveFollowsFilename).read(): + actorFound = True + break + if not actorFound: + return approvefilenew = open(approveFollowsFilename + '.new', 'w+') with open(approveFollowsFilename, 'r') as approvefile: - for approveHandle in approvefile: - if not approveHandle.startswith(acceptOrDenyHandle): - approvefilenew.write(approveHandle) + if not acceptDenyActor: + for approveHandle in approvefile: + if not approveHandle.startswith(acceptOrDenyHandle): + approvefilenew.write(approveHandle) + else: + for approveHandle in approvefile: + if acceptDenyActor not in approveHandle: + approvefilenew.write(approveHandle) approvefilenew.close() os.rename(approveFollowsFilename + '.new', approveFollowsFilename) diff --git a/notifications_client.py b/notifications_client.py index 7359764dc..b27fb0b21 100644 --- a/notifications_client.py +++ b/notifications_client.py @@ -11,7 +11,9 @@ import html import time import sys import select +from pathlib import Path from random import randint +from utils import saveJson from utils import getNicknameFromActor from utils import getDomainFromActor from utils import getFullDomain @@ -29,6 +31,7 @@ from announce import sendAnnounceViaServer from pgp import pgpDecrypt from pgp import hasLocalPGPkey from pgp import pgpEncryptToActor +from pgp import isPGPEncrypted def _waitForKeypress(timeout: int, debug: bool) -> str: @@ -369,6 +372,23 @@ def _notificationNewDM(session, toHandle: str, _sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak) +def _storeMessage(speakerJson: {}) -> None: + """Stores a message for later reading + """ + if not speakerJson.get('published'): + return + homeDir = str(Path.home()) + if not os.path.isdir(homeDir + '/.config'): + os.mkdir(homeDir + '/.config') + if not os.path.isdir(homeDir + '/.config/epicyon'): + os.mkdir(homeDir + '/.config/epicyon') + msgDir = homeDir + '/.config/epicyon/dm' + if not os.path.isdir(msgDir): + os.mkdir(msgDir) + msgFilename = msgDir + '/' + speakerJson['published'] + '.json' + saveJson(speakerJson, msgFilename) + + def runNotificationsClient(baseDir: str, proxyType: str, httpPrefix: str, nickname: str, domain: str, port: int, password: str, screenreader: str, @@ -518,16 +538,16 @@ def runNotificationsClient(baseDir: str, proxyType: str, httpPrefix: str, else: messageStr = speakerJson['say'] + '. ' + \ speakerJson['imageDescription'] - if speakerJson.get('id'): + encryptedMessage = False + if speakerJson.get('id') and \ + isPGPEncrypted(messageStr): + encryptedMessage = True messageStr = pgpDecrypt(messageStr, speakerJson['id']) content = messageStr if speakerJson.get('content'): - if speakerJson.get('id'): - content = pgpDecrypt(speakerJson['content'], - speakerJson['id']) - else: + if not encryptedMessage: content = speakerJson['content'] # say the speaker's name @@ -542,6 +562,12 @@ def runNotificationsClient(baseDir: str, proxyType: str, httpPrefix: str, systemLanguage, espeak, nameStr, gender) + if encryptedMessage: + speakerJson['content'] = content + speakerJson['say'] = messageStr + speakerJson['decrypted'] = True + _storeMessage(speakerJson) + print('') prevSay = speakerJson['say'] diff --git a/pgp.py b/pgp.py index 1720f75bf..c5c65209d 100644 --- a/pgp.py +++ b/pgp.py @@ -52,7 +52,7 @@ def getPGPpubKey(actorJson: {}) -> str: continue if propertyValue['type'] != 'PropertyValue': continue - if '--BEGIN PGP PUBLIC KEY' not in propertyValue['value']: + if not containsPGPPublicKey(propertyValue['value']): continue return propertyValue['value'] return '' @@ -139,7 +139,7 @@ def setPGPpubKey(actorJson: {}, PGPpubKey: str) -> None: if not PGPpubKey: removeKey = True else: - if '--BEGIN PGP PUBLIC KEY' not in PGPpubKey: + if not containsPGPPublicKey(PGPpubKey): removeKey = True if '<' in PGPpubKey: removeKey = True @@ -318,7 +318,7 @@ def _pgpEncrypt(content: str, recipientPubKey: str) -> str: if not encryptResult: return None encryptResult = encryptResult.decode('utf-8') - if '--BEGIN PGP MESSAGE--' not in encryptResult: + if not isPGPEncrypted(encryptResult): return None return encryptResult @@ -343,9 +343,8 @@ def _getPGPPublicKeyFromActor(handle: str, actorJson=None) -> str: continue if not isinstance(tag['value'], str): continue - if '--BEGIN PGP PUBLIC KEY BLOCK--' in tag['value']: - if '--END PGP PUBLIC KEY BLOCK--' in tag['value']: - return tag['value'] + if containsPGPPublicKey(tag['value']): + return tag['value'] return None @@ -370,17 +369,33 @@ def pgpEncryptToActor(content: str, toHandle: str) -> str: return _pgpEncrypt(content, recipientPubKey) +def isPGPEncrypted(content: str) -> bool: + """Returns true if the given content is PGP encrypted + """ + if '--BEGIN PGP MESSAGE--' in content: + if '--END PGP MESSAGE--' in content: + return True + return False + + +def containsPGPPublicKey(content: str) -> bool: + """Returns true if the given content contains a PGP public key + """ + if '--BEGIN PGP PUBLIC KEY BLOCK--' in content: + if '--END PGP PUBLIC KEY BLOCK--' in content: + return True + return False + + def pgpDecrypt(content: str, fromHandle: str) -> str: """ Encrypt using your default pgp key to the given recipient fromHandle can be a handle or actor url """ - if '--BEGIN PGP MESSAGE--' not in content: + if not isPGPEncrypted(content): return content # if the public key is also included within the message then import it - startBlock = '--BEGIN PGP PUBLIC KEY BLOCK--' - endBlock = '--END PGP PUBLIC KEY BLOCK--' - if startBlock in content and endBlock in content: + if containsPGPPublicKey(content): pubKey = extractPGPPublicKey(content) else: pubKey = _getPGPPublicKeyFromActor(content, fromHandle) diff --git a/tests.py b/tests.py index a2adea0ea..00dc92605 100644 --- a/tests.py +++ b/tests.py @@ -103,6 +103,7 @@ from webapp_post import prepareHtmlPostNickname from webapp_utils import markdownToHtml from speaker import speakerReplaceLinks from pgp import extractPGPPublicKey +from pgp import containsPGPPublicKey testServerAliceRunning = False testServerBobRunning = False @@ -3439,6 +3440,8 @@ def testExtractPGPPublicKey(): '=gv5G\n' + \ '-----END PGP PUBLIC KEY BLOCK-----' testStr = "Some introduction\n\n" + pubKey + "\n\nSome message." + assert containsPGPPublicKey(testStr) + assert not containsPGPPublicKey('String without a pgp key') result = extractPGPPublicKey(testStr) assert result assert result == pubKey