mirror of https://gitlab.com/bashrc2/epicyon
				
				
				
			
		
			
				
	
	
		
			421 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			421 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Python
		
	
	
| __filename__ = "daemon_post_remove.py"
 | |
| __author__ = "Bob Mottram"
 | |
| __license__ = "AGPL3+"
 | |
| __version__ = "1.5.0"
 | |
| __maintainer__ = "Bob Mottram"
 | |
| __email__ = "bob@libreserver.org"
 | |
| __status__ = "Production"
 | |
| __module_group__ = "Core POST"
 | |
| 
 | |
| import os
 | |
| import errno
 | |
| import urllib.parse
 | |
| from socket import error as SocketError
 | |
| from utils import save_json
 | |
| from utils import load_json
 | |
| from utils import acct_dir
 | |
| from utils import get_instance_url
 | |
| from utils import get_domain_from_actor
 | |
| from utils import local_actor_url
 | |
| from utils import get_config_param
 | |
| from utils import get_nickname_from_actor
 | |
| from reading import remove_reading_event
 | |
| from httpheaders import redirect_headers
 | |
| from posts import is_moderator
 | |
| from shares import remove_shared_item2
 | |
| from shares import add_shares_to_actor
 | |
| from cache import store_person_in_cache
 | |
| from cache import remove_person_from_cache
 | |
| from cache import get_person_from_cache
 | |
| from person import get_actor_update_json
 | |
| from daemon_utils import post_to_outbox_thread
 | |
| from daemon_utils import post_to_outbox
 | |
| from happening import remove_calendar_event
 | |
| 
 | |
| 
 | |
| def remove_reading_status(self, calling_domain: str, cookie: str,
 | |
|                           path: str, base_dir: str, http_prefix: str,
 | |
|                           domain_full: str,
 | |
|                           onion_domain: str, i2p_domain: str,
 | |
|                           debug: bool,
 | |
|                           books_cache: {}) -> None:
 | |
|     """Remove a reading status from the profile screen
 | |
|     """
 | |
|     users_path = path.split('/removereadingstatus')[0]
 | |
|     origin_path_str = http_prefix + '://' + domain_full + users_path
 | |
|     reader_nickname = get_nickname_from_actor(origin_path_str)
 | |
|     if not reader_nickname:
 | |
|         self.send_response(400)
 | |
|         self.end_headers()
 | |
|         self.server.postreq_busy = False
 | |
|         return
 | |
| 
 | |
|     length = int(self.headers['Content-length'])
 | |
| 
 | |
|     try:
 | |
|         remove_reading_status_params = \
 | |
|             self.rfile.read(length).decode('utf-8')
 | |
|     except SocketError as ex:
 | |
|         if ex.errno == errno.ECONNRESET:
 | |
|             print('EX: POST remove_reading_status_params ' +
 | |
|                   'connection was reset')
 | |
|         else:
 | |
|             print('EX: POST remove_reading_status_params socket error')
 | |
|         self.send_response(400)
 | |
|         self.end_headers()
 | |
|         self.server.postreq_busy = False
 | |
|         return
 | |
|     except ValueError as ex:
 | |
|         print('EX: POST remove_reading_status_params rfile.read failed, ' +
 | |
|               str(ex))
 | |
|         self.send_response(400)
 | |
|         self.end_headers()
 | |
|         self.server.postreq_busy = False
 | |
|         return
 | |
| 
 | |
|     if '&submitRemoveReadingStatus=' in remove_reading_status_params:
 | |
|         reading_actor = \
 | |
|             urllib.parse.unquote_plus(remove_reading_status_params)
 | |
|         reading_actor = reading_actor.split('actor=')[1]
 | |
|         if '&' in reading_actor:
 | |
|             reading_actor = reading_actor.split('&')[0]
 | |
| 
 | |
|         if reading_actor == origin_path_str:
 | |
|             post_secs_since_epoch = \
 | |
|                 urllib.parse.unquote_plus(remove_reading_status_params)
 | |
|             post_secs_since_epoch = \
 | |
|                 post_secs_since_epoch.split('publishedtimesec=')[1]
 | |
|             if '&' in post_secs_since_epoch:
 | |
