From edf36ecd52a565afa769692fa534757a2ac8681d Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 11 Jul 2020 15:00:49 +0100 Subject: [PATCH 01/18] Permitted path --- daemon.py | 1 + 1 file changed, 1 insertion(+) diff --git a/daemon.py b/daemon.py index 152285641..c1ea430d6 100644 --- a/daemon.py +++ b/daemon.py @@ -7952,6 +7952,7 @@ class PubServer(BaseHTTPRequestHandler): if not (self.path.endswith('/outbox') or self.path.endswith('/inbox') or self.path.endswith('/shares') or + self.path.endswith('/rmpost') or self.path.endswith('/moderationaction') or self.path.endswith('/caps/new') or self.path == '/sharedInbox'): From 19232de12744b7a0369fda30b1a2361ee7656db8 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 11 Jul 2020 15:22:05 +0100 Subject: [PATCH 02/18] Check for unauthorized removals --- daemon.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/daemon.py b/daemon.py index c1ea430d6..e262ce630 100644 --- a/daemon.py +++ b/daemon.py @@ -7142,6 +7142,12 @@ class PubServer(BaseHTTPRequestHandler): self._benchmarkPOSTtimings(POSTstartTime, POSTtimings, 8) # removes a post + if not authorized and self.path.endswith('/rmpost'): + print('ERROR: attempt to remove post was not authorized. ' + + self.path) + self._400() + self.server.POSTbusy = False + return if authorized and self.path.endswith('/rmpost'): pageNumber = 1 usersPath = self.path.split('/rmpost')[0] @@ -7952,7 +7958,6 @@ class PubServer(BaseHTTPRequestHandler): if not (self.path.endswith('/outbox') or self.path.endswith('/inbox') or self.path.endswith('/shares') or - self.path.endswith('/rmpost') or self.path.endswith('/moderationaction') or self.path.endswith('/caps/new') or self.path == '/sharedInbox'): From 68a1559881b8ebc29519b2fe35796719abf5388a Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 11 Jul 2020 16:10:30 +0100 Subject: [PATCH 03/18] Report auth failures --- daemon.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/daemon.py b/daemon.py index e262ce630..623264b96 100644 --- a/daemon.py +++ b/daemon.py @@ -1067,19 +1067,18 @@ class PubServer(BaseHTTPRequestHandler): # to be authorized to use an account you don't own if '/' + nickname + '/' in self.path: return True - if '/' + nickname + '?' in self.path: + elif '/' + nickname + '?' in self.path: return True - if self.path.endswith('/'+nickname): + elif self.path.endswith('/'+nickname): return True print('AUTH: nickname ' + nickname + ' was not found in path ' + self.path) return False - if self.server.debug: - print('AUTH: epicyon cookie ' + - 'authorization failed, header=' + - self.headers['Cookie'].replace('epicyon=', '') + - ' tokenStr=' + tokenStr + ' tokens=' + - str(self.server.tokensLookup)) + print('AUTH: epicyon cookie ' + + 'authorization failed, header=' + + self.headers['Cookie'].replace('epicyon=', '') + + ' tokenStr=' + tokenStr + ' tokens=' + + str(self.server.tokensLookup)) return False print('AUTH: Header cookie was not authorized') return False From bbaa8ac8419b338d4d4172b854a0f3288c4278dc Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 11 Jul 2020 16:45:22 +0100 Subject: [PATCH 04/18] Show authorization --- daemon.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/daemon.py b/daemon.py index 623264b96..6f4cf0768 100644 --- a/daemon.py +++ b/daemon.py @@ -5786,12 +5786,11 @@ class PubServer(BaseHTTPRequestHandler): # check authorization authorized = self._isAuthorized() - if self.server.debug: - if authorized: - print('POST Authorization granted') - else: - print('POST Not authorized') - print(str(self.headers)) + if authorized: + print('POST Authorization granted') + else: + print('POST Not authorized') + print(str(self.headers)) # if this is a POST to the outbox then check authentication self.outboxAuthenticated = False From cb533b1222dd72eead3a96ae33e42c54987ad819 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 11 Jul 2020 16:49:26 +0100 Subject: [PATCH 05/18] Simplify --- daemon.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/daemon.py b/daemon.py index 6f4cf0768..f93c3456e 100644 --- a/daemon.py +++ b/daemon.py @@ -5786,9 +5786,7 @@ class PubServer(BaseHTTPRequestHandler): # check authorization authorized = self._isAuthorized() - if authorized: - print('POST Authorization granted') - else: + if not authorized: print('POST Not authorized') print(str(self.headers)) From 4b5040890ae9c387350bb882406d2ddf5ea68cca Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 11 Jul 2020 16:54:58 +0100 Subject: [PATCH 06/18] Debug --- daemon.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/daemon.py b/daemon.py index f93c3456e..670ee4f1c 100644 --- a/daemon.py +++ b/daemon.py @@ -3090,6 +3090,12 @@ class PubServer(BaseHTTPRequestHandler): # delete a post from the web interface icon if htmlGET and '?delete=' in self.path: + if not cookie: + print('ERROR: no cookie given when deleting') + self._400() + self.server.GETbusy = False + return + print('Cookie for delete: ' + str(cookie)) pageNumber = 1 if '?page=' in self.path: pageNumberStr = self.path.split('?page=')[1] From e59796b42693458fd3efaf2b8d5426487933e34e Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 11 Jul 2020 17:57:00 +0100 Subject: [PATCH 07/18] Use calling domain when generating delete screen --- daemon.py | 2 +- webinterface.py | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/daemon.py b/daemon.py index 670ee4f1c..7cf42ff95 100644 --- a/daemon.py +++ b/daemon.py @@ -3164,7 +3164,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.session, self.server.baseDir, deleteUrl, self.server.httpPrefix, __version__, self.server.cachedWebfingers, - self.server.personCache) + self.server.personCache, callingDomain) if deleteStr: self._set_headers('text/html', len(deleteStr), cookie, callingDomain) diff --git a/webinterface.py b/webinterface.py index d7e86d6cd..b57c388c8 100644 --- a/webinterface.py +++ b/webinterface.py @@ -5112,7 +5112,8 @@ def htmlDeletePost(recentPostsCache: {}, maxRecentPosts: int, translate, pageNumber: int, session, baseDir: str, messageId: str, httpPrefix: str, projectVersion: str, - wfRequest: {}, personCache: {}) -> str: + wfRequest: {}, personCache: {}, + callingDomain: str) -> str: """Shows a screen asking to confirm the deletion of a post """ if '/statuses/' not in messageId: @@ -5121,6 +5122,10 @@ def htmlDeletePost(recentPostsCache: {}, maxRecentPosts: int, actor = messageId.split('/statuses/')[0] nickname = getNicknameFromActor(actor) domain, port = getDomainFromActor(actor) + domainFull = domain + if port: + if port != 80 and port != 443: + domainFull = domain + ':' + str(port) postFilename = locatePost(baseDir, nickname, domain, messageId) if not postFilename: @@ -5157,7 +5162,16 @@ def htmlDeletePost(recentPostsCache: {}, maxRecentPosts: int, deletePostStr += \ '

