From f32d31464a24c977013326926c3fe26f10c85047 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jul 2022 18:36:37 +0100 Subject: [PATCH 01/15] Receiving POST from lynx --- daemon.py | 73 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/daemon.py b/daemon.py index dd82f995c..60cfe2562 100644 --- a/daemon.py +++ b/daemon.py @@ -4918,25 +4918,27 @@ class PubServer(BaseHTTPRequestHandler): users_path = users_path.split('/tags/')[0] actor_str = self._get_instance_url(calling_domain) + users_path tag_screen_str = actor_str + '/tags/' + hashtag + boundary = None if ' boundary=' in self.headers['Content-type']: boundary = self.headers['Content-type'].split('boundary=')[1] if ';' in boundary: boundary = boundary.split(';')[0] - # get the nickname - nickname = get_nickname_from_actor(actor_str) - editor = None - if nickname: - editor = is_editor(base_dir, nickname) - if not hashtag or not editor: - if not nickname: - print('WARN: nickname not found in ' + actor_str) - else: - print('WARN: nickname is not a moderator' + actor_str) - self._redirect_headers(tag_screen_str, cookie, calling_domain) - self.server.postreq_busy = False - return + # get the nickname + nickname = get_nickname_from_actor(actor_str) + editor = None + if nickname: + editor = is_editor(base_dir, nickname) + if not hashtag or not editor: + if not nickname: + print('WARN: nickname not found in ' + actor_str) + else: + print('WARN: nickname is not a moderator' + actor_str) + self._redirect_headers(tag_screen_str, cookie, calling_domain) + self.server.postreq_busy = False + return + if self.headers.get('Content-length'): length = int(self.headers['Content-length']) # check that the POST isn't too large @@ -4946,27 +4948,32 @@ class PubServer(BaseHTTPRequestHandler): self.server.postreq_busy = False return - try: - # read the bytes of the http form POST - post_bytes = self.rfile.read(length) - except SocketError as ex: - if ex.errno == errno.ECONNRESET: - print('EX: connection was reset while ' + - 'reading bytes from http form POST') - else: - print('EX: error while reading bytes ' + - 'from http form POST') - self.send_response(400) - self.end_headers() - self.server.postreq_busy = False - return - except ValueError as ex: - print('EX: failed to read bytes for POST, ' + str(ex)) - self.send_response(400) - self.end_headers() - self.server.postreq_busy = False - return + try: + # read the bytes of the http form POST + post_bytes = self.rfile.read(length) + except SocketError as ex: + if ex.errno == errno.ECONNRESET: + print('EX: connection was reset while ' + + 'reading bytes from http form POST') + else: + print('EX: error while reading bytes ' + + 'from http form POST') + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return + except ValueError as ex: + print('EX: failed to read bytes for POST, ' + str(ex)) + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return + if not boundary: + if b'--LYNX' in post_bytes: + boundary = '--LYNX' + + if boundary: # extract all of the text fields into a dict fields = \ extract_text_fields_in_post(post_bytes, boundary, debug) From 9b5f638bee08b91aa1e8e6273db5df5fc379133b Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jul 2022 18:44:58 +0100 Subject: [PATCH 02/15] More debug --- content.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/content.py b/content.py index 5d0a54a6b..332726812 100644 --- a/content.py +++ b/content.py @@ -1495,6 +1495,8 @@ def extract_text_fields_in_post(post_bytes, boundary: str, debug: bool, 'instanceDescription', 'instanceDescriptionShort', 'subject', 'location', 'imageDescription' ) + if debug: + print('DEBUG: POST message_fields: ' + str(message_fields)) # examine each section of the POST, separated by the boundary for fld in message_fields: if fld == '--': From 3dd4debf243c220b3fd6285815270f0ef8452bd4 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jul 2022 20:04:54 +0100 Subject: [PATCH 03/15] Add unit test for Lynx browser POST --- content.py | 4 ++++ tests.py | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/content.py b/content.py index 332726812..9caccaf87 100644 --- a/content.py +++ b/content.py @@ -1497,6 +1497,7 @@ def extract_text_fields_in_post(post_bytes, boundary: str, debug: bool, ) if debug: print('DEBUG: POST message_fields: ' + str(message_fields)) + lynx_content_type = 'Content-Type: text/plain; charset=utf-8' # examine each section of the POST, separated by the boundary for fld in message_fields: if fld == '--': @@ -1508,6 +1509,9 @@ def extract_text_fields_in_post(post_bytes, boundary: str, debug: bool, continue post_key = post_str.split('"', 1)[0] post_value_str = post_str.split('"', 1)[1] + if boundary == '--LYNX': + post_value_str = \ + post_value_str.replace(lynx_content_type, '') if ';' in post_value_str: if post_key not in fields_with_semicolon_allowed and \ not post_key.startswith('edited'): diff --git a/tests.py b/tests.py index 6bbe9e32d..7e2524463 100644 --- a/tests.py +++ b/tests.py @@ -5852,6 +5852,18 @@ def _test_extract_text_fields_from_post(): assert fields['imageDescription'] == '' assert fields['message'] == 'This is a ; test' + boundary = '--LYNX' + form_data = '--LYNX\r\nContent-Disposition: form-data; ' + \ + 'name="fieldName"\r\nContent-Type: text/plain; ' + \ + 'charset=utf-8\r\nThis is a lynx test\r\n--LYNX\r\n' + \ + 'Content-Disposition: form-data; name="submitYes"\r\n' + \ + 'Content-Type: text/plain; charset=utf-8\r\nBUTTON\r\n--LYNX--\r\n' + debug = True + fields = extract_text_fields_in_post(None, boundary, debug, form_data) + print('fields: ' + str(fields)) + assert fields['fieldName'] == 'This is a lynx test' + assert fields['submitYes'] == 'BUTTON' + def _test_speaker_replace_link(): print('testSpeakerReplaceLinks') From 4dc62cfb8ed8ace4485b65f4e346fba4a06b0cfa Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jul 2022 20:18:37 +0100 Subject: [PATCH 04/15] Extra newline --- content.py | 2 +- tests.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/content.py b/content.py index 9caccaf87..cac39bf6a 100644 --- a/content.py +++ b/content.py @@ -1497,7 +1497,7 @@ def extract_text_fields_in_post(post_bytes, boundary: str, debug: bool, ) if debug: print('DEBUG: POST message_fields: ' + str(message_fields)) - lynx_content_type = 'Content-Type: text/plain; charset=utf-8' + lynx_content_type = 'Content-Type: text/plain; charset=utf-8\r\n' # examine each section of the POST, separated by the boundary for fld in message_fields: if fld == '--': diff --git a/tests.py b/tests.py index 7e2524463..0d0831805 100644 --- a/tests.py +++ b/tests.py @@ -5855,9 +5855,9 @@ def _test_extract_text_fields_from_post(): boundary = '--LYNX' form_data = '--LYNX\r\nContent-Disposition: form-data; ' + \ 'name="fieldName"\r\nContent-Type: text/plain; ' + \ - 'charset=utf-8\r\nThis is a lynx test\r\n--LYNX\r\n' + \ + 'charset=utf-8\r\n\r\nThis is a lynx test\r\n--LYNX\r\n' + \ 'Content-Disposition: form-data; name="submitYes"\r\n' + \ - 'Content-Type: text/plain; charset=utf-8\r\nBUTTON\r\n--LYNX--\r\n' + 'Content-Type: text/plain; charset=utf-8\r\n\r\nBUTTON\r\n--LYNX--\r\n' debug = True fields = extract_text_fields_in_post(None, boundary, debug, form_data) print('fields: ' + str(fields)) From 94ff176452ca9c7e02931911464e414ee3596c80 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jul 2022 21:02:17 +0100 Subject: [PATCH 05/15] Debug --- daemon.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/daemon.py b/daemon.py index 60cfe2562..71c5ebe00 100644 --- a/daemon.py +++ b/daemon.py @@ -4978,6 +4978,9 @@ class PubServer(BaseHTTPRequestHandler): fields = \ extract_text_fields_in_post(post_bytes, boundary, debug) + print('hashtag category POST bytes: ' + str(post_bytes)) + print('hashtag category POST fields: ' + str(fields)) + if fields.get('hashtagCategory'): category_str = fields['hashtagCategory'].lower() if not is_blocked_hashtag(base_dir, category_str) and \ From 05235683072d0610236e983a5ff72e69c3cef0fd Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jul 2022 21:22:52 +0100 Subject: [PATCH 06/15] Redo lynx unit test --- daemon.py | 3 --- tests.py | 8 +++++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/daemon.py b/daemon.py index 71c5ebe00..60cfe2562 100644 --- a/daemon.py +++ b/daemon.py @@ -4978,9 +4978,6 @@ class PubServer(BaseHTTPRequestHandler): fields = \ extract_text_fields_in_post(post_bytes, boundary, debug) - print('hashtag category POST bytes: ' + str(post_bytes)) - print('hashtag category POST fields: ' + str(fields)) - if fields.get('hashtagCategory'): category_str = fields['hashtagCategory'].lower() if not is_blocked_hashtag(base_dir, category_str) and \ diff --git a/tests.py b/tests.py index 0d0831805..db7594936 100644 --- a/tests.py +++ b/tests.py @@ -5855,12 +5855,14 @@ def _test_extract_text_fields_from_post(): boundary = '--LYNX' form_data = '--LYNX\r\nContent-Disposition: form-data; ' + \ 'name="fieldName"\r\nContent-Type: text/plain; ' + \ - 'charset=utf-8\r\n\r\nThis is a lynx test\r\n--LYNX\r\n' + \ - 'Content-Disposition: form-data; name="submitYes"\r\n' + \ - 'Content-Type: text/plain; charset=utf-8\r\n\r\nBUTTON\r\n--LYNX--\r\n' + 'charset=utf-8\r\n\r\nThis is a lynx test\r\n' + \ + '--LYNX\r\nContent-Disposition: ' + \ + 'form-data; name="submitYes"\r\nContent-Type: text/plain; ' + \ + 'charset=utf-8\r\n\r\nBUTTON\r\n--LYNX--\r\n' debug = True fields = extract_text_fields_in_post(None, boundary, debug, form_data) print('fields: ' + str(fields)) + assert fields assert fields['fieldName'] == 'This is a lynx test' assert fields['submitYes'] == 'BUTTON' From e963b32353c81d77eb7a0fe90fafe3f8102a4770 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jul 2022 22:03:14 +0100 Subject: [PATCH 07/15] Debug --- content.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content.py b/content.py index cac39bf6a..ff18db3d5 100644 --- a/content.py +++ b/content.py @@ -1485,8 +1485,8 @@ def extract_text_fields_in_post(post_bytes, boundary: str, debug: bool, else: message_fields = unit_test_data - if debug: - print('DEBUG: POST arriving ' + message_fields) +# if debug: + print('DEBUG: POST arriving ' + message_fields) message_fields = message_fields.split(boundary) fields = {} @@ -1495,8 +1495,8 @@ def extract_text_fields_in_post(post_bytes, boundary: str, debug: bool, 'instanceDescription', 'instanceDescriptionShort', 'subject', 'location', 'imageDescription' ) - if debug: - print('DEBUG: POST message_fields: ' + str(message_fields)) +# if debug: + print('DEBUG: POST message_fields: ' + str(message_fields)) lynx_content_type = 'Content-Type: text/plain; charset=utf-8\r\n' # examine each section of the POST, separated by the boundary for fld in message_fields: From ccac5448e6f2b329f60c0fd0cbc39f04e48400c5 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jul 2022 22:15:06 +0100 Subject: [PATCH 08/15] Exclude password from debug --- content.py | 10 ++++++---- tests.py | 30 ++++++++++++++++-------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/content.py b/content.py index ff18db3d5..b563cb9b9 100644 --- a/content.py +++ b/content.py @@ -1485,8 +1485,9 @@ def extract_text_fields_in_post(post_bytes, boundary: str, debug: bool, else: message_fields = unit_test_data -# if debug: - print('DEBUG: POST arriving ' + message_fields) + if debug: + if 'password' not in message_fields: + print('DEBUG: POST arriving ' + message_fields) message_fields = message_fields.split(boundary) fields = {} @@ -1495,8 +1496,9 @@ def extract_text_fields_in_post(post_bytes, boundary: str, debug: bool, 'instanceDescription', 'instanceDescriptionShort', 'subject', 'location', 'imageDescription' ) -# if debug: - print('DEBUG: POST message_fields: ' + str(message_fields)) + if debug: + if 'password' not in message_fields: + print('DEBUG: POST message_fields: ' + str(message_fields)) lynx_content_type = 'Content-Type: text/plain; charset=utf-8\r\n' # examine each section of the POST, separated by the boundary for fld in message_fields: diff --git a/tests.py b/tests.py index db7594936..24e902404 100644 --- a/tests.py +++ b/tests.py @@ -5818,6 +5818,20 @@ def _test_markdown_to_html(): def _test_extract_text_fields_from_post(): print('test_extract_text_fields_in_post') + boundary = '--LYNX' + form_data = '--LYNX\r\nContent-Disposition: form-data; ' + \ + 'name="fieldName"\r\nContent-Type: text/plain; ' + \ + 'charset=utf-8\r\n\r\nThis is a lynx test\r\n' + \ + '--LYNX\r\nContent-Disposition: ' + \ + 'form-data; name="submitYes"\r\nContent-Type: text/plain; ' + \ + 'charset=utf-8\r\n\r\nBUTTON\r\n--LYNX--\r\n' + debug = True + fields = extract_text_fields_in_post(None, boundary, debug, form_data) + print('fields: ' + str(fields)) + assert fields + assert fields['fieldName'] == 'This is a lynx test' + assert fields['submitYes'] == 'BUTTON' + boundary = '-----------------------------116202748023898664511855843036' form_data = '-----------------------------116202748023898664511855' + \ '843036\r\nContent-Disposition: form-data; name="submitPost"' + \ @@ -5852,20 +5866,6 @@ def _test_extract_text_fields_from_post(): assert fields['imageDescription'] == '' assert fields['message'] == 'This is a ; test' - boundary = '--LYNX' - form_data = '--LYNX\r\nContent-Disposition: form-data; ' + \ - 'name="fieldName"\r\nContent-Type: text/plain; ' + \ - 'charset=utf-8\r\n\r\nThis is a lynx test\r\n' + \ - '--LYNX\r\nContent-Disposition: ' + \ - 'form-data; name="submitYes"\r\nContent-Type: text/plain; ' + \ - 'charset=utf-8\r\n\r\nBUTTON\r\n--LYNX--\r\n' - debug = True - fields = extract_text_fields_in_post(None, boundary, debug, form_data) - print('fields: ' + str(fields)) - assert fields - assert fields['fieldName'] == 'This is a lynx test' - assert fields['submitYes'] == 'BUTTON' - def _test_speaker_replace_link(): print('testSpeakerReplaceLinks') @@ -7413,6 +7413,8 @@ def _test_text_standardize(): def run_all_tests(): + _test_extract_text_fields_from_post() + return base_dir = os.getcwd() print('Running tests...') update_default_themes_list(os.getcwd()) From 621f89b49280a76403b6d3e399f63b614ffe6069 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jul 2022 22:31:31 +0100 Subject: [PATCH 09/15] Tidying --- tests.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests.py b/tests.py index 24e902404..b56e03bc7 100644 --- a/tests.py +++ b/tests.py @@ -7413,8 +7413,6 @@ def _test_text_standardize(): def run_all_tests(): - _test_extract_text_fields_from_post() - return base_dir = os.getcwd() print('Running tests...') update_default_themes_list(os.getcwd()) From 7a59a2482a7f51dd831d0acd19013c56712b4318 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jul 2022 22:44:12 +0100 Subject: [PATCH 10/15] Debug --- content.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/content.py b/content.py index b563cb9b9..26daf4e5c 100644 --- a/content.py +++ b/content.py @@ -1510,17 +1510,26 @@ def extract_text_fields_in_post(post_bytes, boundary: str, debug: bool, if '"' not in post_str: continue post_key = post_str.split('"', 1)[0] + print('post_key: ' + post_key) post_value_str = post_str.split('"', 1)[1] if boundary == '--LYNX': post_value_str = \ post_value_str.replace(lynx_content_type, '') + if 'password' not in post_key: + print('post_value_str1: ' + post_value_str) if ';' in post_value_str: if post_key not in fields_with_semicolon_allowed and \ not post_key.startswith('edited'): + print('exit 1') continue + if 'password' not in post_key: + print('post_value_str2: ' + post_value_str) if '\r\n' not in post_value_str: + print('exit 2') continue post_lines = post_value_str.split('\r\n') + if 'password' not in post_key: + print('post_lines: ' + str(post_lines)) post_value = '' if len(post_lines) > 2: for line in range(2, len(post_lines)-1): From 1352b3faf62458b1764268cb7cdcad0ca68b82d4 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jul 2022 22:48:36 +0100 Subject: [PATCH 11/15] Debug --- content.py | 1 + 1 file changed, 1 insertion(+) diff --git a/content.py b/content.py index 26daf4e5c..3755f020b 100644 --- a/content.py +++ b/content.py @@ -1516,6 +1516,7 @@ def extract_text_fields_in_post(post_bytes, boundary: str, debug: bool, post_value_str = \ post_value_str.replace(lynx_content_type, '') if 'password' not in post_key: + print('boundary: ' + boundary) print('post_value_str1: ' + post_value_str) if ';' in post_value_str: if post_key not in fields_with_semicolon_allowed and \ From fc3816ca1431f1df3dbed2b9d157562c2e8403c0 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jul 2022 22:52:24 +0100 Subject: [PATCH 12/15] Prepend dashes --- content.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/content.py b/content.py index 3755f020b..86cd82804 100644 --- a/content.py +++ b/content.py @@ -1479,6 +1479,9 @@ def extract_text_fields_in_post(post_bytes, boundary: str, debug: bool, """Returns a dictionary containing the text fields of a http form POST The boundary argument comes from the http header """ + if boundary == 'LYNX': + boundary == '--LYNX' + if not unit_test_data: msg_bytes = email.parser.BytesParser().parsebytes(post_bytes) message_fields = msg_bytes.get_payload(decode=True).decode('utf-8') From 5d0192732c795bdfa066e7d00e2eb9c0afa99d1a Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jul 2022 22:52:39 +0100 Subject: [PATCH 13/15] Prepend dashes --- content.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content.py b/content.py index 86cd82804..b1a0eb20d 100644 --- a/content.py +++ b/content.py @@ -1480,7 +1480,7 @@ def extract_text_fields_in_post(post_bytes, boundary: str, debug: bool, The boundary argument comes from the http header """ if boundary == 'LYNX': - boundary == '--LYNX' + boundary = '--LYNX' if not unit_test_data: msg_bytes = email.parser.BytesParser().parsebytes(post_bytes) From 17d7432fc61425df3069a631914ec3633689664b Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jul 2022 22:57:26 +0100 Subject: [PATCH 14/15] Add debug flags --- content.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/content.py b/content.py index b1a0eb20d..113c359fc 100644 --- a/content.py +++ b/content.py @@ -1480,6 +1480,8 @@ def extract_text_fields_in_post(post_bytes, boundary: str, debug: bool, The boundary argument comes from the http header """ if boundary == 'LYNX': + if debug: + print('POST from lynx browser') boundary = '--LYNX' if not unit_test_data: @@ -1513,26 +1515,29 @@ def extract_text_fields_in_post(post_bytes, boundary: str, debug: bool, if '"' not in post_str: continue post_key = post_str.split('"', 1)[0] - print('post_key: ' + post_key) + if debug: + print('post_key: ' + post_key) post_value_str = post_str.split('"', 1)[1] if boundary == '--LYNX': post_value_str = \ post_value_str.replace(lynx_content_type, '') - if 'password' not in post_key: + if debug and 'password' not in post_key: print('boundary: ' + boundary) print('post_value_str1: ' + post_value_str) if ';' in post_value_str: if post_key not in fields_with_semicolon_allowed and \ not post_key.startswith('edited'): - print('exit 1') + if debug: + print('extract_text_fields_in_post exit 1') continue - if 'password' not in post_key: + if debug and 'password' not in post_key: print('post_value_str2: ' + post_value_str) if '\r\n' not in post_value_str: - print('exit 2') + if debug: + print('extract_text_fields_in_post exit 2') continue post_lines = post_value_str.split('\r\n') - if 'password' not in post_key: + if debug and 'password' not in post_key: print('post_lines: ' + str(post_lines)) post_value = '' if len(post_lines) > 2: From 712beebcb858a2708b002657ec55444f708cb49a Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jul 2022 23:18:36 +0100 Subject: [PATCH 15/15] POST from lynx browser --- daemon.py | 307 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 170 insertions(+), 137 deletions(-) diff --git a/daemon.py b/daemon.py index 60cfe2562..c1d21ed83 100644 --- a/daemon.py +++ b/daemon.py @@ -4739,25 +4739,28 @@ class PubServer(BaseHTTPRequestHandler): users_path = path.replace('/linksdata', '') users_path = users_path.replace('/editlinks', '') actor_str = self._get_instance_url(calling_domain) + users_path + + boundary = None if ' boundary=' in self.headers['Content-type']: boundary = self.headers['Content-type'].split('boundary=')[1] if ';' in boundary: boundary = boundary.split(';')[0] - # get the nickname - nickname = get_nickname_from_actor(actor_str) - editor = None - if nickname: - editor = is_editor(base_dir, nickname) - if not nickname or not editor: - if not nickname: - print('WARN: nickname not found in ' + actor_str) - else: - print('WARN: nickname is not a moderator' + actor_str) - self._redirect_headers(actor_str, cookie, calling_domain) - self.server.postreq_busy = False - return + # get the nickname + nickname = get_nickname_from_actor(actor_str) + editor = None + if nickname: + editor = is_editor(base_dir, nickname) + if not nickname or not editor: + if not nickname: + print('WARN: nickname not found in ' + actor_str) + else: + print('WARN: nickname is not a moderator' + actor_str) + self._redirect_headers(actor_str, cookie, calling_domain) + self.server.postreq_busy = False + return + if self.headers.get('Content-length'): length = int(self.headers['Content-length']) # check that the POST isn't too large @@ -4767,32 +4770,37 @@ class PubServer(BaseHTTPRequestHandler): self.server.postreq_busy = False return - try: - # read the bytes of the http form POST - post_bytes = self.rfile.read(length) - except SocketError as ex: - if ex.errno == errno.ECONNRESET: - print('EX: connection was reset while ' + - 'reading bytes from http form POST') - else: - print('EX: error while reading bytes ' + - 'from http form POST') - self.send_response(400) - self.end_headers() - self.server.postreq_busy = False - return - except ValueError as ex: - print('EX: failed to read bytes for POST, ' + str(ex)) - self.send_response(400) - self.end_headers() - self.server.postreq_busy = False - return + try: + # read the bytes of the http form POST + post_bytes = self.rfile.read(length) + except SocketError as ex: + if ex.errno == errno.ECONNRESET: + print('EX: connection was reset while ' + + 'reading bytes from http form POST') + else: + print('EX: error while reading bytes ' + + 'from http form POST') + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return + except ValueError as ex: + print('EX: failed to read bytes for POST, ' + str(ex)) + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return - links_filename = base_dir + '/accounts/links.txt' - about_filename = base_dir + '/accounts/about.md' - tos_filename = base_dir + '/accounts/tos.md' - specification_filename = base_dir + '/accounts/activitypub.md' + links_filename = base_dir + '/accounts/links.txt' + about_filename = base_dir + '/accounts/about.md' + tos_filename = base_dir + '/accounts/tos.md' + specification_filename = base_dir + '/accounts/activitypub.md' + if not boundary: + if b'--LYNX' in post_bytes: + boundary = '--LYNX' + + if boundary: # extract all of the text fields into a dict fields = \ extract_text_fields_in_post(post_bytes, boundary, debug) @@ -4918,6 +4926,7 @@ class PubServer(BaseHTTPRequestHandler): users_path = users_path.split('/tags/')[0] actor_str = self._get_instance_url(calling_domain) + users_path tag_screen_str = actor_str + '/tags/' + hashtag + boundary = None if ' boundary=' in self.headers['Content-type']: boundary = self.headers['Content-type'].split('boundary=')[1] @@ -5007,25 +5016,28 @@ class PubServer(BaseHTTPRequestHandler): users_path = path.replace('/newswiredata', '') users_path = users_path.replace('/editnewswire', '') actor_str = self._get_instance_url(calling_domain) + users_path + + boundary = None if ' boundary=' in self.headers['Content-type']: boundary = self.headers['Content-type'].split('boundary=')[1] if ';' in boundary: boundary = boundary.split(';')[0] - # get the nickname - nickname = get_nickname_from_actor(actor_str) - moderator = None - if nickname: - moderator = is_moderator(base_dir, nickname) - if not nickname or not moderator: - if not nickname: - print('WARN: nickname not found in ' + actor_str) - else: - print('WARN: nickname is not a moderator' + actor_str) - self._redirect_headers(actor_str, cookie, calling_domain) - self.server.postreq_busy = False - return + # get the nickname + nickname = get_nickname_from_actor(actor_str) + moderator = None + if nickname: + moderator = is_moderator(base_dir, nickname) + if not nickname or not moderator: + if not nickname: + print('WARN: nickname not found in ' + actor_str) + else: + print('WARN: nickname is not a moderator' + actor_str) + self._redirect_headers(actor_str, cookie, calling_domain) + self.server.postreq_busy = False + return + if self.headers.get('Content-length'): length = int(self.headers['Content-length']) # check that the POST isn't too large @@ -5035,29 +5047,34 @@ class PubServer(BaseHTTPRequestHandler): self.server.postreq_busy = False return - try: - # read the bytes of the http form POST - post_bytes = self.rfile.read(length) - except SocketError as ex: - if ex.errno == errno.ECONNRESET: - print('EX: connection was reset while ' + - 'reading bytes from http form POST') - else: - print('EX: error while reading bytes ' + - 'from http form POST') - self.send_response(400) - self.end_headers() - self.server.postreq_busy = False - return - except ValueError as ex: - print('EX: failed to read bytes for POST, ' + str(ex)) - self.send_response(400) - self.end_headers() - self.server.postreq_busy = False - return + try: + # read the bytes of the http form POST + post_bytes = self.rfile.read(length) + except SocketError as ex: + if ex.errno == errno.ECONNRESET: + print('EX: connection was reset while ' + + 'reading bytes from http form POST') + else: + print('EX: error while reading bytes ' + + 'from http form POST') + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return + except ValueError as ex: + print('EX: failed to read bytes for POST, ' + str(ex)) + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return - newswire_filename = base_dir + '/accounts/newswire.txt' + newswire_filename = base_dir + '/accounts/newswire.txt' + if not boundary: + if b'--LYNX' in post_bytes: + boundary = '--LYNX' + + if boundary: # extract all of the text fields into a dict fields = \ extract_text_fields_in_post(post_bytes, boundary, debug) @@ -5276,30 +5293,33 @@ class PubServer(BaseHTTPRequestHandler): users_path = path.replace('/newseditdata', '') users_path = users_path.replace('/editnewspost', '') actor_str = self._get_instance_url(calling_domain) + users_path + + boundary = None if ' boundary=' in self.headers['Content-type']: boundary = self.headers['Content-type'].split('boundary=')[1] if ';' in boundary: boundary = boundary.split(';')[0] - # get the nickname - nickname = get_nickname_from_actor(actor_str) - editor_role = None - if nickname: - editor_role = is_editor(base_dir, nickname) - if not nickname or not editor_role: - if not nickname: - print('WARN: nickname not found in ' + actor_str) - else: - print('WARN: nickname is not an editor' + actor_str) - if self.server.news_instance: - self._redirect_headers(actor_str + '/tlfeatures', - cookie, calling_domain) - else: - self._redirect_headers(actor_str + '/tlnews', - cookie, calling_domain) - self.server.postreq_busy = False - return + # get the nickname + nickname = get_nickname_from_actor(actor_str) + editor_role = None + if nickname: + editor_role = is_editor(base_dir, nickname) + if not nickname or not editor_role: + if not nickname: + print('WARN: nickname not found in ' + actor_str) + else: + print('WARN: nickname is not an editor' + actor_str) + if self.server.news_instance: + self._redirect_headers(actor_str + '/tlfeatures', + cookie, calling_domain) + else: + self._redirect_headers(actor_str + '/tlnews', + cookie, calling_domain) + self.server.postreq_busy = False + return + if self.headers.get('Content-length'): length = int(self.headers['Content-length']) # check that the POST isn't too large @@ -5314,27 +5334,32 @@ class PubServer(BaseHTTPRequestHandler): self.server.postreq_busy = False return - try: - # read the bytes of the http form POST - post_bytes = self.rfile.read(length) - except SocketError as ex: - if ex.errno == errno.ECONNRESET: - print('EX: connection was reset while ' + - 'reading bytes from http form POST') - else: - print('EX: error while reading bytes ' + - 'from http form POST') - self.send_response(400) - self.end_headers() - self.server.postreq_busy = False - return - except ValueError as ex: - print('EX: failed to read bytes for POST, ' + str(ex)) - self.send_response(400) - self.end_headers() - self.server.postreq_busy = False - return + try: + # read the bytes of the http form POST + post_bytes = self.rfile.read(length) + except SocketError as ex: + if ex.errno == errno.ECONNRESET: + print('EX: connection was reset while ' + + 'reading bytes from http form POST') + else: + print('EX: error while reading bytes ' + + 'from http form POST') + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return + except ValueError as ex: + print('EX: failed to read bytes for POST, ' + str(ex)) + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return + if not boundary: + if b'--LYNX' in post_bytes: + boundary = '--LYNX' + + if boundary: # extract all of the text fields into a dict fields = \ extract_text_fields_in_post(post_bytes, boundary, debug) @@ -5416,19 +5441,22 @@ class PubServer(BaseHTTPRequestHandler): users_path = path.replace('/profiledata', '') users_path = users_path.replace('/editprofile', '') actor_str = self._get_instance_url(calling_domain) + users_path + + boundary = None if ' boundary=' in self.headers['Content-type']: boundary = self.headers['Content-type'].split('boundary=')[1] if ';' in boundary: boundary = boundary.split(';')[0] - # get the nickname - nickname = get_nickname_from_actor(actor_str) - if not nickname: - print('WARN: nickname not found in ' + actor_str) - self._redirect_headers(actor_str, cookie, calling_domain) - self.server.postreq_busy = False - return + # get the nickname + nickname = get_nickname_from_actor(actor_str) + if not nickname: + print('WARN: nickname not found in ' + actor_str) + self._redirect_headers(actor_str, cookie, calling_domain) + self.server.postreq_busy = False + return + if self.headers.get('Content-length'): length = int(self.headers['Content-length']) # check that the POST isn't too large @@ -5439,29 +5467,34 @@ class PubServer(BaseHTTPRequestHandler): self.server.postreq_busy = False return - try: - # read the bytes of the http form POST - post_bytes = self.rfile.read(length) - except SocketError as ex: - if ex.errno == errno.ECONNRESET: - print('EX: connection was reset while ' + - 'reading bytes from http form POST') - else: - print('EX: error while reading bytes ' + - 'from http form POST') - self.send_response(400) - self.end_headers() - self.server.postreq_busy = False - return - except ValueError as ex: - print('EX: failed to read bytes for POST, ' + str(ex)) - self.send_response(400) - self.end_headers() - self.server.postreq_busy = False - return + try: + # read the bytes of the http form POST + post_bytes = self.rfile.read(length) + except SocketError as ex: + if ex.errno == errno.ECONNRESET: + print('EX: connection was reset while ' + + 'reading bytes from http form POST') + else: + print('EX: error while reading bytes ' + + 'from http form POST') + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return + except ValueError as ex: + print('EX: failed to read bytes for POST, ' + str(ex)) + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return - admin_nickname = get_config_param(self.server.base_dir, 'admin') + admin_nickname = get_config_param(self.server.base_dir, 'admin') + if not boundary: + if b'--LYNX' in post_bytes: + boundary = '--LYNX' + + if boundary: # get the various avatar, banner and background images actor_changed = True profile_media_types = (