|                 post_secs_since_epoch = post_secs_since_epoch.split('&')[0]
 | |
| 
 | |
|             book_event_type = \
 | |
|                 urllib.parse.unquote_plus(remove_reading_status_params)
 | |
|             book_event_type = \
 | |
|                 book_event_type.split('bookeventtype=')[1]
 | |
|             if '&' in book_event_type:
 | |
|                 book_event_type = book_event_type.split('&')[0]
 | |
| 
 | |
|             remove_reading_event(base_dir,
 | |
|                                  reading_actor, post_secs_since_epoch,
 | |
|                                  book_event_type, books_cache, debug)
 | |
| 
 | |
|     if calling_domain.endswith('.onion') and onion_domain:
 | |
|         origin_path_str = 'http://' + onion_domain + users_path
 | |
|     elif (calling_domain.endswith('.i2p') and i2p_domain):
 | |
|         origin_path_str = 'http://' + i2p_domain + users_path
 | |
|     redirect_headers(self, origin_path_str, cookie, calling_domain, 303)
 | |
|     self.server.postreq_busy = False
 | |
| 
 | |
| 
 | |
| def remove_share(self, calling_domain: str, cookie: str,
 | |
|                  authorized: bool, path: str,
 | |
|                  base_dir: str, http_prefix: str, domain_full: str,
 | |
|                  onion_domain: str, i2p_domain: str,
 | |
|                  curr_session, proxy_type: str,
 | |
|                  person_cache: {},
 | |
|                  max_shares_on_profile: int,
 | |
|                  project_version: str) -> None:
 | |
|     """Removes a shared item
 | |
|     """
 | |
|     users_path = path.split('/rmshare')[0]
 | |
|     origin_path_str = http_prefix + '://' + domain_full + users_path
 | |
| 
 | |
|     length = int(self.headers['Content-length'])
 | |
| 
 | |
|     try:
 | |
|         remove_share_confirm_params = \
 | |
|             self.rfile.read(length).decode('utf-8')
 | |
|     except SocketError as ex:
 | |
|         if ex.errno == errno.ECONNRESET:
 | |
|             print('EX: POST remove_share_confirm_params ' +
 | |
|                   'connection was reset')
 | |
|         else:
 | |
|             print('EX: POST remove_share_confirm_params socket error')
 | |
|         self.send_response(400)
 | |
|         self.end_headers()
 | |
|         self.server.postreq_busy = False
 | |
|         return
 | |
|     except ValueError as ex:
 | |
|         print('EX: POST remove_share_confirm_params ' +
 | |
|               'rfile.read failed, ' + str(ex))
 | |
|         self.send_response(400)
 | |
|         self.end_headers()
 | |
|         self.server.postreq_busy = False
 | |
|         return
 | |
| 
 | |
|     if '&submitYes=' in remove_share_confirm_params and authorized:
 | |
|         remove_share_confirm_params = \
 | |
|             remove_share_confirm_params.replace('+', ' ').strip()
 | |
|         remove_share_confirm_params = \
 | |
|             urllib.parse.unquote_plus(remove_share_confirm_params)
 | |
|         share_actor = remove_share_confirm_params.split('actor=')[1]
 | |
|         if '&' in share_actor:
 | |
|             share_actor = share_actor.split('&')[0]
 | |
|         admin_nickname = get_config_param(base_dir, 'admin')
 | |
|         admin_actor = \
 | |
|             local_actor_url(http_prefix, admin_nickname, domain_full)
 | |
|         actor = origin_path_str
 | |
|         actor_nickname = get_nickname_from_actor(actor)
 | |
|         if not actor_nickname:
 | |
|             self.send_response(400)
 | |
|             self.end_headers()
 | |
|             self.server.postreq_busy = False
 | |
|             return
 | |
|         if actor == share_actor or actor == admin_actor or \
 | |
|            is_moderator(base_dir, actor_nickname):
 | |
|             item_id = remove_share_confirm_params.split('itemID=')[1]
 | |
|             if '&' in item_id:
 | |
|                 item_id = item_id.split('&')[0]
 | |
|             share_nickname = get_nickname_from_actor(share_actor)
 | |
|             share_domain, _ = \
 | |