' + \ translate['Delete this post?'] + '

' - deletePostStr += '
' + postActor = actor + if callingDomain not in actor and domainFull in actor: + if callingDomain.endswith('.onion') or \ + callingDomain.endswith('.i2p'): + postActor = \ + 'http://' + callingDomain + actor.split(domainFull)[1] + print('Changed POST domain from ' + actor + ' to ' + postActor) + + deletePostStr += \ + ' ' deletePostStr += \ ' ' From 3c811e9809846ec22c0c9af5ed76960d374fe9b0 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 11 Jul 2020 18:00:56 +0100 Subject: [PATCH 08/18] Remove debug --- daemon.py | 1 - 1 file changed, 1 deletion(-) diff --git a/daemon.py b/daemon.py index 7cf42ff95..9c0036492 100644 --- a/daemon.py +++ b/daemon.py @@ -3095,7 +3095,6 @@ class PubServer(BaseHTTPRequestHandler): self._400() self.server.GETbusy = False return - print('Cookie for delete: ' + str(cookie)) pageNumber = 1 if '?page=' in self.path: pageNumberStr = self.path.split('?page=')[1] From 51d8b9fbe25a4f64383669e94f2e2c4ccdeb9c98 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 11 Jul 2020 18:45:45 +0100 Subject: [PATCH 09/18] Calendar relative path --- webinterface.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/webinterface.py b/webinterface.py index b57c388c8..53b63e600 100644 --- a/webinterface.py +++ b/webinterface.py @@ -5829,20 +5829,24 @@ def htmlCalendar(translate: {}, with open(cssFilename, 'r') as cssFile: calendarStyle = cssFile.read() + calActor = actor + if '/users/' in actor: + calActor = '/users/' + actor.split('/users/')[1] + calendarStr = htmlHeader(cssFilename, calendarStyle) calendarStr += '
\n' calendarStr += '
\n' calendarStr += \ - ' ' calendarStr += \ ' ' + translate['Previous month'] + \
         '\n' - calendarStr += ' ' + calendarStr += ' ' calendarStr += '

' + monthName + '

