__filename__ = "epicyon.py" __author__ = "Bob Mottram" __license__ = "AGPL3+" __version__ = "1.5.0" __maintainer__ = "Bob Mottram" __email__ = "bob@libreserver.org" __status__ = "Production" __module_group__ = "Commandline Interface" import os import shutil 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 from person import set_profile_image from person import remove_account from person import activate_account2 from person import deactivate_account from skills import set_skill_level from roles import set_role from webfinger import webfinger_handle from bookmarks import send_bookmark_via_server from bookmarks import send_undo_bookmark_via_server from conversation import download_conversation_posts from keys import get_instance_actor_key from posts import set_post_expiry_days from posts import send_mute_via_server from posts import send_undo_mute_via_server from posts import c2s_box_json from posts import download_follow_collection from posts import get_public_post_domains from posts import get_public_post_domains_blocked from posts import send_block_via_server from posts import send_undo_block_via_server from posts import create_public_post from posts import delete_all_posts from posts import expire_posts from posts import archive_posts from posts import send_post_via_server from posts import get_public_posts_of_person from posts import get_user_url from posts import check_domains from session import create_session from session import get_json from session import get_vcard from session import download_html from session import verify_html from session import download_ssml from newswire import get_rss from filters import add_filter from filters import remove_filter from pprint import pprint from daemon import run_daemon from follow import get_follow_requests_via_server from follow import get_following_via_server from follow import get_followers_via_server from follow import clear_follows from follow import add_follower_of_person from follow import send_follow_request_via_server from follow import send_unfollow_request_via_server from tests import test_shared_items_federation from tests import test_group_follow from tests import test_post_message_between_servers from tests import test_follow_between_servers from tests import test_client_to_server from tests import test_update_actor from tests import run_all_tests from auth import store_basic_credentials from auth import create_password from utils import remove_html from utils import remove_eol from utils import text_in_file from utils import remove_domain_port from utils import get_port_from_domain from utils import has_users_path from utils import get_full_domain from utils import set_config_param from utils import get_config_param from utils import get_domain_from_actor from utils import get_nickname_from_actor from utils import follow_person from utils import valid_nickname from utils import get_protocol_prefixes from utils import acct_dir from utils import resembles_url from media import archive_media from media import get_attachment_media_type from delete import send_delete_via_server from like import send_like_via_server from like import send_undo_like_via_server from reaction import send_reaction_via_server from reaction import send_undo_reaction_via_server from reaction import valid_emoji_content from skills import send_skill_via_server from availability import set_availability from availability import send_availability_via_server from manualapprove import manual_deny_follow_request from manualapprove import manual_approve_follow_request from shares import send_share_via_server from shares import send_undo_share_via_server from shares import send_wanted_via_server from shares import send_undo_wanted_via_server from shares import add_share from theme import set_theme 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 from happening import dav_day_via_server from content import import_emoji from relationships import get_moved_accounts from blocking import get_blocks_via_server def str2bool(value_str) -> bool: """Returns true if the given value is a boolean """ if isinstance(value_str, bool): return value_str if value_str.lower() in ('yes', 'true', 't', 'y', '1'): return True if value_str.lower() in ('no', 'false', 'f', 'n', '0'): return False raise argparse.ArgumentTypeError('Boolean value expected.') def _command_options() -> None: """Parse the command options """ opt = {} search_date = datetime.datetime.now() parser = argparse.ArgumentParser(description='ActivityPub Server') parser.add_argument('--setadmin', type=str, default=None, help='Sets the admin nickname') parser.add_argument('--eventDate', type=str, default=None, help='Date for an event when sending a c2s post' + ' YYYY-MM-DD') parser.add_argument('--eventTime', type=str, default=None, help='Time for an event when sending a c2s post' + ' HH:MM') parser.add_argument('--eventEndTime', type=str, default=None, help='Time when an event ends when sending a ' + 'c2s post HH:MM') parser.add_argument('--eventLocation', type=str, default=None, help='Location for an event when sending a c2s post') parser.add_argument('--chatUrl', type=str, default=None, help='Chat link attachment on a post') parser.add_argument('--buyUrl', type=str, default=None, help='Link for buying something') parser.add_argument('--content_license_url', type=str, default='https://creativecommons.org/' + 'licenses/by-nc/4.0', help='Url of the license used for the ' + 'instance content') parser.add_argument('--media_license_url', type=str, default='https://creativecommons.org/' + 'licenses/by-nc/4.0', help='Url of the license used for attached media') parser.add_argument('--media_creator', type=str, default='', help="Attached media creator's name") parser.add_argument('--import_emoji', type=str, default='', help='Import emoji dict from the given filename') parser.add_argument('--lists_enabled', type=str, default=None, help='Names of content warning lists enabled. ' + 'See the cwlists directory') parser.add_argument('--userAgentBlocks', type=str, default=None, help='List of blocked user agents, separated ' + 'by commas') parser.add_argument('--crawlersAllowed', type=str, default=None, help='List of permitted web crawler user agents, ' + 'separated by commas') parser.add_argument('--libretranslate', dest='libretranslateUrl', type=str, default=None, help='URL for LibreTranslate service') parser.add_argument('--conversationId', dest='conversationId', type=str, default=None, help='Conversation Id which can be added ' + 'when sending a post') parser.add_argument('--libretranslateApiKey', dest='libretranslateApiKey', type=str, default=None, help='API key for LibreTranslate service') parser.add_argument('--defaultCurrency', dest='defaultCurrency', type=str, default=None, help='Default currency EUR/GBP/USD...') parser.add_argument('-n', '--nickname', dest='nickname', type=str, default=None, help='Nickname of the account to use') parser.add_argument('--conversation', dest='conversation', type=str, default=None, help='Download a conversation for the given post id') parser.add_argument('--screenreader', dest='screenreader', type=str, default=None, help='Name of the screen reader: ' + 'espeak/picospeaker/mimic3') parser.add_argument('--clacks', dest='clacks', type=str, default=None, help='http header clacks overhead') parser.add_argument('--fol', '--follow', dest='follow', type=str, default=None, help='Handle of account to follow. eg. ' + 'nickname@domain') parser.add_argument('--unfol', '--unfollow', dest='unfollow', type=str, default=None, help='Handle of account stop following. ' + 'eg. nickname@domain') parser.add_argument('-d', '--domain', dest='domain', type=str, default=None, help='Domain name of the server') parser.add_argument('--notificationType', '--notifyType', dest='notificationType', type=str, default='notify-send', help='Type of desktop notification command: ' + 'notify-send/zenity/osascript/' + 'New-BurntToastNotification') parser.add_argument('-o', '--onion', dest='onion', type=str, default=None, help='Onion domain name of the server if ' + 'primarily on clearnet') parser.add_argument('--i2p_domain', dest='i2p_domain', type=str, default=None, help='i2p domain name of the server if ' + 'primarily on clearnet') parser.add_argument('-p', '--port', dest='port', type=int, default=None, help='Port number to run on') parser.add_argument('--expiryDays', dest='expiryDays', type=int, default=None, help='Number of days after which posts expire ' + 'for the given account') parser.add_argument('--check-actor-timeout', dest='check_actor_timeout', type=int, default=2, help='Timeout in seconds used for checking is ' + 'an actor has changed when clicking their ' + 'avatar image') 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('--day', dest='day', type=int, default=None, help='Day for calendar query') parser.add_argument('--postsPerSource', dest='max_newswire_posts_per_source', type=int, default=4, help='Maximum newswire posts per feed or account') parser.add_argument('--maxSharesOnProfile', dest='max_shares_on_profile', type=int, default=8, help='Maximum shared items shown on profile') parser.add_argument('--dormant_months', dest='dormant_months', type=int, default=3, help='How many months does a followed account need ' + 'to be unseen for before being considered dormant') parser.add_argument('--default_reply_interval_hrs', dest='default_reply_interval_hrs', type=int, default=1000, help='How many hours after publication of a post ' + 'are replies to it permitted') parser.add_argument('--send_threads_timeout_mins', dest='send_threads_timeout_mins', type=int, default=30, help='How many minutes before a thread to send out ' + 'posts expires') parser.add_argument('--max_newswire_posts', dest='max_newswire_posts', type=int, default=20, help='Maximum newswire posts in the right column') parser.add_argument('--maxFeedSize', dest='max_newswire_feed_size_kb', type=int, default=10240, help='Maximum newswire rss/atom feed size in K') parser.add_argument('--max_feed_item_size_kb', dest='max_feed_item_size_kb', type=int, default=2048, help='Maximum size of an individual rss/atom ' + 'feed item in K') parser.add_argument('--max_mirrored_articles', dest='max_mirrored_articles', type=int, default=100, help='Maximum number of news articles to mirror.' + ' Set to zero for indefinite mirroring.') parser.add_argument('--max_news_posts', dest='max_news_posts', type=int, default=0, help='Maximum number of news timeline posts ' + 'to keep. Zero for no expiry.') parser.add_argument('--max_followers', dest='max_followers', type=int, default=2000, help='Maximum number of followers per account. ' + 'Zero for no limit.') parser.add_argument('--followers', dest='followers', type=str, default='', help='Show list of followers for the given actor') parser.add_argument('--postcache', dest='max_recent_posts', type=int, default=512, help='The maximum number of recent posts to ' + 'store in RAM') parser.add_argument('--proxy', dest='proxy_port', type=int, default=None, help='Proxy port number to run on') parser.add_argument('--path', dest='base_dir', type=str, default=os.getcwd(), help='Directory in which to store posts') parser.add_argument('--podcast-formats', dest='podcast_formats', type=str, default=None, help='Preferred podcast formats separated ' + 'by commas. eg. "opus, mp3, spx"') parser.add_argument('--ytdomain', dest='yt_replace_domain', type=str, default=None, help='Domain used to replace youtube.com') parser.add_argument('--twitterdomain', dest='twitter_replacement_domain', type=str, default=None, help='Domain used to replace twitter.com') parser.add_argument('--language', dest='language', type=str, default=None, help='Specify a single language code, ' + 'eg. "en" or "fr" or "de"') parser.add_argument('--languagesUnderstood', dest='languages_understood', type=str, default=None, help='List of the default languages understood eg. ' + '"en / fr"') parser.add_argument('-a', '--addaccount', dest='addaccount', type=str, default=None, help='Adds a new account') parser.add_argument('-g', '--addgroup', dest='addgroup', type=str, default=None, help='Adds a new group') parser.add_argument('--activate', dest='activate', type=str, default=None, help='Activate a previously deactivated account') parser.add_argument('--deactivate', dest='deactivate', type=str, default=None, help='Deactivate an account') parser.add_argument('-r', '--rmaccount', dest='rmaccount', type=str, default=None, help='Remove an account') parser.add_argument('--rmgroup', dest='rmgroup', type=str, default=None, help='Remove a group') parser.add_argument('--pass', '--password', dest='password', type=str, default=None, help='Set a password for an account') parser.add_argument('--chpass', '--changepassword', nargs='+', dest='changepassword', help='Change the password for an account') parser.add_argument('--actor', dest='actor', type=str, default=None, help='Show the json actor the given handle') parser.add_argument('--posts', dest='posts', type=str, default=None, help='Show posts for the given handle') parser.add_argument('--moved', dest='moved', type=str, default=None, help='Show moved accounts for the given handle') parser.add_argument('--postDomains', dest='postDomains', type=str, default=None, help='Show domains referenced in public ' 'posts for the given handle') parser.add_argument('--postDomainsBlocked', dest='postDomainsBlocked', type=str, default=None, help='Show blocked domains referenced in public ' 'posts for the given handle') parser.add_argument('--check_domains', dest='check_domains', type=str, default=None, help='Check domains of non-mutual followers for ' 'domains which are globally blocked by this instance') parser.add_argument('--socnet', dest='socnet', type=str, default=None, help='Show dot diagram for social network ' 'of federated instances') parser.add_argument('--postsraw', dest='postsraw', type=str, default=None, help='Show raw json of posts for the given handle') parser.add_argument('--vcard', dest='vcard', type=str, default=None, help='Show the vcard for a given activitypub ' + 'actor url') parser.add_argument('--xmlvcard', dest='xmlvcard', type=str, default=None, help='Show the xml vcard for a given ' + 'activitypub actor url') parser.add_argument('--json', dest='json', type=str, default=None, help='Show the json for a given activitypub url') parser.add_argument('--ssml', dest='ssml', type=str, default=None, help='Show the SSML for a given activitypub url') parser.add_argument('--htmlpost', dest='htmlpost', type=str, default=None, help='Show the html for a given activitypub url') parser.add_argument('--verifyurl', dest='verifyurl', type=str, default=None, help='Verify an identity using the given url') parser.add_argument('--rss', dest='rss', type=str, default=None, help='Show an rss feed for a given url') parser.add_argument('-f', '--federate', nargs='+', dest='federation_list', help='Specify federation list separated by spaces') parser.add_argument('--federateshares', nargs='+', dest='shared_items_federated_domains', help='Specify federation list for shared items, ' + 'separated by spaces') parser.add_argument("--following", "--followingList", dest='followingList', type=str2bool, nargs='?', const=True, default=False, help="Get the following list. Use nickname and " + "domain options to specify the account") parser.add_argument("--blocked", dest='blocked', type=str2bool, nargs='?', const=True, default=False, help="Get the blocked collection. Use nickname and " + "domain options to specify the account") parser.add_argument("--followersList", dest='followersList', type=str2bool, nargs='?', const=True, default=False, help="Get the followers list. Use nickname and " + "domain options to specify the account") parser.add_argument("--followRequestsList", dest='followRequestsList', type=str2bool, nargs='?', const=True, default=False, help="Get the follow requests list. Use nickname " + "and domain options to specify the account") parser.add_argument("--repliesEnabled", "--commentsEnabled", dest='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("--public_replies_unlisted", dest='public_replies_unlisted', type=str2bool, nargs='?', const=True, default=False, help="Whether replies to public posts " + "should be unlisted") parser.add_argument("--show_publish_as_icon", dest='show_publish_as_icon', type=str2bool, nargs='?', const=True, default=True, help="Whether to show newswire publish " + "as an icon or a button") parser.add_argument("--full_width_tl_button_header", dest='full_width_tl_button_header', type=str2bool, nargs='?', const=True, default=False, help="Whether to show the timeline " + "button header containing inbox and outbox " + "as the full width of the screen") parser.add_argument("--icons_as_buttons", dest='icons_as_buttons', type=str2bool, nargs='?', const=True, default=False, help="Show header icons as buttons") parser.add_argument("--log_login_failures", dest='log_login_failures', type=str2bool, nargs='?', const=True, default=False, help="Whether to log longin failures") parser.add_argument("--rss_icon_at_top", dest='rss_icon_at_top', type=str2bool, nargs='?', const=True, default=True, help="Whether to show the rss icon at the top or " + "bottom of the timeline") parser.add_argument("--low_bandwidth", dest='low_bandwidth', type=str2bool, nargs='?', const=True, default=True, help="Whether to use low bandwidth images") parser.add_argument("--publish_button_at_top", dest='publish_button_at_top', type=str2bool, nargs='?', const=True, default=False, help="Whether to show the publish button at the " + "top of the newswire column") parser.add_argument("--allow_local_network_access", dest='allow_local_network_access', type=str2bool, nargs='?', const=True, default=False, help="Whether to allow access to local network " + "addresses. This might be useful when deploying in " + "a mesh network") parser.add_argument("--verify_all_signatures", dest='verify_all_signatures', type=str2bool, nargs='?', const=True, default=False, help="Whether to require that all incoming " + "posts have valid jsonld signatures") parser.add_argument("--broch_mode", dest='broch_mode', type=str2bool, nargs='?', const=True, default=False, help="Enable broch mode") parser.add_argument("--dyslexic_font", dest='dyslexic_font', type=str2bool, nargs='?', const=True, default=False, help="Use dyslexic font") parser.add_argument("--nodeinfoaccounts", dest='show_node_info_accounts', type=str2bool, nargs='?', const=True, default=False, help="Show numbers of accounts within nodeinfo " + "metadata") parser.add_argument("--nodeinfoversion", dest='show_node_info_version', type=str2bool, nargs='?', const=True, default=False, help="Show version number within nodeinfo metadata") parser.add_argument("--noKeyPress", dest='noKeyPress', type=str2bool, nargs='?', const=True, default=False, help="Notification daemon does not wait for " + "keypresses") parser.add_argument("--notifyShowNewPosts", dest='notifyShowNewPosts', type=str2bool, nargs='?', const=True, default=False, help="Desktop client shows/speaks new posts " + "as they arrive") parser.add_argument("--noapproval", type=str2bool, nargs='?', const=True, default=False, help="Allow followers without approval") parser.add_argument("--mediainstance", type=str2bool, nargs='?', const=True, default=False, help="Media Instance - favor media over text") parser.add_argument("--dateonly", type=str2bool, nargs='?', const=True, default=False, help="Only show the date at the bottom of posts") parser.add_argument("--blogsinstance", type=str2bool, nargs='?', const=True, default=False, help="Blogs Instance - favor blogs over microblogging") parser.add_argument("--newsinstance", type=str2bool, nargs='?', const=True, default=False, help="News Instance - favor news over microblogging") parser.add_argument("--positivevoting", type=str2bool, nargs='?', const=True, default=False, help="On newswire, whether moderators vote " + "positively for or veto against items") parser.add_argument("--debug", type=str2bool, nargs='?', const=True, default=False, help="Show debug messages") parser.add_argument("--notificationSounds", type=str2bool, nargs='?', const=True, default=True, help="Play notification sounds") parser.add_argument("--secure_mode", type=str2bool, nargs='?', const=True, default=False, help="Requires all GET requests to be signed, " + "so that the sender can be identifies and " + "blocked if neccessary") parser.add_argument("--instance_only_skills_search", type=str2bool, nargs='?', const=True, default=False, help="Skills searches only return " + "results from this instance") parser.add_argument("--http", type=str2bool, nargs='?', const=True, default=False, help="Use http only") parser.add_argument("--gnunet", type=str2bool, nargs='?', const=True, default=False, help="Use gnunet protocol only") parser.add_argument("--ipfs", type=str2bool, nargs='?', const=True, default=False, help="Use ipfs protocol only") parser.add_argument("--ipns", type=str2bool, nargs='?', const=True, default=False, help="Use ipns protocol only") parser.add_argument("--dat", type=str2bool, nargs='?', const=True, default=False, help="Use dat protocol only") parser.add_argument("--hyper", type=str2bool, nargs='?', const=True, default=False, help="Use hypercore protocol only") parser.add_argument("--i2p", type=str2bool, nargs='?', const=True, default=False, help="Use i2p protocol only") parser.add_argument("--tor", type=str2bool, nargs='?', const=True, default=False, help="Route via Tor") parser.add_argument("--migrations", type=str2bool, nargs='?', const=True, default=False, help="Migrate moved accounts") parser.add_argument("--tests", type=str2bool, nargs='?', const=True, default=False, help="Run unit tests") parser.add_argument("--testsnetwork", type=str2bool, nargs='?', const=True, default=False, help="Run network unit tests") parser.add_argument("--testdata", type=str2bool, nargs='?', const=True, default=False, help="Generate some data for testing purposes") parser.add_argument('--icon', '--avatar', dest='avatar', type=str, default=None, help='Set the avatar filename for an account') parser.add_argument('--image', '--background', dest='backgroundImage', type=str, default=None, help='Set the profile background image for an account') parser.add_argument('--archive', dest='archive', type=str, default=None, help='Archive old files to the given directory') parser.add_argument('--archiveweeks', dest='archiveWeeks', type=int, default=0, help='Specify the number of weeks after which ' + 'media will be archived') parser.add_argument('--maxposts', dest='archiveMaxPosts', type=int, default=32000, help='Maximum number of posts in in/outbox') parser.add_argument('--maxCacheAgeDays', dest='maxCacheAgeDays', type=int, default=30, help='Maximum age of files in the announce cache') parser.add_argument('--minimumvotes', dest='minimumvotes', type=int, default=1, help='Minimum number of votes to remove or add' + ' a newswire item') parser.add_argument('--no_of_books', dest='no_of_books', type=int, default=10, help='Number of book events shown on profile screens') parser.add_argument('--max_like_count', dest='max_like_count', type=int, default=10, help='Maximum number of likes displayed on a post') parser.add_argument('--max_hashtags', dest='max_hashtags', type=int, default=20, help='Maximum number of hashtags on a post') parser.add_argument('--votingtime', dest='votingtime', type=int, default=1440, help='Time to vote on newswire items in minutes') parser.add_argument('--message', dest='message', type=str, default=None, help='Message content') parser.add_argument('--delete', dest='delete', type=str, default=None, help='Delete a specified post') parser.add_argument("--allowdeletion", type=str2bool, nargs='?', const=True, default=False, help="Do not allow deletions") parser.add_argument('--repeat', '--announce', dest='announce', type=str, default=None, help='Announce/repeat a url') parser.add_argument('--box', type=str, default=None, help='Returns the json for a given timeline, ' + 'with authentication') parser.add_argument('--page', '--pageNumber', dest='pageNumber', type=int, default=1, help='Page number when using the --box option') parser.add_argument('--favorite', '--like', dest='like', type=str, default=None, help='Like a url') parser.add_argument('--undolike', '--unlike', dest='undolike', type=str, default=None, help='Undo a like of a url') parser.add_argument('--react', '--reaction', dest='react', type=str, default=None, help='Reaction url') parser.add_argument('--emoji', type=str, default=None, help='Reaction emoji') parser.add_argument('--undoreact', '--undoreaction', dest='undoreact', type=str, default=None, help='Reaction url') parser.add_argument('--bookmark', '--bm', dest='bookmark', type=str, default=None, help='Bookmark the url of a post') parser.add_argument('--unbookmark', '--unbm', dest='unbookmark', type=str, default=None, help='Undo a bookmark given the url of a post') parser.add_argument('--sendto', dest='sendto', type=str, default=None, help='Address to send a post to') parser.add_argument('--attach', dest='attach', type=str, default=None, help='File to attach to a post') parser.add_argument('--imagedescription', dest='imageDescription', type=str, default=None, help='Description of an attached image') parser.add_argument('--city', dest='city', type=str, default='London, England', help='Spoofed city for image metadata misdirection') parser.add_argument('--warning', '--warn', '--cwsubject', '--subject', dest='subject', type=str, default=None, help='Subject of content warning') parser.add_argument('--reply', '--replyto', dest='replyto', type=str, default=None, help='Url of post to reply to') parser.add_argument("--followersonly", type=str2bool, nargs='?', const=True, default=True, help="Send to followers only") parser.add_argument("--followerspending", type=str2bool, nargs='?', const=True, default=False, help="Show a list of followers pending") parser.add_argument('--approve', dest='approve', type=str, default=None, help='Approve a follow request') parser.add_argument('--deny', dest='deny', type=str, default=None, help='Deny a follow request') parser.add_argument("-c", "--client", type=str2bool, nargs='?', const=True, default=False, help="Use as an ActivityPub client") parser.add_argument('--maxreplies', dest='max_replies', type=int, default=64, help='Maximum number of replies to a post') parser.add_argument('--max_mentions', '--hellthread', dest='max_mentions', type=int, default=10, help='Maximum number of mentions within a post') parser.add_argument('--max_emoji', '--maxemoji', dest='max_emoji', type=int, default=10, help='Maximum number of emoji within a post') parser.add_argument('--role', dest='role', type=str, default=None, help='Set a role for a person') parser.add_argument('--skill', dest='skill', type=str, default=None, help='Set a skill for a person') parser.add_argument('--level', dest='skillLevelPercent', type=int, default=None, help='Set a skill level for a person as a ' + 'percentage, or zero to remove') parser.add_argument('--status', '--availability', dest='availability', type=str, default=None, help='Set an availability status') parser.add_argument('--desktop', dest='desktop', type=str, default=None, help='Run desktop client') parser.add_argument('--block', dest='block', type=str, default=None, help='Block a particular address') parser.add_argument('--unblock', dest='unblock', type=str, default=None, help='Remove a block on a particular address') parser.add_argument('--mute', dest='mute', type=str, default=None, help='Mute a particular post URL') parser.add_argument('--unmute', dest='unmute', type=str, default=None, help='Unmute a particular post URL') parser.add_argument('--filter', dest='filterStr', type=str, default=None, help='Adds a word or phrase which if present will ' + 'cause a message to be ignored') parser.add_argument('--unfilter', dest='unfilterStr', type=str, default=None, help='Remove a filter on a particular word or phrase') parser.add_argument('--domainmax', dest='domain_max_posts_per_day', type=int, default=16000, help='Maximum number of received posts ' + 'from a domain per day') parser.add_argument('--accountmax', dest='account_max_posts_per_day', type=int, default=8640, help='Maximum number of received posts ' + 'from an account per day') parser.add_argument('--itemName', dest='itemName', type=str, default=None, help='Name of an item being shared') parser.add_argument('--undoItemName', dest='undoItemName', type=str, default=None, help='Name of an shared item to remove') parser.add_argument('--wantedItemName', dest='wantedItemName', type=str, default=None, help='Name of a wanted item') parser.add_argument('--undoWantedItemName', dest='undoWantedItemName', type=str, default=None, help='Name of a wanted item to remove') parser.add_argument('--summary', dest='summary', type=str, default=None, help='Description of an item being shared') parser.add_argument('--itemImage', dest='itemImage', type=str, default=None, help='Filename of an image for an item being shared') parser.add_argument('--itemQty', dest='itemQty', type=float, default=1, help='Quantity of items being shared') parser.add_argument('--itemPrice', dest='itemPrice', type=str, default="0.00", help='Total price of items being shared') parser.add_argument('--itemCurrency', dest='itemCurrency', type=str, default="EUR", help='Currency of items being shared') parser.add_argument('--itemType', dest='itemType', type=str, default=None, help='Type of item being shared') parser.add_argument('--itemCategory', dest='itemCategory', type=str, default=None, help='Category of item being shared') parser.add_argument('--location', dest='location', type=str, default=None, help='Location/City of item being shared') parser.add_argument('--mapFormat', dest='mapFormat', type=str, default='kml', help='Format for hashtag maps GPX/KML') parser.add_argument('--duration', dest='duration', type=str, default=None, help='Duration for which to share an item') parser.add_argument('--registration', dest='registration', type=str, default='open', help='Whether new registrations are open or closed') parser.add_argument("--nosharedinbox", type=str2bool, nargs='?', const=True, default=False, help='Disable shared inbox') parser.add_argument('--maxregistrations', dest='maxRegistrations', type=int, default=10, help='The maximum number of new registrations') parser.add_argument("--resetregistrations", type=str2bool, nargs='?', const=True, default=False, help="Reset the number of remaining registrations") argb = parser.parse_args() debug = False if argb.debug: debug = True else: if os.path.isfile('debug'): debug = True if argb.tests: run_all_tests() sys.exit() if argb.testsnetwork: print('Network Tests') base_dir = os.getcwd() test_shared_items_federation(base_dir) test_group_follow(base_dir) test_post_message_between_servers(base_dir) test_follow_between_servers(base_dir) test_client_to_server(base_dir) test_update_actor(base_dir) print('All tests succeeded') sys.exit() http_prefix = 'https' if argb.http or argb.i2p: http_prefix = 'http' elif argb.ipfs: http_prefix = 'ipfs' elif argb.ipns: http_prefix = 'ipns' elif argb.gnunet: http_prefix = 'gnunet' base_dir = argb.base_dir if base_dir.endswith('/'): print("--path option should not end with '/'") sys.exit() if not argb.public_replies_unlisted: pub_replies_unlisted = \ get_config_param(base_dir, 'publicRepliesUnlisted') if pub_replies_unlisted is not None: if isinstance(pub_replies_unlisted, bool): argb.public_replies_unlisted = pub_replies_unlisted if argb.setadmin: set_config_param(base_dir, 'admin', argb.setadmin) sys.exit() if argb.import_emoji: import_filename = argb.import_emoji print('Importing custom emoji from ' + import_filename) session = create_session(None) import_emoji(base_dir, import_filename, session) sys.exit() # automatic translations if argb.libretranslateUrl: if resembles_url(argb.libretranslateUrl): set_config_param(base_dir, 'libretranslateUrl', argb.libretranslateUrl) if argb.libretranslateApiKey: set_config_param(base_dir, 'libretranslateApiKey', argb.libretranslateApiKey) if argb.posts: if not argb.domain: origin_domain = get_config_param(base_dir, 'domain') else: origin_domain = argb.domain if debug: print('origin_domain: ' + str(origin_domain)) if argb.posts.startswith('@'): argb.posts = argb.posts[1:] url_with_at = False if '://' in argb.posts and '/@' in argb.posts and \ '/@/' not in argb.posts: url_with_at = True if '@' not in argb.posts or '/@/' in argb.posts or \ url_with_at: posts_nickname = get_nickname_from_actor(argb.posts) if not posts_nickname: print('No nickname found ' + argb.posts) sys.exit() posts_domain, posts_port = get_domain_from_actor(argb.posts) if not posts_domain: print('No domain found ' + argb.posts) sys.exit() argb.posts = \ get_full_domain(posts_nickname + '@' + posts_domain, posts_port) if not argb.http: argb.port = 443 nickname = argb.posts.split('@')[0] domain = argb.posts.split('@')[1] proxy_type = None if argb.tor or domain.endswith('.onion'): proxy_type = 'tor' if domain.endswith('.onion'): argb.port = 80 elif argb.i2p or domain.endswith('.i2p'): proxy_type = 'i2p' if domain.endswith('.i2p'): argb.port = 80 elif argb.gnunet: proxy_type = 'gnunet' if not argb.language: argb.language = 'en' signing_priv_key_pem = get_instance_actor_key(base_dir, origin_domain) get_public_posts_of_person(base_dir, nickname, domain, False, True, proxy_type, argb.port, http_prefix, debug, __version__, argb.language, signing_priv_key_pem, origin_domain) sys.exit() if argb.moved: if not argb.domain: origin_domain = get_config_param(base_dir, 'domain') else: origin_domain = argb.domain if debug: print('origin_domain: ' + str(origin_domain)) if argb.moved.startswith('@'): argb.moved = argb.moved[1:] if '@' not in argb.moved: if '/users/' in argb.moved: moved_nickname = get_nickname_from_actor(argb.moved) moved_domain, moved_port = get_domain_from_actor(argb.moved) argb.moved = \ get_full_domain(moved_nickname + '@' + moved_domain, moved_port) else: print('Syntax: --moved nickname@domain') sys.exit() if not argb.http: argb.port = 443 nickname = argb.moved.split('@')[0] domain = argb.moved.split('@')[1] proxy_type = None if argb.tor or domain.endswith('.onion'): proxy_type = 'tor' if domain.endswith('.onion'): argb.port = 80 elif argb.i2p or domain.endswith('.i2p'): proxy_type = 'i2p' if domain.endswith('.i2p'): argb.port = 80 elif argb.gnunet: proxy_type = 'gnunet' if not argb.language: argb.language = 'en' moved_dict = \ get_moved_accounts(base_dir, nickname, domain, 'following.txt') pprint(moved_dict) sys.exit() if argb.postDomains: if argb.postDomains.startswith('@'): argb.postDomains = argb.postDomains[1:] if '@' not in argb.postDomains: if '/users/' in argb.postDomains: posts_nickname = get_nickname_from_actor(argb.postDomains) posts_domain, posts_port = \ get_domain_from_actor(argb.postDomains) argb.postDomains = \ get_full_domain(posts_nickname + '@' + posts_domain, posts_port) else: print('Syntax: --postDomains nickname@domain') sys.exit() if not argb.http: argb.port = 443 nickname = argb.postDomains.split('@')[0] domain = argb.postDomains.split('@')[1] proxy_type = None if argb.tor or domain.endswith('.onion'): proxy_type = 'tor' if domain.endswith('.onion'): argb.port = 80 elif argb.i2p or domain.endswith('.i2p'): proxy_type = 'i2p' if domain.endswith('.i2p'): argb.port = 80 elif argb.gnunet: proxy_type = 'gnunet' word_frequency = {} domain_list = [] if not argb.language: argb.language = 'en' signing_priv_key_pem = None if not argb.domain: origin_domain = get_config_param(base_dir, 'domain') else: origin_domain = argb.domain if argb.secure_mode: signing_priv_key_pem = \ get_instance_actor_key(base_dir, origin_domain) domain_list = \ get_public_post_domains(None, base_dir, nickname, domain, origin_domain, proxy_type, argb.port, http_prefix, debug, __version__, word_frequency, domain_list, argb.language, signing_priv_key_pem) for post_domain in domain_list: print(post_domain) sys.exit() if argb.postDomainsBlocked: # Domains which were referenced in public posts by a # given handle but which are globally blocked on this instance if argb.postDomainsBlocked.startswith('@'): argb.postDomainsBlocked = argb.postDomainsBlocked[1:] if '@' not in argb.postDomainsBlocked: if '/users/' in argb.postDomainsBlocked: posts_nickname = \ get_nickname_from_actor(argb.postDomainsBlocked) posts_domain, posts_port = \ get_domain_from_actor(argb.postDomainsBlocked) argb.postDomainsBlocked = \ get_full_domain(posts_nickname + '@' + posts_domain, posts_port) else: print('Syntax: --postDomainsBlocked nickname@domain') sys.exit() if not argb.http: argb.port = 443 nickname = argb.postDomainsBlocked.split('@')[0] domain = argb.postDomainsBlocked.split('@')[1] proxy_type = None if argb.tor or domain.endswith('.onion'): proxy_type = 'tor' if domain.endswith('.onion'): argb.port = 80 elif argb.i2p or domain.endswith('.i2p'): proxy_type = 'i2p' if domain.endswith('.i2p'): argb.port = 80 elif argb.gnunet: proxy_type = 'gnunet' word_frequency = {} domain_list = [] if not argb.language: argb.language = 'en' signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) domain_list = \ get_public_post_domains_blocked(None, base_dir, nickname, domain, proxy_type, argb.port, http_prefix, debug, __version__, word_frequency, domain_list, argb.language, signing_priv_key_pem) for post_domain in domain_list: print(post_domain) sys.exit() if argb.check_domains: # Domains which were referenced in public posts by a # given handle but which are globally blocked on this instance if argb.check_domains.startswith('@'): argb.check_domains = argb.check_domains[1:] if '@' not in argb.check_domains: if '/users/' in argb.check_domains: posts_nickname = get_nickname_from_actor(argb.posts) posts_domain, posts_port = get_domain_from_actor(argb.posts) argb.check_domains = \ get_full_domain(posts_nickname + '@' + posts_domain, posts_port) else: print('Syntax: --check_domains nickname@domain') sys.exit() if not argb.http: argb.port = 443 nickname = argb.check_domains.split('@')[0] domain = argb.check_domains.split('@')[1] proxy_type = None if argb.tor or domain.endswith('.onion'): proxy_type = 'tor' if domain.endswith('.onion'): argb.port = 80 elif argb.i2p or domain.endswith('.i2p'): proxy_type = 'i2p' if domain.endswith('.i2p'): argb.port = 80 elif argb.gnunet: proxy_type = 'gnunet' max_blocked_domains = 0 if not argb.language: argb.language = 'en' signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) check_domains(None, base_dir, nickname, domain, proxy_type, argb.port, http_prefix, debug, __version__, max_blocked_domains, False, argb.language, signing_priv_key_pem) sys.exit() if argb.socnet: if ',' not in argb.socnet: print('Syntax: ' '--socnet nick1@domain1,nick2@domain2,nick3@domain3') sys.exit() if not argb.http: argb.port = 443 proxy_type = 'tor' if not argb.language: argb.language = 'en' if not argb.domain: argb.domain = get_config_param(base_dir, 'domain') domain = '' if argb.domain: domain = argb.domain signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) dot_graph = instances_graph(base_dir, argb.socnet, proxy_type, argb.port, http_prefix, debug, __version__, argb.language, signing_priv_key_pem) try: with open('socnet.dot', 'w+', encoding='utf-8') as fp_soc: fp_soc.write(dot_graph) print('Saved to socnet.dot') except OSError: print('EX: commandline unable to write socnet.dot') sys.exit() if argb.postsraw: if not argb.domain: origin_domain = get_config_param(base_dir, 'domain') else: origin_domain = argb.domain if debug: print('origin_domain: ' + str(origin_domain)) if argb.postsraw.startswith('@'): argb.postsraw = argb.postsraw[1:] url_with_at = False if '://' in argb.postsraw and '/@' in argb.postsraw and \ '/@/' not in argb.postsraw: url_with_at = True if '@' not in argb.postsraw or '/@/' in argb.postsraw or \ url_with_at: posts_nickname = get_nickname_from_actor(argb.postsraw) if not posts_nickname: print('No nickname found ' + argb.postsraw) sys.exit() posts_domain, posts_port = get_domain_from_actor(argb.postsraw) if not posts_domain: print('No domain found ' + argb.postsraw) sys.exit() argb.postsraw = \ get_full_domain(posts_nickname + '@' + posts_domain, posts_port) if argb.debug: print('handle: ' + argb.postsraw) if '@' not in argb.postsraw: print('Syntax: --postsraw nickname@domain') sys.exit() if not argb.http: argb.port = 443 nickname = argb.postsraw.split('@')[0] domain = argb.postsraw.split('@')[1] proxy_type = None if argb.tor or domain.endswith('.onion'): proxy_type = 'tor' elif argb.i2p or domain.endswith('.i2p'): proxy_type = 'i2p' elif argb.gnunet: proxy_type = 'gnunet' if not argb.language: argb.language = 'en' signing_priv_key_pem = get_instance_actor_key(base_dir, origin_domain) get_public_posts_of_person(base_dir, nickname, domain, False, False, proxy_type, argb.port, http_prefix, debug, __version__, argb.language, signing_priv_key_pem, origin_domain) sys.exit() if argb.json: proxy_type = None if '.onion/' in argb.json: proxy_type = 'tor' elif '.i2p/' in argb.json: proxy_type = 'i2p' session = create_session(proxy_type) profile_str = 'https://www.w3.org/ns/activitystreams' as_header = { 'Accept': 'application/ld+json; profile="' + profile_str + '"' } if not argb.domain: argb.domain = get_config_param(base_dir, 'domain') domain = '' if argb.domain: domain = argb.domain signing_priv_key_pem = get_instance_actor_key(base_dir, domain) if debug: print('base_dir: ' + str(base_dir)) if signing_priv_key_pem: print('Obtained instance actor signing key') else: print('Did not obtain instance actor key for ' + domain) test_json = get_json(signing_priv_key_pem, session, argb.json, as_header, None, debug, __version__, http_prefix, domain) if test_json: pprint(test_json) sys.exit() if argb.conversation: post_id = argb.conversation if '://' not in post_id: print('--conversation should be the url of a post') sys.exit() proxy_type = None if '.onion/' in post_id: proxy_type = 'tor' elif '.i2p/' in post_id: proxy_type = 'i2p' session = create_session(proxy_type) if not argb.domain: argb.domain = get_config_param(base_dir, 'domain') domain = '' if argb.domain: domain = argb.domain if not domain: print('Please specify a domain with the --domain option') sys.exit() nickname = '' if argb.nickname: nickname = argb.nickname if not nickname: print('Please specify a nickname with the --nickname option') sys.exit() conv_json = download_conversation_posts(True, session, http_prefix, base_dir, nickname, domain, post_id, argb.debug) if conv_json: pprint(conv_json) sys.exit() if argb.ssml: session = create_session(None) profile_str = 'https://www.w3.org/ns/activitystreams' as_header = { 'Accept': 'application/ssml+xml; profile="' + profile_str + '"' } if not argb.domain: argb.domain = get_config_param(base_dir, 'domain') domain = '' if argb.domain: domain = argb.domain signing_priv_key_pem = get_instance_actor_key(base_dir, domain) if debug: print('base_dir: ' + str(base_dir)) if signing_priv_key_pem: print('Obtained instance actor signing key') else: print('Did not obtain instance actor key for ' + domain) test_ssml = download_ssml(signing_priv_key_pem, session, argb.ssml, as_header, None, debug, __version__, http_prefix, domain) if test_ssml: print(str(test_ssml)) sys.exit() if argb.vcard: session = create_session(None) if not argb.domain: argb.domain = get_config_param(base_dir, 'domain') domain = '' if argb.domain: domain = argb.domain test_vcard = get_vcard(False, session, argb.vcard, None, debug, __version__, http_prefix, domain) if test_vcard: print(test_vcard) sys.exit() if argb.xmlvcard: session = create_session(None) if not argb.domain: argb.domain = get_config_param(base_dir, 'domain') domain = '' if argb.domain: domain = argb.domain test_vcard = get_vcard(True, session, argb.xmlvcard, None, debug, __version__, http_prefix, domain) if test_vcard: print(test_vcard) sys.exit() if argb.htmlpost: session = create_session(None) profile_str = 'https://www.w3.org/ns/activitystreams' as_header = { 'Accept': 'text/html; profile="' + profile_str + '"' } if not argb.domain: argb.domain = get_config_param(base_dir, 'domain') domain = '' if argb.domain: domain = argb.domain signing_priv_key_pem = get_instance_actor_key(base_dir, domain) if debug: print('base_dir: ' + str(base_dir)) if signing_priv_key_pem: print('Obtained instance actor signing key') else: print('Did not obtain instance actor key for ' + domain) test_html = download_html(signing_priv_key_pem, session, argb.htmlpost, as_header, None, debug, __version__, http_prefix, domain) if test_html: print(test_html) sys.exit() if argb.verifyurl: if not argb.nickname: print('You must specify a nickname for the handle ' + 'to be verified nickname@domain using the ' + '--nickname option') sys.exit() profile_str = 'https://www.w3.org/ns/activitystreams' as_header = { 'Accept': 'text/html; profile="' + profile_str + '"' } if not argb.domain: argb.domain = get_config_param(base_dir, 'domain') domain = '' if argb.domain: domain = argb.domain if not domain: print('You must specify a domain for the handle ' + 'to be verified nickname@domain using the ' + '--domain option') sys.exit() session = create_session(None) verified = \ verify_html(session, argb.verifyurl, debug, __version__, http_prefix, argb.nickname, domain) if verified: print('Verified') sys.exit() print('Verification failed') sys.exit() # create cache for actors if not os.path.isdir(base_dir + '/cache'): os.mkdir(base_dir + '/cache') if not os.path.isdir(base_dir + '/cache/actors'): print('Creating actors cache') os.mkdir(base_dir + '/cache/actors') if not os.path.isdir(base_dir + '/cache/announce'): print('Creating announce cache') os.mkdir(base_dir + '/cache/announce') # set the theme in config.json theme_name = get_config_param(base_dir, 'theme') if not theme_name: set_config_param(base_dir, 'theme', 'default') theme_name = 'default' if not argb.mediainstance: media_instance = get_config_param(base_dir, 'mediaInstance') if media_instance is not None: argb.mediainstance = media_instance if argb.mediainstance: argb.blogsinstance = False argb.newsinstance = False if not argb.newsinstance: news_instance = get_config_param(base_dir, 'newsInstance') if news_instance is not None: argb.newsinstance = news_instance if argb.newsinstance: argb.blogsinstance = False argb.mediainstance = False if not argb.blogsinstance: blogs_instance = get_config_param(base_dir, 'blogsInstance') if blogs_instance is not None: argb.blogsinstance = blogs_instance if argb.blogsinstance: argb.mediainstance = False argb.newsinstance = False # set the instance title in config.json title = get_config_param(base_dir, 'instanceTitle') if not title: set_config_param(base_dir, 'instanceTitle', 'Epicyon') # set the instance description in config.json desc_full = get_config_param(base_dir, 'instanceDescription') if not desc_full: set_config_param(base_dir, 'instanceDescription', 'Just another ActivityPub server') # set the short instance description in config.json desc_short = get_config_param(base_dir, 'instanceDescriptionShort') if not desc_short: set_config_param(base_dir, 'instanceDescriptionShort', 'Just another ActivityPub server') if argb.domain: domain = argb.domain set_config_param(base_dir, 'domain', domain) # comma separated list of preferred audio formats. eg. "opus", "mp3", "spx" # in order of preference preferred_podcast_formats = ['ogg', 'mpeg', 'opus', 'spx', 'wav'] if argb.podcast_formats: podcast_formats_str = argb.podcast_formats else: podcast_formats_str = \ get_config_param(base_dir, 'preferredPodcastFormats') if podcast_formats_str: podcast_formats = podcast_formats_str.split(',') preferred_podcast_formats = [] for pod_format in podcast_formats: pod_format = pod_format.lower().strip() if '/' not in pod_format: pod_format = 'audio/' + pod_format if pod_format in preferred_podcast_formats: continue preferred_podcast_formats.append(pod_format) if argb.rss: timeout_sec = 20 session = create_session(None) if not argb.language: argb.language = 'en' if not argb.domain: domain = 'mydomain' else: domain = argb.domain test_rss = get_rss(base_dir, domain, session, argb.rss, False, False, 1000, 1000, 1000, 1000, debug, preferred_podcast_formats, timeout_sec, argb.language) pprint(test_rss) sys.exit() if argb.onion: if not argb.onion.endswith('.onion'): print(argb.onion + ' does not look like an onion domain') sys.exit() if '://' in argb.onion: argb.onion = argb.onion.split('://')[1] onion_domain = argb.onion set_config_param(base_dir, 'onion', onion_domain) i2p_domain = None if argb.i2p_domain: if not argb.i2p_domain.endswith('.i2p'): print(argb.i2p_domain + ' does not look like an i2p domain') sys.exit() if '://' in argb.i2p_domain: argb.onion = argb.onion.split('://')[1] i2p_domain = argb.i2p_domain set_config_param(base_dir, 'i2pDomain', i2p_domain) if not argb.language: language_code = get_config_param(base_dir, 'language') if language_code: argb.language = language_code else: argb.language = 'en' # maximum number of new registrations if not argb.maxRegistrations: max_registrations = get_config_param(base_dir, 'maxRegistrations') if not max_registrations: max_registrations = 10 set_config_param(base_dir, 'maxRegistrations', str(max_registrations)) else: max_registrations = int(max_registrations) else: max_registrations = argb.maxRegistrations set_config_param(base_dir, 'maxRegistrations', str(max_registrations)) # if this is the initial run then allow new registrations if not get_config_param(base_dir, 'registration'): if argb.registration.lower() == 'open': set_config_param(base_dir, 'registration', 'open') set_config_param(base_dir, 'maxRegistrations', str(max_registrations)) set_config_param(base_dir, 'registrationsRemaining', str(max_registrations)) if argb.resetregistrations: set_config_param(base_dir, 'registrationsRemaining', str(max_registrations)) print('Number of new registrations reset to ' + str(max_registrations)) # unique ID for the instance instance_id = get_config_param(base_dir, 'instanceId') if not instance_id: instance_id = create_password(32) set_config_param(base_dir, 'instanceId', instance_id) print('Instance ID: ' + instance_id) # get domain name from configuration config_domain = get_config_param(base_dir, 'domain') if config_domain: domain = config_domain else: domain = 'localhost' # get onion domain name from configuration config_onion_domain = get_config_param(base_dir, 'onion') if config_onion_domain: onion_domain = config_onion_domain else: onion_domain = None # get i2p domain name from configuration configi2p_domain = get_config_param(base_dir, 'i2pDomain') if configi2p_domain: i2p_domain = configi2p_domain else: i2p_domain = None # get port number from configuration config_port = get_config_param(base_dir, 'port') if config_port: port = config_port else: if domain.endswith('.onion') or \ domain.endswith('.i2p'): port = 80 else: port = 443 config_proxy_port = get_config_param(base_dir, 'proxyPort') if config_proxy_port: proxy_port = config_proxy_port else: proxy_port = port nickname = None if argb.nickname: nickname = argb.nickname federation_list = [] if argb.federation_list: if len(argb.federation_list) == 1: if not (argb.federation_list[0].lower() == 'any' or argb.federation_list[0].lower() == 'all' or argb.federation_list[0].lower() == '*'): for federation_domain in argb.federation_list: if '@' in federation_domain: print(federation_domain + ': Federate with domains, not individual ' + 'accounts') sys.exit() federation_list = argb.federation_list.copy() set_config_param(base_dir, 'federationList', federation_list) else: config_federation_list = get_config_param(base_dir, 'federationList') if config_federation_list: federation_list = config_federation_list proxy_type = None if argb.tor or domain.endswith('.onion'): proxy_type = 'tor' elif argb.i2p or domain.endswith('.i2p'): proxy_type = 'i2p' elif argb.gnunet: proxy_type = 'gnunet' if argb.approve: if not argb.nickname: print('Specify a nickname with the --nickname option') sys.exit() if '@' not in argb.approve: print('syntax: --approve nick@domain') sys.exit() session_onion = None session_i2p = None session = create_session(proxy_type) send_threads = [] post_log = [] cached_webfingers = {} person_cache = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) onion_domain = get_config_param(base_dir, 'onionDomain') if argb.onion: onion_domain = argb.onion if onion_domain: session_onion = create_session('tor') i2p_domain = get_config_param(base_dir, 'i2pDomain') if argb.i2p_domain: i2p_domain = argb.i2p_domain if i2p_domain: session_i2p = create_session('i2p') followers_sync_cache = {} sites_unavailable = [] system_language = argb.language manual_approve_follow_request(session, session_onion, session_i2p, onion_domain, i2p_domain, base_dir, http_prefix, argb.nickname, domain, port, argb.approve, federation_list, send_threads, post_log, cached_webfingers, person_cache, debug, __version__, signing_priv_key_pem, proxy_type, followers_sync_cache, sites_unavailable, system_language) sys.exit() if argb.deny: if not argb.nickname: print('Specify a nickname with the --nickname option') sys.exit() if '@' not in argb.deny: print('syntax: --deny nick@domain') sys.exit() session_onion = None session_i2p = None session = create_session(proxy_type) send_threads = [] post_log = [] cached_webfingers = {} person_cache = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) onion_domain = get_config_param(base_dir, 'onionDomain') if argb.onion: onion_domain = argb.onion if onion_domain: session_onion = create_session('tor') i2p_domain = get_config_param(base_dir, 'i2pDomain') if argb.i2p_domain: i2p_domain = argb.i2p_domain if i2p_domain: session_i2p = create_session('i2p') followers_sync_cache = {} sites_unavailable = [] system_language = argb.language manual_deny_follow_request(session, session_onion, session_i2p, onion_domain, i2p_domain, base_dir, http_prefix, argb.nickname, domain, port, argb.deny, federation_list, send_threads, post_log, cached_webfingers, person_cache, debug, __version__, signing_priv_key_pem, followers_sync_cache, sites_unavailable, system_language) sys.exit() if argb.followerspending: if not argb.nickname: print('Specify a nickname with the --nickname option') sys.exit() accounts_dir = acct_dir(base_dir, argb.nickname, domain) approve_follows_filename = accounts_dir + '/followrequests.txt' approve_ctr = 0 if os.path.isfile(approve_follows_filename): with open(approve_follows_filename, 'r', encoding='utf-8') as approvefile: for approve in approvefile: approve1 = remove_eol(approve) print(approve1) approve_ctr += 1 if approve_ctr == 0: print('There are no follow requests pending approval.') sys.exit() if argb.message: if not argb.nickname: print('Specify a nickname with the --nickname option') sys.exit() if argb.eventDate: if '-' not in argb.eventDate or len(argb.eventDate) != 10: print('Event date format should be YYYY-MM-DD') sys.exit() if argb.eventTime: if ':' not in argb.eventTime or len(argb.eventTime) != 5: print('Event start time format should be HH:MM') sys.exit() if argb.eventEndTime: if ':' not in argb.eventEndTime or len(argb.eventEndTime) != 5: print('Event end time format should be HH:MM') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) session = create_session(proxy_type) if not argb.sendto: print('Specify an account to sent to: --sendto [nickname@domain]') sys.exit() if '@' not in argb.sendto and \ not argb.sendto.lower().endswith('public') and \ not argb.sendto.lower().endswith('followers'): print('syntax: --sendto [nickname@domain]') print(' --sendto public') print(' --sendto followers') sys.exit() if '@' in argb.sendto: to_nickname = argb.sendto.split('@')[0] to_domain = argb.sendto.split('@')[1] to_domain = remove_eol(to_domain) to_port = 443 if ':' in to_domain: to_port = get_port_from_domain(to_domain) to_domain = remove_domain_port(to_domain) else: if argb.sendto.endswith('followers'): to_nickname = None to_domain = 'followers' to_port = port else: to_nickname = None to_domain = 'public' to_port = port cc_url = None send_message = argb.message # client_to_server = argb.client attached_image_description = remove_html(argb.imageDescription) city = 'London, England' send_threads = [] post_log = [] person_cache = {} cached_webfingers = {} subject = argb.subject attach = argb.attach media_type = None if attach: media_type = get_attachment_media_type(attach) reply_to = argb.replyto is_article = False if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) languages_understood = [argb.language] if argb.languages_understood: languages_understood = [argb.languages_understood] translate = {} video_transcript = None auto_cw_cache = {} print('Sending post to ' + argb.sendto) send_post_via_server(signing_priv_key_pem, __version__, base_dir, session, argb.nickname, argb.password, domain, port, to_nickname, to_domain, to_port, cc_url, http_prefix, send_message, argb.commentsEnabled, attach, media_type, attached_image_description, video_transcript, city, cached_webfingers, person_cache, is_article, argb.language, languages_understood, argb.low_bandwidth, argb.content_license_url, argb.media_license_url, argb.media_creator, argb.eventDate, argb.eventTime, argb.eventEndTime, argb.eventLocation, translate, argb.buyUrl, argb.chatUrl, auto_cw_cache, argb.debug, reply_to, reply_to, argb.conversationId, subject) for _ in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.expiryDays is not None and argb.nickname and argb.domain: set_post_expiry_days(base_dir, argb.nickname, argb.domain, argb.expiryDays) print('Post expiry for ' + argb.nickname + ' set to ' + str(argb.expiryDays)) sys.exit() if argb.dav: if not argb.nickname: print('Please specify a nickname with --nickname') sys.exit() if not argb.domain: print('Please specify a domain with --domain') sys.exit() if not argb.year: print('Please specify a year with --year') sys.exit() if not argb.month: print('Please specify a month with --month') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) proxy_type = None if argb.tor or domain.endswith('.onion'): proxy_type = 'tor' if domain.endswith('.onion'): argb.port = 80 elif argb.i2p or domain.endswith('.i2p'): proxy_type = 'i2p' if domain.endswith('.i2p'): argb.port = 80 elif argb.gnunet: proxy_type = 'gnunet' session = create_session(proxy_type) if argb.day: result = \ dav_day_via_server(session, http_prefix, argb.nickname, argb.domain, argb.port, argb.debug, argb.year, argb.month, argb.day, argb.password) else: result = \ dav_month_via_server(session, http_prefix, argb.nickname, argb.domain, argb.port, argb.debug, argb.year, argb.month, argb.password) if result: print(str(result)) sys.exit() if argb.announce: if not argb.nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending announce/repeat of ' + argb.announce) send_announce_via_server(base_dir, session, argb.nickname, argb.password, domain, port, http_prefix, argb.announce, cached_webfingers, person_cache, True, __version__, signing_priv_key_pem, system_language) for _ in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.box: if not domain: print('Specify a domain with the --domain option') sys.exit() if not argb.nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) proxy_type = None if argb.tor or domain.endswith('.onion'): proxy_type = 'tor' if domain.endswith('.onion'): argb.port = 80 elif argb.i2p or domain.endswith('.i2p'): proxy_type = 'i2p' if domain.endswith('.i2p'): argb.port = 80 elif argb.gnunet: proxy_type = 'gnunet' if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) session = create_session(proxy_type) box_json = c2s_box_json(session, argb.nickname, argb.password, domain, port, http_prefix, argb.box, argb.pageNumber, argb.debug, signing_priv_key_pem) if box_json: pprint(box_json) else: print('Box not found: ' + argb.box) sys.exit() if argb.itemName: if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) if not argb.nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.summary: print('Specify a description for your shared item ' + 'with the --summary option') sys.exit() if not argb.itemQty: print('Specify a quantity of shared items with the ' + '--itemQty option') sys.exit() if not argb.itemType: print('Specify a type of shared item with the --itemType option') sys.exit() if not argb.itemCategory: print('Specify a category of shared item ' + 'with the --itemCategory option') sys.exit() if not argb.location: print('Specify a location or city where the shared ' + 'item resides with the --location option') sys.exit() if not argb.duration: print('Specify a duration to share the object ' + 'with the --duration option') sys.exit() session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending shared item: ' + argb.itemName) send_share_via_server(base_dir, session, argb.nickname, argb.password, domain, port, http_prefix, argb.itemName, argb.summary, argb.itemImage, argb.itemQty, argb.itemType, argb.itemCategory, argb.location, argb.duration, cached_webfingers, person_cache, debug, __version__, argb.itemPrice, argb.itemCurrency, signing_priv_key_pem, system_language) for _ in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.undoItemName: if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) if not argb.nickname: print('Specify a nickname with the --nickname option') sys.exit() session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending undo of shared item: ' + argb.undoItemName) send_undo_share_via_server(base_dir, session, argb.nickname, argb.password, domain, port, http_prefix, argb.undoItemName, cached_webfingers, person_cache, debug, __version__, signing_priv_key_pem, system_language) for _ in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.wantedItemName: if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) if not argb.nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.summary: print('Specify a description for your shared item ' + 'with the --summary option') sys.exit() if not argb.itemQty: print('Specify a quantity of shared items with the ' + '--itemQty option') sys.exit() if not argb.itemType: print('Specify a type of shared item with the --itemType option') sys.exit() if not argb.itemCategory: print('Specify a category of shared item ' + 'with the --itemCategory option') sys.exit() if not argb.location: print('Specify a location or city where the wanted ' + 'item resides with the --location option') sys.exit() if not argb.duration: print('Specify a duration to share the object ' + 'with the --duration option') sys.exit() session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending wanted item: ' + argb.wantedItemName) send_wanted_via_server(base_dir, session, argb.nickname, argb.password, domain, port, http_prefix, argb.wantedItemName, argb.summary, argb.itemImage, argb.itemQty, argb.itemType, argb.itemCategory, argb.location, argb.duration, cached_webfingers, person_cache, debug, __version__, argb.itemPrice, argb.itemCurrency, signing_priv_key_pem, system_language) for _ in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.undoWantedItemName: if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) if not argb.nickname: print('Specify a nickname with the --nickname option') sys.exit() session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending undo of wanted item: ' + argb.undoWantedItemName) send_undo_wanted_via_server(base_dir, session, argb.nickname, argb.password, domain, port, http_prefix, argb.undoWantedItemName, cached_webfingers, person_cache, debug, __version__, signing_priv_key_pem, system_language) for _ in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.like: if not argb.nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending like of ' + argb.like) send_like_via_server(base_dir, session, argb.nickname, argb.password, domain, port, http_prefix, argb.like, cached_webfingers, person_cache, True, __version__, signing_priv_key_pem, system_language) for _ in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.react: if not argb.nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.emoji: print('Specify a reaction emoji with the --emoji option') sys.exit() if not valid_emoji_content(argb.emoji): print('This is not a valid emoji') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending emoji reaction ' + argb.emoji + ' to ' + argb.react) send_reaction_via_server(base_dir, session, argb.nickname, argb.password, domain, port, http_prefix, argb.react, argb.emoji, cached_webfingers, person_cache, True, __version__, signing_priv_key_pem, system_language) for _ in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.undolike: if not argb.nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending undo like of ' + argb.undolike) send_undo_like_via_server(base_dir, session, argb.nickname, argb.password, domain, port, http_prefix, argb.undolike, cached_webfingers, person_cache, True, __version__, signing_priv_key_pem, system_language) for _ in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.undoreact: if not argb.nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.emoji: print('Specify a reaction emoji with the --emoji option') sys.exit() if not valid_emoji_content(argb.emoji): print('This is not a valid emoji') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending undo emoji reaction ' + argb.emoji + ' to ' + argb.react) send_undo_reaction_via_server(base_dir, session, argb.nickname, argb.password, domain, port, http_prefix, argb.undoreact, argb.emoji, cached_webfingers, person_cache, True, __version__, signing_priv_key_pem, system_language) for _ in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.bookmark: if not argb.nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending bookmark of ' + argb.bookmark) send_bookmark_via_server(base_dir, session, argb.nickname, argb.password, domain, port, http_prefix, argb.bookmark, cached_webfingers, person_cache, True, __version__, signing_priv_key_pem, system_language) for _ in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.unbookmark: if not argb.nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending undo bookmark of ' + argb.unbookmark) send_undo_bookmark_via_server(base_dir, session, argb.nickname, argb.password, domain, port, http_prefix, argb.unbookmark, cached_webfingers, person_cache, True, __version__, signing_priv_key_pem, system_language) for _ in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.delete: if not argb.nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending delete request of ' + argb.delete) send_delete_via_server(base_dir, session, argb.nickname, argb.password, domain, port, http_prefix, argb.delete, cached_webfingers, person_cache, True, __version__, signing_priv_key_pem, system_language) for _ in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.follow: # follow via c2s protocol if '.' not in argb.follow: print("This doesn't look like a fediverse handle") sys.exit() if not argb.nickname: print('Please specify the nickname for the account ' + 'with --nickname') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) if argb.follow.startswith('@'): argb.follow = argb.follow[1:] follow_nickname = get_nickname_from_actor(argb.follow) if not follow_nickname: print('Unable to find nickname in ' + argb.follow) sys.exit() follow_domain, follow_port = get_domain_from_actor(argb.follow) session = create_session(proxy_type) person_cache = {} cached_webfingers = {} follow_http_prefix = http_prefix if argb.follow.startswith('https'): follow_http_prefix = 'https' if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language send_follow_request_via_server(base_dir, session, argb.nickname, argb.password, domain, port, follow_nickname, follow_domain, follow_port, follow_http_prefix, cached_webfingers, person_cache, debug, __version__, signing_priv_key_pem, system_language) for _ in range(20): time.sleep(1) # TODO some method to know if it worked print('Ok') sys.exit() if argb.unfollow: # unfollow via c2s protocol if '.' not in argb.follow: print("This doesn't look like a fediverse handle") sys.exit() if not argb.nickname: print('Please specify the nickname for the account ' + 'with --nickname') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) if argb.unfollow.startswith('@'): argb.unfollow = argb.unfollow[1:] follow_nickname = get_nickname_from_actor(argb.unfollow) if not follow_nickname: print('WARN: unable to find nickname in ' + argb.unfollow) sys.exit() follow_domain, follow_port = get_domain_from_actor(argb.unfollow) session = create_session(proxy_type) person_cache = {} cached_webfingers = {} follow_http_prefix = http_prefix if argb.follow.startswith('https'): follow_http_prefix = 'https' if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language send_unfollow_request_via_server(base_dir, session, argb.nickname, argb.password, domain, port, follow_nickname, follow_domain, follow_port, follow_http_prefix, cached_webfingers, person_cache, debug, __version__, signing_priv_key_pem, system_language) for _ in range(20): time.sleep(1) # TODO some method to know if it worked print('Ok') sys.exit() if argb.followingList: # following list via c2s protocol if not argb.nickname: print('Please specify the nickname for the account ' + 'with --nickname') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) session = create_session(proxy_type) person_cache = {} cached_webfingers = {} follow_http_prefix = http_prefix if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) following_json = \ get_following_via_server(session, argb.nickname, argb.password, domain, port, follow_http_prefix, argb.pageNumber, debug, __version__, signing_priv_key_pem) if following_json: pprint(following_json) sys.exit() if argb.blocked: # blocked collection if not argb.nickname: print('Please specify the nickname for the account ' + 'with --nickname') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) session = create_session(proxy_type) person_cache = {} cached_webfingers = {} blocked_http_prefix = http_prefix if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) blocked_json = \ get_blocks_via_server(session, argb.nickname, argb.password, domain, port, blocked_http_prefix, argb.pageNumber, debug, __version__, signing_priv_key_pem) if blocked_json: pprint(blocked_json) sys.exit() if argb.followersList: # following list via c2s protocol if not argb.nickname: print('Please specify the nickname for the account ' + 'with --nickname') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) session = create_session(proxy_type) person_cache = {} cached_webfingers = {} follow_http_prefix = http_prefix if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) followers_json = \ get_followers_via_server(session, argb.nickname, argb.password, domain, port, follow_http_prefix, argb.pageNumber, debug, __version__, signing_priv_key_pem) if followers_json: pprint(followers_json) sys.exit() if argb.followRequestsList: # follow requests list via c2s protocol if not argb.nickname: print('Please specify the nickname for the account ' + 'with --nickname') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) session = create_session(proxy_type) person_cache = {} cached_webfingers = {} follow_http_prefix = http_prefix if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) follow_requests_json = \ get_follow_requests_via_server(session, argb.nickname, argb.password, domain, port, follow_http_prefix, argb.pageNumber, debug, __version__, signing_priv_key_pem) if follow_requests_json: pprint(follow_requests_json) sys.exit() nickname = 'admin' if argb.domain: domain = argb.domain set_config_param(base_dir, 'domain', domain) if argb.port: port = argb.port set_config_param(base_dir, 'port', port) if argb.proxy_port: proxy_port = argb.proxy_port set_config_param(base_dir, 'proxyPort', proxy_port) if argb.gnunet: http_prefix = 'gnunet' if argb.dat or argb.hyper: http_prefix = 'hyper' if argb.ipfs: http_prefix = 'ipfs' if argb.ipns: http_prefix = 'ipns' if argb.i2p: http_prefix = 'http' if argb.migrations: cached_webfingers = {} if argb.http or domain.endswith('.onion'): http_prefix = 'http' port = 80 proxy_type = 'tor' elif domain.endswith('.i2p'): http_prefix = 'http' port = 80 proxy_type = 'i2p' elif argb.ipfs: http_prefix = 'ipfs' port = 80 proxy_type = 'ipfs' elif argb.ipns: http_prefix = 'ipns' port = 80 proxy_type = 'ipfs' elif argb.gnunet: http_prefix = 'gnunet' port = 80 proxy_type = 'gnunet' else: http_prefix = 'https' port = 443 session = create_session(proxy_type) if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) block_federated = [] ctr = migrate_accounts(base_dir, session, http_prefix, cached_webfingers, True, signing_priv_key_pem, block_federated) if ctr == 0: print('No followed accounts have moved') else: print(str(ctr) + ' followed accounts were migrated') sys.exit() if argb.actor: if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = get_instance_actor_key(base_dir, domain) if debug: print('base_dir: ' + str(base_dir)) if signing_priv_key_pem: print('Obtained instance actor signing key') else: print('Did not obtain instance actor key for ' + domain) if argb.actor.startswith('@'): argb.actor = argb.actor[1:] get_actor_json(domain, argb.actor, argb.http, argb.gnunet, argb.ipfs, argb.ipns, debug, False, signing_priv_key_pem, None) sys.exit() if argb.followers: original_actor = argb.followers if '/@' in argb.followers or \ '/users/' in argb.followers or \ argb.followers.startswith('http') or \ argb.followers.startswith('ipfs') or \ argb.followers.startswith('ipns') or \ argb.followers.startswith('hyper'): # format: https://domain/@nick prefixes = get_protocol_prefixes() for prefix in prefixes: argb.followers = argb.followers.replace(prefix, '') argb.followers = argb.followers.replace('/@', '/users/') if not has_users_path(argb.followers): print('Expected actor format: ' + 'https://domain/@nick or https://domain/users/nick') sys.exit() if '/users/' in argb.followers: nickname = argb.followers.split('/users/')[1] nickname = remove_eol(nickname) domain = argb.followers.split('/users/')[0] elif '/profile/' in argb.followers: nickname = argb.followers.split('/profile/')[1] nickname = remove_eol(nickname) domain = argb.followers.split('/profile/')[0] elif '/author/' in argb.followers: nickname = argb.followers.split('/author/')[1] nickname = remove_eol(nickname) domain = argb.followers.split('/author/')[0] elif '/channel/' in argb.followers: nickname = argb.followers.split('/channel/')[1] nickname = remove_eol(nickname) domain = argb.followers.split('/channel/')[0] elif '/accounts/' in argb.followers: nickname = argb.followers.split('/accounts/')[1] nickname = remove_eol(nickname) domain = argb.followers.split('/accounts/')[0] elif '/u/' in argb.followers: nickname = argb.followers.split('/u/')[1] nickname = remove_eol(nickname) domain = argb.followers.split('/u/')[0] elif '/fediverse/blog/' in argb.followers: nickname = argb.followers.split('/fediverse/blog/')[1] nickname = remove_eol(nickname) domain = argb.followers.split('/fediverse/blog/')[0] elif '/c/' in argb.followers: nickname = argb.followers.split('/c/')[1] nickname = remove_eol(nickname) elif '/m/' in argb.followers: nickname = argb.followers.split('/m/')[1] nickname = remove_eol(nickname) domain = argb.followers.split('/m/')[0] else: # format: @nick@domain if '@' not in argb.followers: print('Syntax: --actor nickname@domain') sys.exit() if argb.followers.startswith('@'): argb.followers = argb.followers[1:] if '@' not in argb.followers: print('Syntax: --actor nickname@domain') sys.exit() nickname = argb.followers.split('@')[0] domain = argb.followers.split('@')[1] domain = remove_eol(domain) cached_webfingers = {} if argb.http or domain.endswith('.onion'): http_prefix = 'http' port = 80 proxy_type = 'tor' elif domain.endswith('.i2p'): http_prefix = 'http' port = 80 proxy_type = 'i2p' elif argb.gnunet: http_prefix = 'gnunet' port = 80 proxy_type = 'gnunet' elif argb.ipfs: http_prefix = 'ipfs' port = 80 proxy_type = 'ipfs' elif argb.ipns: http_prefix = 'ipns' port = 80 proxy_type = 'ipfs' else: http_prefix = 'https' port = 443 session = create_session(proxy_type) if nickname == 'inbox': nickname = domain host_domain = None if argb.domain: host_domain = argb.domain handle = nickname + '@' + domain signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) wf_request = webfinger_handle(session, handle, http_prefix, cached_webfingers, host_domain, __version__, debug, False, signing_priv_key_pem) if not wf_request: print('Unable to webfinger ' + handle) sys.exit() if not isinstance(wf_request, dict): print('Webfinger for ' + handle + ' did not return a dict. ' + str(wf_request)) sys.exit() person_url = None if wf_request.get('errors'): print('wf_request error: ' + str(wf_request['errors'])) if has_users_path(argb.followers): person_url = original_actor else: sys.exit() profile_str = 'https://www.w3.org/ns/activitystreams' accept_str = \ 'application/activity+json; profile="' + profile_str + '"' as_header = { 'Accept': accept_str } if not person_url: person_url = get_user_url(wf_request, 0, argb.debug) if nickname == domain: person_url = person_url.replace('/users/', '/actor/') person_url = person_url.replace('/accounts/', '/actor/') person_url = person_url.replace('/channel/', '/actor/') person_url = person_url.replace('/profile/', '/actor/') person_url = person_url.replace('/author/', '/actor/') person_url = person_url.replace('/u/', '/actor/') person_url = person_url.replace('/fediverse/blog/', '/actor/') person_url = person_url.replace('/c/', '/actor/') person_url = person_url.replace('/m/', '/actor/') if not person_url: # try single user instance person_url = http_prefix + '://' + domain profile_str = 'https://www.w3.org/ns/activitystreams' as_header = { 'Accept': 'application/ld+json; profile="' + profile_str + '"' } if '/channel/' in person_url or '/accounts/' in person_url: profile_str = 'https://www.w3.org/ns/activitystreams' as_header = { 'Accept': 'application/ld+json; profile="' + profile_str + '"' } signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) followers_list = \ download_follow_collection(signing_priv_key_pem, 'followers', session, http_prefix, person_url, 1, 3, argb.debug) if followers_list: for actor in followers_list: print(actor) sys.exit() if argb.addaccount: if '@' in argb.addaccount: nickname = argb.addaccount.split('@')[0] domain = argb.addaccount.split('@')[1] else: nickname = argb.addaccount if not argb.domain or not get_config_param(base_dir, 'domain'): print('Use the --domain option to set the domain name') sys.exit() configured_domain = get_config_param(base_dir, 'domain') if configured_domain: if domain != configured_domain: print('The account domain is expected to be ' + configured_domain) sys.exit() if not valid_nickname(domain, nickname): print(nickname + ' is a reserved name. Use something different.') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) if len(argb.password.strip()) < 8: print('Password should be at least 8 characters') sys.exit() account_dir = acct_dir(base_dir, nickname, domain) if os.path.isdir(account_dir): print('Account already exists') sys.exit() if os.path.isdir(base_dir + '/deactivated/' + nickname + '@' + domain): print('Account is deactivated') sys.exit() if domain.endswith('.onion') or \ domain.endswith('.i2p'): port = 80 http_prefix = 'http' if domain.endswith('.ipfs'): port = 80 http_prefix = 'ipfs' if domain.endswith('.ipns'): port = 80 http_prefix = 'ipns' create_person(base_dir, nickname, domain, port, http_prefix, True, not argb.noapproval, argb.password.strip()) if os.path.isdir(account_dir): print('Account created for ' + nickname + '@' + domain) else: print('Account creation failed') sys.exit() if argb.addgroup: if '@' in argb.addgroup: nickname = argb.addgroup.split('@')[0] domain = argb.addgroup.split('@')[1] else: nickname = argb.addgroup if not argb.domain or not get_config_param(base_dir, 'domain'): print('Use the --domain option to set the domain name') sys.exit() if nickname.startswith('!'): # remove preceding group indicator nickname = nickname[1:] if not valid_nickname(domain, nickname): print(nickname + ' is a reserved name. Use something different.') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) if len(argb.password.strip()) < 8: print('Password should be at least 8 characters') sys.exit() account_dir = acct_dir(base_dir, nickname, domain) if os.path.isdir(account_dir): print('Group already exists') sys.exit() create_group(base_dir, nickname, domain, port, http_prefix, True, argb.password.strip()) if os.path.isdir(account_dir): print('Group created for ' + nickname + '@' + domain) else: print('Group creation failed') sys.exit() if argb.rmgroup: argb.rmaccount = argb.rmgroup if argb.deactivate: argb.rmaccount = argb.deactivate if argb.rmaccount: admin_domain = get_config_param(base_dir, 'domain') admin_nickname = get_config_param(base_dir, 'admin') if admin_nickname and admin_domain: if admin_nickname + '@' + admin_domain == argb.rmaccount: print(argb.rmaccount + ' is the admin account') sys.exit() if '@' in argb.rmaccount: nickname = argb.rmaccount.split('@')[0] domain = argb.rmaccount.split('@')[1] else: nickname = argb.rmaccount if not argb.domain or not get_config_param(base_dir, 'domain'): print('Use the --domain option to set the domain name') sys.exit() if argb.domain: domain = argb.domain else: domain = get_config_param(base_dir, 'domain') configured_domain = get_config_param(base_dir, 'domain') if configured_domain: if domain != configured_domain: print('The account domain is expected to be ' + configured_domain) sys.exit() if argb.deactivate: if deactivate_account(base_dir, nickname, domain): print('Account for ' + nickname + '@' + domain + ' was deactivated') else: print('Account for ' + nickname + '@' + domain + ' was not found') sys.exit() if remove_account(base_dir, nickname, domain, port): if not argb.rmgroup: print('Account for ' + nickname + '@' + domain + ' was removed') else: print('Group ' + nickname + '@' + domain + ' was removed') print('Account for ' + nickname + '@' + domain + ' not removed') sys.exit() if argb.activate: if '@' in argb.activate: nickname = argb.activate.split('@')[0] domain = argb.activate.split('@')[1] else: nickname = argb.activate if not argb.domain or not get_config_param(base_dir, 'domain'): print('Use the --domain option to set the domain name') sys.exit() if activate_account2(base_dir, nickname, domain): print('Account for ' + nickname + '@' + domain + ' was activated') else: print('Deactivated account for ' + nickname + '@' + domain + ' was not found') sys.exit() if argb.changepassword: if len(argb.changepassword) != 2: print('--changepassword [nickname] [new password]') sys.exit() if '@' in argb.changepassword[0]: nickname = argb.changepassword[0].split('@')[0] domain = argb.changepassword[0].split('@')[1] else: nickname = argb.changepassword[0] if not argb.domain or not get_config_param(base_dir, 'domain'): print('Use the --domain option to set the domain name') sys.exit() new_password = argb.changepassword[1] if len(new_password) < 8: print('Password should be at least 8 characters') sys.exit() account_dir = acct_dir(base_dir, nickname, domain) if not os.path.isdir(account_dir): print('Account ' + nickname + '@' + domain + ' not found') sys.exit() password_file = base_dir + '/accounts/passwords' if os.path.isfile(password_file): if text_in_file(nickname + ':', password_file): store_basic_credentials(base_dir, nickname, new_password) print('Password for ' + nickname + ' was changed') else: print(nickname + ' is not in the passwords file') else: print('Passwords file not found') sys.exit() if argb.archive: if argb.archive.lower().endswith('null') or \ argb.archive.lower().endswith('delete') or \ argb.archive.lower().endswith('none'): argb.archive = None print('Archiving with deletion of old posts...') else: print('Archiving to ' + argb.archive + '...') # archiving is for non-instance posts archive_media(base_dir, argb.archive, argb.archiveWeeks) archive_posts(base_dir, http_prefix, argb.archive, {}, argb.archiveMaxPosts, argb.maxCacheAgeDays) print('Archiving complete') # expiry is for instance posts, where an expiry period # has been set within profile settings expired_count = expire_posts(base_dir, http_prefix, {}, argb.debug) if expired_count > 0: print(str(expired_count) + ' posts expired') sys.exit() if not argb.domain and not domain: print('Specify a domain with --domain [name]') sys.exit() if argb.avatar: if not os.path.isfile(argb.avatar): print(argb.avatar + ' is not an image filename') sys.exit() if not argb.nickname: print('Specify a nickname with --nickname [name]') sys.exit() city = 'London, England' if set_profile_image(base_dir, http_prefix, argb.nickname, domain, port, argb.avatar, 'avatar', '128x128', city, argb.content_license_url): print('Avatar added for ' + argb.nickname) else: print('Avatar was not added for ' + argb.nickname) sys.exit() if argb.backgroundImage: if not os.path.isfile(argb.backgroundImage): print(argb.backgroundImage + ' is not an image filename') sys.exit() if not argb.nickname: print('Specify a nickname with --nickname [name]') sys.exit() city = 'London, England' if set_profile_image(base_dir, http_prefix, argb.nickname, domain, port, argb.backgroundImage, 'background', '256x256', city, argb.content_license_url): print('Background image added for ' + argb.nickname) else: print('Background image was not added for ' + argb.nickname) sys.exit() if argb.skill: if not nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) if not argb.skillLevelPercent: print('Specify a skill level in the range 0-100') sys.exit() if int(argb.skillLevelPercent) < 0 or \ int(argb.skillLevelPercent) > 100: print('Skill level should be a percentage in the range 0-100') sys.exit() session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending ' + argb.skill + ' skill level ' + str(argb.skillLevelPercent) + ' for ' + nickname) send_skill_via_server(base_dir, session, nickname, argb.password, domain, port, http_prefix, argb.skill, argb.skillLevelPercent, cached_webfingers, person_cache, True, __version__, signing_priv_key_pem, system_language) for i in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.availability: if not nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending availability status of ' + nickname + ' as ' + argb.availability) send_availability_via_server(base_dir, session, nickname, argb.password, domain, port, http_prefix, argb.availability, cached_webfingers, person_cache, True, __version__, signing_priv_key_pem, system_language) for i in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.desktop: # Announce posts as they arrive in your inbox using text-to-speech if argb.desktop.startswith('@'): argb.desktop = argb.desktop[1:] if '@' not in argb.desktop: print('Specify the handle to notify: nickname@domain') sys.exit() nickname = argb.desktop.split('@')[0] domain = argb.desktop.split('@')[1] if not nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) proxy_type = None if argb.tor or domain.endswith('.onion'): proxy_type = 'tor' if domain.endswith('.onion'): argb.port = 80 elif argb.i2p or domain.endswith('.i2p'): proxy_type = 'i2p' if domain.endswith('.i2p'): argb.port = 80 elif argb.gnunet: proxy_type = 'gnunet' # only store inbox posts if we are not running as a daemon store_inbox_posts = not argb.noKeyPress run_desktop_client(base_dir, proxy_type, http_prefix, nickname, domain, port, argb.password, argb.screenreader, argb.language, argb.notificationSounds, argb.notificationType, argb.noKeyPress, store_inbox_posts, argb.notifyShowNewPosts, argb.language, argb.debug, argb.low_bandwidth) sys.exit() if federation_list: print('Federating with: ' + str(federation_list)) if argb.shared_items_federated_domains: print('Federating shared items with: ' + argb.shared_items_federated_domains) shared_items_federated_domains = [] if argb.shared_items_federated_domains: fed_domains_str = argb.shared_items_federated_domains set_config_param(base_dir, 'sharedItemsFederatedDomains', fed_domains_str) else: fed_domains_str = \ get_config_param(base_dir, 'sharedItemsFederatedDomains') if fed_domains_str: fed_domains_list = fed_domains_str.split(',') for shared_federated_domain in fed_domains_list: federated_domain = shared_federated_domain.strip() shared_items_federated_domains.append(federated_domain) if argb.block: if not nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) if '@' in argb.block: blocked_domain = argb.block.split('@')[1] blocked_domain = remove_eol(blocked_domain) blocked_nickname = argb.block.split('@')[0] blocked_actor = http_prefix + '://' + blocked_domain + \ '/users/' + blocked_nickname argb.block = blocked_actor else: if '/users/' not in argb.block: print(argb.block + ' does not look like an actor url') sys.exit() session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending block of ' + argb.block) send_block_via_server(base_dir, session, nickname, argb.password, domain, port, http_prefix, argb.block, cached_webfingers, person_cache, True, __version__, signing_priv_key_pem, system_language) for i in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.mute: if not nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending mute of ' + argb.mute) send_mute_via_server(base_dir, session, nickname, argb.password, domain, port, http_prefix, argb.mute, cached_webfingers, person_cache, True, __version__, signing_priv_key_pem, system_language) for i in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.unmute: if not nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending undo mute of ' + argb.unmute) send_undo_mute_via_server(base_dir, session, nickname, argb.password, domain, port, http_prefix, argb.unmute, cached_webfingers, person_cache, True, __version__, signing_priv_key_pem, system_language) for i in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.unblock: if not nickname: print('Specify a nickname with the --nickname option') sys.exit() if not argb.password: argb.password = getpass.getpass('Password: ') if not argb.password: print('Specify a password with the --password option') sys.exit() argb.password = remove_eol(argb.password) if '@' in argb.unblock: blocked_domain = argb.unblock.split('@')[1] blocked_domain = remove_eol(blocked_domain) blocked_nickname = argb.unblock.split('@')[0] blocked_actor = http_prefix + '://' + blocked_domain + \ '/users/' + blocked_nickname argb.unblock = blocked_actor else: if '/users/' not in argb.unblock: print(argb.unblock + ' does not look like an actor url') sys.exit() session = create_session(proxy_type) person_cache = {} cached_webfingers = {} if not domain: domain = get_config_param(base_dir, 'domain') signing_priv_key_pem = None if argb.secure_mode: signing_priv_key_pem = get_instance_actor_key(base_dir, domain) system_language = argb.language print('Sending undo block of ' + argb.unblock) send_undo_block_via_server(base_dir, session, nickname, argb.password, domain, port, http_prefix, argb.unblock, cached_webfingers, person_cache, True, __version__, signing_priv_key_pem, system_language) for i in range(10): # TODO detect send success/fail time.sleep(1) sys.exit() if argb.filterStr: if not argb.nickname: print('Please specify a nickname') sys.exit() if add_filter(base_dir, argb.nickname, domain, argb.filterStr): print('Filter added to ' + argb.nickname + ': ' + argb.filterStr) sys.exit() if argb.unfilterStr: if not argb.nickname: print('Please specify a nickname') sys.exit() if remove_filter(base_dir, argb.nickname, domain, argb.unfilterStr): print('Filter removed from ' + argb.nickname + ': ' + argb.unfilterStr) sys.exit() if argb.testdata: argb.language = 'en' city = 'London, England' nickname = 'testuser567' password = 'boringpassword' print('Generating some test data for user: ' + nickname) if os.path.isdir(base_dir + '/tags'): shutil.rmtree(base_dir + '/tags', ignore_errors=False, onerror=None) if os.path.isdir(base_dir + '/accounts'): shutil.rmtree(base_dir + '/accounts', ignore_errors=False, onerror=None) if os.path.isdir(base_dir + '/keys'): shutil.rmtree(base_dir + '/keys', ignore_errors=False, onerror=None) if os.path.isdir(base_dir + '/media'): shutil.rmtree(base_dir + '/media', ignore_errors=False, onerror=None) if os.path.isdir(base_dir + '/sharefiles'): shutil.rmtree(base_dir + '/sharefiles', ignore_errors=False, onerror=None) if os.path.isdir(base_dir + '/wfendpoints'): shutil.rmtree(base_dir + '/wfendpoints', ignore_errors=False, onerror=None) set_config_param(base_dir, 'registrationsRemaining', str(max_registrations)) create_person(base_dir, 'maxboardroom', domain, port, http_prefix, True, False, password) create_person(base_dir, 'ultrapancake', domain, port, http_prefix, True, False, password) create_person(base_dir, 'drokk', domain, port, http_prefix, True, False, password) create_person(base_dir, 'sausagedog', domain, port, http_prefix, True, False, password) create_person(base_dir, nickname, domain, port, http_prefix, True, False, 'likewhateveryouwantscoob') set_skill_level(base_dir, nickname, domain, 'testing', 60) set_skill_level(base_dir, nickname, domain, 'typing', 50) set_role(base_dir, nickname, domain, 'admin') set_availability(base_dir, nickname, domain, 'busy') block_federated = [] add_share(base_dir, http_prefix, nickname, domain, port, "spanner", "It's a spanner", "img/shares1.png", 1, "tool", "mechanical", "City", "0", "GBP", "2 months", debug, city, argb.language, {}, 'shares', argb.low_bandwidth, argb.content_license_url, False, block_federated) add_share(base_dir, http_prefix, nickname, domain, port, "witch hat", "Spooky", "img/shares2.png", 1, "hat", "clothing", "City", "0", "GBP", "3 months", debug, city, argb.language, {}, 'shares', argb.low_bandwidth, argb.content_license_url, False, block_federated) delete_all_posts(base_dir, nickname, domain, 'inbox') delete_all_posts(base_dir, nickname, domain, 'outbox') test_save_to_file = True test_c2s = False test_comments_enabled = True test_attach_image_filename = None test_media_type = None test_image_description = None test_city = 'London, England' test_in_reply_to = None test_in_reply_to_atom_uri = None test_subject = None test_schedule_post = False test_event_date = None test_event_time = None test_event_end_time = None test_location = None test_is_article = False conversation_id = None low_bandwidth = False languages_understood = [argb.language] translate = {} buy_url = '' chat_url = '' auto_cw_cache = {} test_video_transcript = '' create_public_post(base_dir, nickname, domain, port, http_prefix, "like this is totally just a #test man", test_save_to_file, test_c2s, test_comments_enabled, test_attach_image_filename, test_media_type, test_image_description, test_video_transcript, test_city, test_in_reply_to, test_in_reply_to_atom_uri, test_subject, test_schedule_post, test_event_date, test_event_time, test_event_end_time, test_location, test_is_article, argb.language, conversation_id, low_bandwidth, argb.content_license_url, argb.media_license_url, argb.media_creator, languages_understood, translate, buy_url, chat_url, auto_cw_cache) create_public_post(base_dir, nickname, domain, port, http_prefix, "Zoiks!!!", test_save_to_file, test_c2s, test_comments_enabled, test_attach_image_filename, test_media_type, test_image_description, test_video_transcript, test_city, test_in_reply_to, test_in_reply_to_atom_uri, test_subject, test_schedule_post, test_event_date, test_event_time, test_event_end_time, test_location, test_is_article, argb.language, conversation_id, low_bandwidth, argb.content_license_url, argb.media_license_url, argb.media_creator, languages_understood, translate, buy_url, chat_url, auto_cw_cache) create_public_post(base_dir, nickname, domain, port, http_prefix, "Hey scoob we need like a hundred more #milkshakes", test_save_to_file, test_c2s, test_comments_enabled, test_attach_image_filename, test_media_type, test_image_description, test_video_transcript, test_city, test_in_reply_to, test_in_reply_to_atom_uri, test_subject, test_schedule_post, test_event_date, test_event_time, test_event_end_time, test_location, test_is_article, argb.language, conversation_id, low_bandwidth, argb.content_license_url, argb.media_license_url, argb.media_creator, languages_understood, translate, buy_url, chat_url, auto_cw_cache) create_public_post(base_dir, nickname, domain, port, http_prefix, "Getting kinda spooky around here", test_save_to_file, test_c2s, test_comments_enabled, test_attach_image_filename, test_media_type, test_image_description, test_video_transcript, test_city, 'someone', test_in_reply_to_atom_uri, test_subject, test_schedule_post, test_event_date, test_event_time, test_event_end_time, test_location, test_is_article, argb.language, conversation_id, low_bandwidth, argb.content_license_url, argb.media_license_url, argb.media_creator, languages_understood, translate, buy_url, chat_url, auto_cw_cache) create_public_post(base_dir, nickname, domain, port, http_prefix, "And they would have gotten away with it too" + "if it wasn't for those pesky hackers", test_save_to_file, test_c2s, test_comments_enabled, 'img/logo.png', 'image/png', 'Description of image', test_video_transcript, test_city, test_in_reply_to, test_in_reply_to_atom_uri, test_subject, test_schedule_post, test_event_date, test_event_time, test_event_end_time, test_location, test_is_article, argb.language, conversation_id, low_bandwidth, argb.content_license_url, argb.media_license_url, argb.media_creator, languages_understood, translate, buy_url, chat_url, auto_cw_cache) create_public_post(base_dir, nickname, domain, port, http_prefix, "man these centralized sites are like the worst!", test_save_to_file, test_c2s, test_comments_enabled, test_attach_image_filename, test_media_type, test_image_description, test_video_transcript, test_city, test_in_reply_to, test_in_reply_to_atom_uri, test_subject, test_schedule_post, test_event_date, test_event_time, test_event_end_time, test_location, test_is_article, argb.language, conversation_id, low_bandwidth, argb.content_license_url, argb.media_license_url, argb.media_creator, languages_understood, translate, buy_url, chat_url, auto_cw_cache) create_public_post(base_dir, nickname, domain, port, http_prefix, "another mystery solved #test", test_save_to_file, test_c2s, test_comments_enabled, test_attach_image_filename, test_media_type, test_image_description, test_video_transcript, test_city, test_in_reply_to, test_in_reply_to_atom_uri, test_subject, test_schedule_post, test_event_date, test_event_time, test_event_end_time, test_location, test_is_article, argb.language, conversation_id, low_bandwidth, argb.content_license_url, argb.media_license_url, argb.media_creator, languages_understood, translate, buy_url, chat_url, auto_cw_cache) create_public_post(base_dir, nickname, domain, port, http_prefix, "let's go bowling", test_save_to_file, test_c2s, test_comments_enabled, test_attach_image_filename, test_media_type, test_image_description, test_video_transcript, test_city, test_in_reply_to, test_in_reply_to_atom_uri, test_subject, test_schedule_post, test_event_date, test_event_time, test_event_end_time, test_location, test_is_article, argb.language, conversation_id, low_bandwidth, argb.content_license_url, argb.media_license_url, argb.media_creator, languages_understood, translate, buy_url, chat_url, auto_cw_cache) domain_full = domain + ':' + str(port) clear_follows(base_dir, nickname, domain, 'following.txt') follow_person(base_dir, nickname, domain, 'maxboardroom', domain_full, federation_list, False, False, 'following.txt') follow_person(base_dir, nickname, domain, 'ultrapancake', domain_full, federation_list, False, False, 'following.txt') follow_person(base_dir, nickname, domain, 'sausagedog', domain_full, federation_list, False, False, 'following.txt') follow_person(base_dir, nickname, domain, 'drokk', domain_full, federation_list, False, False, 'following.txt') add_follower_of_person(base_dir, nickname, domain, 'drokk', domain_full, federation_list, False, False) add_follower_of_person(base_dir, nickname, domain, 'maxboardroom', domain_full, federation_list, False, False) set_config_param(base_dir, 'admin', nickname) # set a lower bound to the maximum mentions # so that it can't be accidentally set to zero and disable replies argb.max_mentions = max(argb.max_mentions, 4) registration = get_config_param(base_dir, 'registration') if not registration: registration = False map_format = get_config_param(base_dir, 'mapFormat') if map_format: argb.mapFormat = map_format else: set_config_param(base_dir, 'mapFormat', argb.mapFormat) minimumvotes = get_config_param(base_dir, 'minvotes') if minimumvotes: argb.minimumvotes = int(minimumvotes) no_of_books = get_config_param(base_dir, 'noOfBooks') if no_of_books: argb.no_of_books = int(no_of_books) content_license_url = '' if argb.content_license_url: content_license_url = argb.content_license_url set_config_param(base_dir, 'contentLicenseUrl', content_license_url) else: content_license_url = get_config_param(base_dir, 'contentLicenseUrl') votingtime = get_config_param(base_dir, 'votingtime') if votingtime: argb.votingtime = votingtime # only show the date at the bottom of posts dateonly = get_config_param(base_dir, 'dateonly') if dateonly: argb.dateonly = dateonly # set the maximum number of newswire posts per account or rss feed max_newswire_posts_per_source = \ get_config_param(base_dir, 'maxNewswirePostsPerSource') if max_newswire_posts_per_source: argb.max_newswire_posts_per_source = \ int(max_newswire_posts_per_source) # set the maximum number of newswire posts appearing in the right column max_newswire_posts = \ get_config_param(base_dir, 'maxNewswirePosts') if max_newswire_posts: argb.max_newswire_posts = int(max_newswire_posts) # set the maximum size of a newswire rss/atom feed in Kilobytes max_newswire_feed_size_kb = \ get_config_param(base_dir, 'maxNewswireFeedSizeKb') if max_newswire_feed_size_kb: argb.max_newswire_feed_size_kb = int(max_newswire_feed_size_kb) max_mirrored_articles = \ get_config_param(base_dir, 'maxMirroredArticles') if max_mirrored_articles is not None: argb.max_mirrored_articles = int(max_mirrored_articles) max_news_posts = \ get_config_param(base_dir, 'maxNewsPosts') if max_news_posts is not None: argb.max_news_posts = int(max_news_posts) max_followers = \ get_config_param(base_dir, 'maxFollowers') if max_followers is not None: argb.max_followers = int(max_followers) max_feed_item_size_kb = \ get_config_param(base_dir, 'maxFeedItemSizeKb') if max_feed_item_size_kb is not None: argb.max_feed_item_size_kb = int(max_feed_item_size_kb) dormant_months = \ get_config_param(base_dir, 'dormantMonths') if dormant_months is not None: argb.dormant_months = int(dormant_months) send_threads_timeout_mins = \ get_config_param(base_dir, 'sendThreadsTimeoutMins') if send_threads_timeout_mins is not None: argb.send_threads_timeout_mins = int(send_threads_timeout_mins) max_like_count = \ get_config_param(base_dir, 'maxLikeCount') if max_like_count is not None: argb.max_like_count = int(max_like_count) show_publish_as_icon = \ get_config_param(base_dir, 'showPublishAsIcon') if show_publish_as_icon is not None: argb.show_publish_as_icon = bool(show_publish_as_icon) icons_as_buttons = \ get_config_param(base_dir, 'iconsAsButtons') if icons_as_buttons is not None: argb.icons_as_buttons = bool(icons_as_buttons) rss_icon_at_top = \ get_config_param(base_dir, 'rssIconAtTop') if rss_icon_at_top is not None: argb.rss_icon_at_top = bool(rss_icon_at_top) publish_button_at_top = \ get_config_param(base_dir, 'publishButtonAtTop') if publish_button_at_top is not None: argb.publish_button_at_top = bool(publish_button_at_top) full_width_tl_button_header = \ get_config_param(base_dir, 'fullWidthTlButtonHeader') if full_width_tl_button_header is not None: argb.full_width_tl_button_header = bool(full_width_tl_button_header) allow_local_network_access = \ get_config_param(base_dir, 'allowLocalNetworkAccess') if allow_local_network_access is not None: argb.allow_local_network_access = bool(allow_local_network_access) verify_all_signatures = \ get_config_param(base_dir, 'verifyAllSignatures') if verify_all_signatures is not None: argb.verify_all_signatures = bool(verify_all_signatures) broch_mode = get_config_param(base_dir, 'brochMode') if broch_mode is not None: argb.broch_mode = bool(broch_mode) dyslexic_font = get_config_param(base_dir, 'dyslexicFont') if dyslexic_font is not None: argb.dyslexic_font = bool(dyslexic_font) log_login_failures = \ get_config_param(base_dir, 'logLoginFailures') if log_login_failures is not None: argb.log_login_failures = bool(log_login_failures) show_node_info_accounts = \ get_config_param(base_dir, 'showNodeInfoAccounts') if show_node_info_accounts is not None: argb.show_node_info_accounts = bool(show_node_info_accounts) show_node_info_version = \ get_config_param(base_dir, 'showNodeInfoVersion') if show_node_info_version is not None: argb.show_node_info_version = bool(show_node_info_version) low_bandwidth = \ get_config_param(base_dir, 'lowBandwidth') if low_bandwidth is not None: argb.low_bandwidth = bool(low_bandwidth) user_agents_blocked = [] if argb.userAgentBlocks: user_agents_blocked_str = argb.userAgentBlocks set_config_param(base_dir, 'userAgentsBlocked', user_agents_blocked_str) else: user_agents_blocked_str = \ get_config_param(base_dir, 'userAgentsBlocked') if user_agents_blocked_str: agent_blocks_list = user_agents_blocked_str.split(',') for user_agents_blocked_str2 in agent_blocks_list: user_agents_blocked.append(user_agents_blocked_str2.strip()) crawlers_allowed = [] if argb.crawlersAllowed: crawlers_allowed_str = argb.crawlersAllowed set_config_param(base_dir, 'crawlersAllowed', crawlers_allowed_str) else: crawlers_allowed_str = \ get_config_param(base_dir, 'crawlersAllowed') if crawlers_allowed_str: crawlers_allowed_list = crawlers_allowed_str.split(',') for crawlers_allowed_str2 in crawlers_allowed_list: crawlers_allowed.append(crawlers_allowed_str2.strip()) lists_enabled = '' if argb.lists_enabled: lists_enabled = argb.lists_enabled set_config_param(base_dir, 'listsEnabled', lists_enabled) else: lists_enabled = get_config_param(base_dir, 'listsEnabled') city = \ get_config_param(base_dir, 'city') if city is not None: argb.city = city yt_domain = get_config_param(base_dir, 'youtubedomain') if yt_domain: if '://' in yt_domain: yt_domain = yt_domain.split('://')[1] if '/' in yt_domain: yt_domain = yt_domain.split('/')[0] if '.' in yt_domain: argb.yt_replace_domain = yt_domain twitter_domain = get_config_param(base_dir, 'twitterdomain') if twitter_domain: if '://' in twitter_domain: twitter_domain = twitter_domain.split('://')[1] if '/' in twitter_domain: twitter_domain = twitter_domain.split('/')[0] if '.' in twitter_domain: argb.twitter_replacement_domain = twitter_domain if set_theme(base_dir, theme_name, domain, argb.allow_local_network_access, argb.language, argb.dyslexic_font, False): print('Theme set to ' + theme_name) # whether new registrations are open or closed if argb.registration: if argb.registration.lower() == 'open': registration = get_config_param(base_dir, 'registration') if not registration: set_config_param(base_dir, 'registrationsRemaining', str(max_registrations)) else: if registration != 'open': set_config_param(base_dir, 'registrationsRemaining', str(max_registrations)) set_config_param(base_dir, 'registration', 'open') print('New registrations open') else: set_config_param(base_dir, 'registration', 'closed') print('New registrations closed') default_currency = get_config_param(base_dir, 'defaultCurrency') if not default_currency: set_config_param(base_dir, 'defaultCurrency', 'EUR') if argb.defaultCurrency: if argb.defaultCurrency == argb.defaultCurrency.upper(): set_config_param(base_dir, 'defaultCurrency', argb.defaultCurrency) print('Default currency set to ' + argb.defaultCurrency) opt['preferred_podcast_formats'] = preferred_podcast_formats opt['crawlers_allowed'] = crawlers_allowed opt['content_license_url'] = content_license_url opt['lists_enabled'] = lists_enabled opt['shared_items_federated_domains'] = shared_items_federated_domains opt['user_agents_blocked'] = user_agents_blocked opt['registration'] = registration opt['instance_id'] = instance_id opt['base_dir'] = base_dir opt['domain'] = domain opt['onion_domain'] = onion_domain opt['i2p_domain'] = i2p_domain opt['port'] = port opt['proxy_port'] = proxy_port opt['http_prefix'] = http_prefix opt['federation_list'] = federation_list opt['proxy_type'] = proxy_type opt['debug'] = debug return argb, opt if __name__ == "__main__": argb2, opt2 = _command_options() print('allowdeletion: ' + str(argb2.allowdeletion)) run_daemon(argb2.no_of_books, argb2.public_replies_unlisted, argb2.max_shares_on_profile, argb2.max_hashtags, argb2.mapFormat, argb2.clacks, opt2['preferred_podcast_formats'], argb2.check_actor_timeout, opt2['crawlers_allowed'], argb2.dyslexic_font, opt2['content_license_url'], opt2['lists_enabled'], argb2.default_reply_interval_hrs, argb2.low_bandwidth, argb2.max_like_count, opt2['shared_items_federated_domains'], opt2['user_agents_blocked'], argb2.log_login_failures, argb2.city, argb2.show_node_info_accounts, argb2.show_node_info_version, argb2.broch_mode, argb2.verify_all_signatures, argb2.send_threads_timeout_mins, argb2.dormant_months, argb2.max_newswire_posts, argb2.allow_local_network_access, argb2.max_feed_item_size_kb, argb2.publish_button_at_top, argb2.rss_icon_at_top, argb2.icons_as_buttons, argb2.full_width_tl_button_header, argb2.show_publish_as_icon, argb2.max_followers, argb2.max_news_posts, argb2.max_mirrored_articles, argb2.max_newswire_feed_size_kb, argb2.max_newswire_posts_per_source, argb2.dateonly, argb2.votingtime, argb2.positivevoting, argb2.minimumvotes, argb2.newsinstance, argb2.blogsinstance, argb2.mediainstance, argb2.max_recent_posts, not argb2.nosharedinbox, opt2['registration'], argb2.language, __version__, opt2['instance_id'], argb2.client, opt2['base_dir'], opt2['domain'], opt2['onion_domain'], opt2['i2p_domain'], argb2.yt_replace_domain, argb2.twitter_replacement_domain, opt2['port'], opt2['proxy_port'], opt2['http_prefix'], opt2['federation_list'], argb2.max_mentions, argb2.max_emoji, argb2.secure_mode, opt2['proxy_type'], argb2.max_replies, argb2.domain_max_posts_per_day, argb2.account_max_posts_per_day, argb2.allowdeletion, opt2['debug'], False, argb2.instance_only_skills_search, [], not argb2.noapproval)