|                 get_domain_from_actor(share_actor)
 | |
|             if share_nickname and share_domain:
 | |
|                 remove_shared_item2(base_dir,
 | |
|                                     share_nickname, share_domain, item_id,
 | |
|                                     'shares')
 | |
|                 # remove shared items from the actor attachments
 | |
|                 # https://codeberg.org/fediverse/fep/
 | |
|                 # src/branch/main/fep/0837/fep-0837.md
 | |
|                 actor = \
 | |
|                     get_instance_url(calling_domain,
 | |
|                                      http_prefix,
 | |
|                                      domain_full,
 | |
|                                      onion_domain,
 | |
|                                      i2p_domain) + \
 | |
|                     '/users/' + share_nickname
 | |
|                 actor_json = get_person_from_cache(base_dir,
 | |
|                                                    actor, person_cache)
 | |
|                 if not actor_json:
 | |
|                     actor_filename = \
 | |
|                         acct_dir(base_dir, share_nickname,
 | |
|                                  share_domain) + '.json'
 | |
|                     if os.path.isfile(actor_filename):
 | |
|                         actor_json = load_json(actor_filename)
 | |
|                 if actor_json:
 | |
|                     if add_shares_to_actor(base_dir,
 | |
|                                            share_nickname, share_domain,
 | |
|                                            actor_json,
 | |
|                                            max_shares_on_profile):
 | |
|                         remove_person_from_cache(base_dir, actor,
 | |
|                                                  person_cache)
 | |
|                         store_person_in_cache(base_dir, actor,
 | |
|                                               actor_json,
 | |
|                                               person_cache, True)
 | |
|                         actor_filename = acct_dir(base_dir, share_nickname,
 | |
|                                                   share_domain) + '.json'
 | |
|                         save_json(actor_json, actor_filename)
 | |
|                         # send profile update to followers
 | |
| 
 | |
|                         update_actor_json = \
 | |
|                             get_actor_update_json(actor_json)
 | |
|                         print('Sending actor update ' +
 | |
|                               'after change to attached shares 2: ' +
 | |
|                               str(update_actor_json))
 | |
|                         post_to_outbox(self, update_actor_json,
 | |
|                                        project_version,
 | |
|                                        share_nickname,
 | |
|                                        curr_session,
 | |
|                                        proxy_type)
 | |
| 
 | |
|     if calling_domain.endswith('.onion') and onion_domain:
 | |
|         origin_path_str = 'http://' + onion_domain + users_path
 | |
|     elif (calling_domain.endswith('.i2p') and i2p_domain):
 | |
|         origin_path_str = 'http://' + i2p_domain + users_path
 | |
|     redirect_headers(self, origin_path_str + '/tlshares',
 | |
|                      cookie, calling_domain, 303)
 | |
|     self.server.postreq_busy = False
 | |
| 
 | |
| 
 | |
| def remove_wanted(self, calling_domain: str, cookie: str,
 | |
|                   authorized: bool, path: str,
 | |
|                   base_dir: str, http_prefix: str,
 | |
|                   domain_full: str,
 | |
|                   onion_domain: str, i2p_domain: str) -> None:
 | |
|     """Removes a wanted item
 | |
|     """
 | |
|     users_path = path.split('/rmwanted')[0]
 | |
|     origin_path_str = http_prefix + '://' + domain_full + users_path
 | |
| 
 | |
|     length = int(self.headers['Content-length'])
 | |
| 
 | |
|     try:
 | |
|         remove_share_confirm_params = \
 | |
|             self.rfile.read(length).decode('utf-8')
 | |
|     except SocketError as ex:
 | |
|         if ex.errno == errno.ECONNRESET:
 | |
|             print('EX: POST remove_share_confirm_params ' +
 | |
|                   'connection was reset')
 | |
|         else:
 | |
|             print('EX: POST remove_share_confirm_params socket error')
 | |
|         self.send_response(400)
 | |
|         self.end_headers()
 | |
|         self.server.postreq_busy = False
 | |
|         return
 | |
|     except ValueError as ex:
 | |
|         print('EX: POST remove_share_confirm_params ' +
 | |
|               'rfile.read failed, ' + str(ex))
 | |
|         self.send_response(400)
 | |