\n' calendarStr += \ - ' ' calendarStr += \ ' ' + translate['Next month'] + \
@@ -5884,7 +5888,7 @@ def htmlCalendar(translate: {},
                         if dayOfMonth == currDate.day:
                             isToday = True
                 if events.get(str(dayOfMonth)):
-                    url = actor + '/calendar?year=' + str(year) + '?month=' + \
+                    url = calActor + '/calendar?year=' + str(year) + '?month=' + \
                         str(monthNumber) + '?day=' + str(dayOfMonth)
                     dayLink = '<a href=' + \ str(dayOfMonth) + '' From ce04a4cf7ab2a76fc5d017117f05837c42a715e6 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 11 Jul 2020 18:49:45 +0100 Subject: [PATCH 10/18] Calendar day --- webinterface.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/webinterface.py b/webinterface.py index 53b63e600..77ebd0060 100644 --- a/webinterface.py +++ b/webinterface.py @@ -5648,11 +5648,15 @@ def htmlCalendarDay(translate: {}, with open(cssFilename, 'r') as cssFile: calendarStyle = cssFile.read() + calActor = actor + if '/users/' in actor: + calActor = '/users/' + actor.split('/users/')[1] + calendarStr = htmlHeader(cssFilename, calendarStyle) calendarStr += '
\n' calendarStr += '
\n' calendarStr += \ - ' ' calendarStr += \ '

' + str(dayNumber) + ' ' + monthName + \ @@ -5687,7 +5691,7 @@ def htmlCalendarDay(translate: {}, deleteButtonStr = '' if postId: deleteButtonStr = \ - '

' + \ str(dayOfMonth) + '' From 5fb01a6368b7f82c3f2d7885ea8f9e203cb6ad10 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 11 Jul 2020 21:17:55 +0100 Subject: [PATCH 12/18] Tidying --- daemon.py | 3 ++- webinterface.py | 28 +++++++++++++++++++--------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/daemon.py b/daemon.py index 9c0036492..112e5c9f6 100644 --- a/daemon.py +++ b/daemon.py @@ -2386,7 +2386,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.httpPrefix, self.server.domainFull, postId, postTime, - postYear, postMonth, postDay) + postYear, postMonth, postDay, + callingDomain) if not msg: actor = \ self.server.httpPrefix + '://' + \ diff --git a/webinterface.py b/webinterface.py index 59ef09d1b..26683ac9d 100644 --- a/webinterface.py +++ b/webinterface.py @@ -79,6 +79,19 @@ from petnames import getPetName from followingCalendar import receivingCalendarEvents +def getUrlPath(actor: str, domainFull: str, callingDomain: str) -> str: + """Returns path from url + """ + postActor = actor + if callingDomain not in actor and domainFull in actor: + if callingDomain.endswith('.onion') or \ + callingDomain.endswith('.i2p'): + postActor = \ + 'http://' + callingDomain + actor.split(domainFull)[1] + print('Changed POST domain from ' + actor + ' to ' + postActor) + return postActor + + def getContentWarningButton(postID: str, translate: {}, content: str) -> str: """Returns the markup for a content warning button @@ -5162,14 +5175,8 @@ def htmlDeletePost(recentPostsCache: {}, maxRecentPosts: int, deletePostStr += \ '

' + \ translate['Delete this post?'] + '

' - postActor = actor - if callingDomain not in actor and domainFull in actor: - if callingDomain.endswith('.onion') or \ - callingDomain.endswith('.i2p'): - postActor = \ - 'http://' + callingDomain + actor.split(domainFull)[1] - print('Changed POST domain from ' + actor + ' to ' + postActor) + postActor = getUrlPath(actor, domainFull, callingDomain) deletePostStr += \ ' ' deletePostStr += \ @@ -5194,7 +5201,7 @@ def htmlCalendarDeleteConfirm(translate: {}, baseDir: str, path: str, httpPrefix: str, domainFull: str, postId: str, postTime: str, year: int, monthNumber: int, - dayNumber: int) -> str: + dayNumber: int, callingDomain: str) -> str: """Shows a screen asking to confirm the deletion of a calendar event """ nickname = getNicknameFromActor(path) @@ -5232,7 +5239,10 @@ def htmlCalendarDeleteConfirm(translate: {}, baseDir: str, deletePostStr += '
' deletePostStr += '

' + \ translate['Delete this event'] + '

' - deletePostStr += ' ' + + postActor = getUrlPath(actor, domainFull, callingDomain) + deletePostStr += \ + ' ' deletePostStr += ' ' deletePostStr += ' ' sharedItemsForm += '

' if not resultsExist and currPage > 1: + postActor = \ + getUrlPath(actor, domainFull, + callingDomain) # previous page link, needs to be a POST sharedItemsForm += \ - '' sharedItemsForm += \ @@ -578,9 +583,13 @@ def htmlSearchSharedItems(translate: {}, if ctr >= resultsPerPage: currPage += 1 if currPage > pageNumber: + postActor = \ + getUrlPath(actor, domainFull, + callingDomain) # next page link, needs to be a POST sharedItemsForm += \ - '' sharedItemsForm += \ @@ -5060,12 +5069,17 @@ def htmlPostReplies(recentPostsCache: {}, maxRecentPosts: int, def htmlRemoveSharedItem(translate: {}, baseDir: str, - actor: str, shareName: str) -> str: + actor: str, shareName: str, + callingDomain: str) -> str: """Shows a screen asking to confirm the removal of a shared item """ itemID = getValidSharedItemID(shareName) nickname = getNicknameFromActor(actor) domain, port = getDomainFromActor(actor) + domainFull = domain + if port: + if port != 80 and port != 443: + domainFull = domain + ':' + str(port) sharesFile = baseDir + '/accounts/' + \ nickname + '@' + domain + '/shares.json' if not os.path.isfile(sharesFile): @@ -5103,7 +5117,8 @@ def htmlRemoveSharedItem(translate: {}, baseDir: str, sharesStr += \ '

' + translate['Remove'] + \ ' ' + sharedItemDisplayName + ' ?

' - sharesStr += ' ' + postActor = getUrlPath(actor, domainFull, callingDomain) + sharesStr += ' ' sharesStr += ' ' sharesStr += ' ' From b9cbbdb9c8de68140cdf348dbece47115059822a Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 11 Jul 2020 21:41:25 +0100 Subject: [PATCH 14/18] Comment --- webinterface.py | 1 + 1 file changed, 1 insertion(+) diff --git a/webinterface.py b/webinterface.py index d62f12cad..b607f7111 100644 --- a/webinterface.py +++ b/webinterface.py @@ -81,6 +81,7 @@ from followingCalendar import receivingCalendarEvents def getUrlPath(actor: str, domainFull: str, callingDomain: str) -> str: """Returns path from url + eg. https://somedomain/users/bob becomes /users/bob """ postActor = actor if callingDomain not in actor and domainFull in actor: From ad55ea6f970b42430c18c80fc0521860e4a24d7d Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 11 Jul 2020 21:44:20 +0100 Subject: [PATCH 15/18] Rename function --- webinterface.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/webinterface.py b/webinterface.py index b607f7111..85faa020b 100644 --- a/webinterface.py +++ b/webinterface.py @@ -79,9 +79,9 @@ from petnames import getPetName from followingCalendar import receivingCalendarEvents -def getUrlPath(actor: str, domainFull: str, callingDomain: str) -> str: - """Returns path from url - eg. https://somedomain/users/bob becomes /users/bob +def getAltPath(actor: str, domainFull: str, callingDomain: str) -> str: + """Returns alternate path from the actor + eg. https://clearnetdomain/path becomes http://oniondomain/path """ postActor = actor if callingDomain not in actor and domainFull in actor: @@ -552,7 +552,7 @@ def htmlSearchSharedItems(translate: {}, sharedItemsForm += '

' if not resultsExist and currPage > 1: postActor = \ - getUrlPath(actor, domainFull, + getAltPath(actor, domainFull, callingDomain) # previous page link, needs to be a POST sharedItemsForm += \ @@ -585,7 +585,7 @@ def htmlSearchSharedItems(translate: {}, currPage += 1 if currPage > pageNumber: postActor = \ - getUrlPath(actor, domainFull, + getAltPath(actor, domainFull, callingDomain) # next page link, needs to be a POST sharedItemsForm += \ @@ -5118,7 +5118,7 @@ def htmlRemoveSharedItem(translate: {}, baseDir: str, sharesStr += \ '

' + translate['Remove'] + \ ' ' + sharedItemDisplayName + ' ?

' - postActor = getUrlPath(actor, domainFull, callingDomain) + postActor = getAltPath(actor, domainFull, callingDomain) sharesStr += ' ' sharesStr += ' ' sharesStr += ' ' + \ translate['Delete this post?'] + '

' - postActor = getUrlPath(actor, domainFull, callingDomain) + postActor = getAltPath(actor, domainFull, callingDomain) deletePostStr += \ ' ' deletePostStr += \ @@ -5256,7 +5256,7 @@ def htmlCalendarDeleteConfirm(translate: {}, baseDir: str, deletePostStr += '

' + \ translate['Delete this event'] + '

' - postActor = getUrlPath(actor, domainFull, callingDomain) + postActor = getAltPath(actor, domainFull, callingDomain) deletePostStr += \ ' ' deletePostStr += '