From 53a72091ae7995326d03c6f814e8f9643b5f334a Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 24 Feb 2022 10:18:54 +0000 Subject: [PATCH] dav handler method name --- daemon.py | 7 +++-- epicyon.py | 55 +++++++++++++++++++++++++++++++++++++ happening.py | 45 ++++++++++++++++++++++++++++++ session.py | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 181 insertions(+), 3 deletions(-) diff --git a/daemon.py b/daemon.py index b0b83d708..ed2bb9154 100644 --- a/daemon.py +++ b/daemon.py @@ -16856,7 +16856,7 @@ class PubServer(BaseHTTPRequestHandler): self._404() return if not self._is_authorized(): - print('PROPFIND Not authorized') + print(endpoint_type.upper() + ' not authorized') self._403() return nickname = self.path.split('/calendars/')[1] @@ -16877,9 +16877,10 @@ class PubServer(BaseHTTPRequestHandler): propfind_bytes = self.rfile.read(length) except SocketError as ex: if ex.errno == errno.ECONNRESET: - print('EX: PROPFIND connection reset by peer') + print('EX: ' + endpoint_type.upper() + + ' connection reset by peer') else: - print('EX: PROPFIND socket error') + print('EX: ' + endpoint_type.upper() + ' socket error') self._400() return except ValueError as ex: diff --git a/epicyon.py b/epicyon.py index a98d161a7..86f8f2a67 100644 --- a/epicyon.py +++ b/epicyon.py @@ -13,6 +13,7 @@ import sys import time import argparse import getpass +import datetime from person import get_actor_json from person import create_person from person import create_group @@ -101,6 +102,7 @@ from announce import send_announce_via_server from socnet import instances_graph from migrate import migrate_accounts from desktop_client import run_desktop_client +from happening import dav_month_via_server def str2bool(value_str) -> bool: @@ -115,6 +117,7 @@ def str2bool(value_str) -> bool: raise argparse.ArgumentTypeError('Boolean value expected.') +search_date = datetime.datetime.now() parser = argparse.ArgumentParser(description='ActivityPub Server') parser.add_argument('--content_license_url', type=str, default='https://creativecommons.org/licenses/by/4.0', @@ -172,6 +175,12 @@ parser.add_argument('--i2p_domain', dest='i2p_domain', type=str, parser.add_argument('-p', '--port', dest='port', type=int, default=None, help='Port number to run on') +parser.add_argument('--year', dest='year', type=int, + default=search_date.year, + help='Year for calendar query') +parser.add_argument('--month', dest='month', type=int, + default=search_date.month, + help='Month for calendar query') parser.add_argument('--postsPerSource', dest='max_newswire_postsPerSource', type=int, default=4, @@ -329,6 +338,11 @@ parser.add_argument("--repliesEnabled", "--commentsEnabled", type=str2bool, nargs='?', const=True, default=True, help="Enable replies to a post") +parser.add_argument("--dav", + dest='dav', + type=str2bool, nargs='?', + const=True, default=False, + help="Caldav") parser.add_argument("--show_publish_as_icon", dest='show_publish_as_icon', type=str2bool, nargs='?', @@ -1375,6 +1389,47 @@ if args.message: time.sleep(1) sys.exit() +if args.dav: + if not args.nickname: + print('Please specify a nickname with --nickname') + sys.exit() + if not args.domain: + print('Please specify a domain with --domain') + sys.exit() + if not args.year: + print('Please specify a year with --year') + sys.exit() + if not args.month: + print('Please specify a month with --month') + sys.exit() + if not args.password: + args.password = getpass.getpass('Password: ') + if not args.password: + print('Specify a password with the --password option') + sys.exit() + args.password = args.password.replace('\n', '') + proxy_type = None + if args.tor or domain.endswith('.onion'): + proxy_type = 'tor' + if domain.endswith('.onion'): + args.port = 80 + elif args.i2p or domain.endswith('.i2p'): + proxy_type = 'i2p' + if domain.endswith('.i2p'): + args.port = 80 + elif args.gnunet: + proxy_type = 'gnunet' + session = create_session(proxy_type) + result = \ + dav_month_via_server(session, http_prefix, + args.nickname, args.domain, args.port, + args.debug, + args.year, args.month, + args.password) + if result: + print(str(result)) + sys.exit() + if args.announce: if not args.nickname: print('Specify a nickname with the --nickname option') diff --git a/happening.py b/happening.py index a3148ed98..9c70092da 100644 --- a/happening.py +++ b/happening.py @@ -23,8 +23,11 @@ from utils import remove_html from utils import get_display_name from utils import delete_post from utils import get_status_number +from utils import get_full_domain from filters import is_filtered from context import get_individual_post_context +from session import get_method +from auth import create_basic_auth_header def _dav_date_from_string(timestamp: str) -> str: @@ -1259,3 +1262,45 @@ def dav_delete_response(base_dir: str, nickname: str, domain: str, nickname, domain, post_filename, debug, recent_posts_cache) return 'Ok' + + +def dav_month_via_server(session, http_prefix: str, + nickname: str, domain: str, port: int, + debug: bool, + year: int, month: int, + password: str) -> str: + """Gets the icalendar for a month via caldav + """ + auth_header = create_basic_auth_header(nickname, password) + + headers = { + 'host': domain, + 'Content-type': 'application/xml', + 'Authorization': auth_header + } + domain_full = get_full_domain(domain, port) + params = {} + url = http_prefix + '://' + domain_full + '/calendars/' + nickname + month_str = str(month) + if month < 10: + month_str = '0' + month_str + xml_str = \ + '\n' + \ + '\n' + \ + ' \n' + \ + ' \n' + \ + ' \n' + \ + ' \n' + \ + ' \n' + \ + ' \n' + \ + ' \n' + \ + ' \n' + \ + ' \n' + \ + ' \n' + \ + '' + result = get_method("REPORT", xml_str, session, url, params, debug) + return result diff --git a/session.py b/session.py index 398c89328..9d951d0d1 100644 --- a/session.py +++ b/session.py @@ -664,3 +664,80 @@ def download_image_any_mime_type(session, url: str, if 'image/' + m_type in content_type: mime_type = 'image/' + m_type return result.content, mime_type + + +def get_method(method_name: str, xml_str: str, + session, url: str, params: {}, debug: bool, + version: str = '1.3.0', http_prefix: str = 'https', + domain: str = 'testdomain', + timeout_sec: int = 20, quiet: bool = False) -> {}: + if method_name not in ("REPORT", "PUT", "PROPFIND"): + print("Unrecognized method: " + method_name) + return None + if not isinstance(url, str): + if debug and not quiet: + print('url: ' + str(url)) + print('ERROR: get_method failed, url should be a string') + return None + headers = { + 'Accept': 'application/xml' + } + session_params = {} + session_headers = {} + if headers: + session_headers = headers + if params: + session_params = params + session_headers['User-Agent'] = 'Epicyon/' + version + if domain: + session_headers['User-Agent'] += \ + '; +' + http_prefix + '://' + domain + '/' + if not session: + if not quiet: + print('WARN: get_method failed, no session specified for get_vcard') + return None + + if debug: + HTTPConnection.debuglevel = 1 + + try: + result = session.request(method_name, url, headers=session_headers, + data=xml_str, + params=session_params, timeout=timeout_sec) + if result.status_code != 200 and result.status_code != 207: + if result.status_code == 401: + print("WARN: get_method " + url + ' rejected by secure mode') + elif result.status_code == 403: + print('WARN: get_method Forbidden url: ' + url) + elif result.status_code == 404: + print('WARN: get_method Not Found url: ' + url) + elif result.status_code == 410: + print('WARN: get_method no longer available url: ' + url) + else: + print('WARN: get_method url: ' + url + + ' failed with error code ' + + str(result.status_code) + + ' headers: ' + str(session_headers)) + return result.content.decode('utf-8') + except requests.exceptions.RequestException as ex: + session_headers2 = session_headers.copy() + if session_headers2.get('Authorization'): + session_headers2['Authorization'] = 'REDACTED' + if debug and not quiet: + print('EX: get_method failed, url: ' + str(url) + ', ' + + 'headers: ' + str(session_headers2) + ', ' + + 'params: ' + str(session_params) + ', ' + str(ex)) + except ValueError as ex: + session_headers2 = session_headers.copy() + if session_headers2.get('Authorization'): + session_headers2['Authorization'] = 'REDACTED' + if debug and not quiet: + print('EX: get_method failed, url: ' + str(url) + ', ' + + 'headers: ' + str(session_headers2) + ', ' + + 'params: ' + str(session_params) + ', ' + str(ex)) + except SocketError as ex: + if not quiet: + if ex.errno == errno.ECONNRESET: + print('EX: get_method failed, ' + + 'connection was reset during get_vcard ' + str(ex)) + return None