|         self.end_headers()
 | |
|         self.server.postreq_busy = False
 | |
|         return
 | |
| 
 | |
|     if '&submitYes=' in remove_share_confirm_params and authorized:
 | |
|         remove_share_confirm_params = \
 | |
|             remove_share_confirm_params.replace('+', ' ').strip()
 | |
|         remove_share_confirm_params = \
 | |
|             urllib.parse.unquote_plus(remove_share_confirm_params)
 | |
|         share_actor = remove_share_confirm_params.split('actor=')[1]
 | |
|         if '&' in share_actor:
 | |
|             share_actor = share_actor.split('&')[0]
 | |
|         admin_nickname = get_config_param(base_dir, 'admin')
 | |
|         admin_actor = \
 | |
|             local_actor_url(http_prefix, admin_nickname, domain_full)
 | |
|         actor = origin_path_str
 | |
|         actor_nickname = get_nickname_from_actor(actor)
 | |
|         if not actor_nickname:
 | |
|             self.send_response(400)
 | |
|             self.end_headers()
 | |
|             self.server.postreq_busy = False
 | |
|             return
 | |
|         if actor == share_actor or actor == admin_actor or \
 | |
|            is_moderator(base_dir, actor_nickname):
 | |
|             item_id = remove_share_confirm_params.split('itemID=')[1]
 | |
|             if '&' in item_id:
 | |
|                 item_id = item_id.split('&')[0]
 | |
|             share_nickname = get_nickname_from_actor(share_actor)
 | |
|             share_domain, _ = \
 | |
|                 get_domain_from_actor(share_actor)
 | |
|             if share_nickname and share_domain:
 | |
|                 remove_shared_item2(base_dir,
 | |
|                                     share_nickname, share_domain, item_id,
 | |
|                                     'wanted')
 | |
| 
 | |
|     if calling_domain.endswith('.onion') and onion_domain:
 | |
|         origin_path_str = 'http://' + onion_domain + users_path
 | |
|     elif (calling_domain.endswith('.i2p') and i2p_domain):
 | |
|         origin_path_str = 'http://' + i2p_domain + users_path
 | |
|     redirect_headers(self, origin_path_str + '/tlwanted',
 | |
|                      cookie, calling_domain, 303)
 | |
|     self.server.postreq_busy = False
 | |
| 
 | |
| 
 | |
| def receive_remove_post(self, calling_domain: str, cookie: str,
 | |
|                         path: str, base_dir: str, http_prefix: str,
 | |
|                         domain: str, domain_full: str,
 | |
|                         onion_domain: str, i2p_domain: str,
 | |
|                         curr_session, proxy_type: str) -> None:
 | |
|     """Endpoint for removing posts after confirmation
 | |
|     """
 | |
|     page_number = 1
 | |
|     users_path = path.split('/rmpost')[0]
 | |
|     origin_path_str = \
 | |
|         http_prefix + '://' + \
 | |
|         domain_full + users_path
 | |
| 
 | |
|     length = int(self.headers['Content-length'])
 | |
| 
 | |
|     try:
 | |
|         remove_post_confirm_params = \
 | |
|             self.rfile.read(length).decode('utf-8')
 | |
|     except SocketError as ex:
 | |
|         if ex.errno == errno.ECONNRESET:
 | |
|             print('EX: POST remove_post_confirm_params ' +
 | |
|                   'connection was reset')
 | |
|         else:
 | |
|             print('EX: POST remove_post_confirm_params socket error')
 | |
|         self.send_response(400)
 | |
|         self.end_headers()
 | |
|         self.server.postreq_busy = False
 | |
|         return
 | |
|     except ValueError as ex:
 | |
|         print('EX: POST remove_post_confirm_params ' +
 | |
|               'rfile.read failed, ' + str(ex))
 | |
|         self.send_response(400)
 | |
|         self.end_headers()
 | |
|         self.server.postreq_busy = False
 | |
|         return
 | |
|     if '&submitYes=' in remove_post_confirm_params:
 | |
|         remove_post_confirm_params = \
 | |
|             urllib.parse.unquote_plus(remove_post_confirm_params)
 | |
|         if 'messageId=' in remove_post_confirm_params:
 | |
|             remove_message_id = \
 | |
|                 remove_post_confirm_params.split('messageId=')[1]
 | |
|         elif 'eventid=' in remove_post_confirm_params:
 | |
|             remove_message_id = \
 | |
|                 remove_post_confirm_params.split('eventid=')[1]
 | |
|         else:
 | |
|             self.send_response(400)
 | |
|             self.end_headers()
 | |
|             self.server.postreq_busy = False
 | |
|             return
 | |
|         if '&' in remove_message_id:
 | |
|             remove_message_id = remove_message_id.split('&')[0]
 | |
|         print('remove_message_id: ' + remove_message_id)
 | |
|         if 'pageNumber=' in remove_post_confirm_params:
 | |
|             page_number_str = \
 | |
|                 remove_post_confirm_params.split('pageNumber=')[1]
 | |
|             if '&' in page_number_str:
 | |
|                 page_number_str = page_number_str.split('&')[0]
 | |
|             if len(page_number_str) > 5:
 | |
|                 page_number_str = "1"
 | |
|             if page_number_str.isdigit():
 | |
|                 page_number = int(page_number_str)
 | |
|         year_str = None
 | |
|         if 'year=' in remove_post_confirm_params:
 | |
|             year_str = remove_post_confirm_params.split('year=')[1]
 | |
|             if '&' in year_str:
 | |
|                 year_str = year_str.split('&')[0]
 | |
|         month_str = None
 | |
|         if 'month=' in remove_post_confirm_params:
 | |
|             month_str = remove_post_confirm_params.split('month=')[1]
 | |
|             if '&' in month_str:
 | |
|                 month_str = month_str.split('&')[0]
 | |
|         if '/statuses/' in remove_message_id:
 | |
|             remove_post_actor = remove_message_id.split('/statuses/')[0]
 | |
|         print('origin_path_str: ' + origin_path_str)
 | |
|         print('remove_post_actor: ' + remove_post_actor)
 | |
|         if origin_path_str in remove_post_actor:
 | |
|             to_list = [
 | |
|                 'https://www.w3.org/ns/activitystreams#Public',
 | |
|                 remove_post_actor
 | |
|             ]
 | |
|             delete_json = {
 | |
|                 "@context": "https://www.w3.org/ns/activitystreams",
 | |
|                 'actor': remove_post_actor,
 | |
|                 'object': remove_message_id,
 | |
|                 'to': to_list,
 | |
|                 'cc': [remove_post_actor + '/followers'],
 | |
|                 'type': 'Delete'
 | |
|             }
 | |
|             self.post_to_nickname = \
 | |
|                 get_nickname_from_actor(remove_post_actor)
 | |
|             if self.post_to_nickname:
 | |
|                 if month_str and year_str:
 | |
|                     if len(month_str) <= 3 and \
 | |
|                        len(year_str) <= 5 and \
 | |
|                        month_str.isdigit() and \
 | |
|                        year_str.isdigit():
 | |
|                         year_int = int(year_str)
 | |
|                         month_int = int(month_str)
 | |
|                         remove_calendar_event(base_dir,
 | |
|                                               self.post_to_nickname,
 | |
|                                               domain, year_int,
 | |
|                                               month_int,
 | |
|                                               remove_message_id)
 | |
|                 post_to_outbox_thread(self, delete_json,
 | |
|                                       curr_session, proxy_type)
 | |
|     if calling_domain.endswith('.onion') and onion_domain:
 | |
|         origin_path_str = 'http://' + onion_domain + users_path
 | |
|     elif (calling_domain.endswith('.i2p') and i2p_domain):
 | |
|         origin_path_str = 'http://' + i2p_domain + users_path
 | |
|     if page_number == 1:
 | |
|         redirect_headers(self, origin_path_str + '/outbox', cookie,
 | |
|                          calling_domain, 303)
 | |
|     else:
 | |
|         page_number_str = str(page_number)
 | |
|         actor_path_str = \
 | |
|             origin_path_str + '/outbox?page=' + page_number_str
 | |
|         redirect_headers(self, actor_path_str,
 | |
|                          cookie, calling_domain, 303)
 | |
|     self.server.postreq_busy = False
 |