2023-06-24 00:23:53 +00:00
from fediseer . apis . v1 . base import *
from fediseer . messaging import activitypub_pm
from fediseer . classes . user import User , Claim
2023-09-13 22:26:03 +00:00
from fediseer import enums
2023-06-22 13:40:28 +00:00
class Whitelist ( Resource ) :
get_parser = reqparse . RequestParser ( )
get_parser . add_argument ( " Client-Agent " , default = " unknown:0:unknown " , type = str , required = False , help = " The client name and version. " , location = " headers " )
get_parser . add_argument ( " endorsements " , required = False , default = 0 , type = int , help = " Limit to this amount of endorsements of more " , location = " args " )
get_parser . add_argument ( " guarantors " , required = False , default = 1 , type = int , help = " Limit to this amount of guarantors of more " , location = " args " )
get_parser . add_argument ( " csv " , required = False , type = bool , help = " Set to true to return just the domains as a csv. Mutually exclusive with domains " , location = " args " )
2023-09-13 22:26:03 +00:00
get_parser . add_argument ( " domains " , required = False , type = str , help = " Set to true to return just the domains as a list. Mutually exclusive with csv " , location = " args " )
2023-06-22 13:40:28 +00:00
@api.expect ( get_parser )
@cache.cached ( timeout = 10 , query_string = True )
@api.marshal_with ( models . response_model_model_Whitelist_get , code = 200 , description = ' Instances ' , skip_none = True )
def get ( self ) :
''' A List with the details of all instances and their endorsements
'''
self . args = self . get_parser . parse_args ( )
instance_details = [ ]
for instance in database . get_all_instances ( self . args . endorsements , self . args . guarantors ) :
instance_details . append ( instance . get_details ( ) )
if self . args . csv :
return { " csv " : " , " . join ( [ instance [ " domain " ] for instance in instance_details ] ) } , 200
if self . args . domains :
return { " domains " : [ instance [ " domain " ] for instance in instance_details ] } , 200
return { " instances " : instance_details } , 200
class WhitelistDomain ( Resource ) :
get_parser = reqparse . RequestParser ( )
get_parser . add_argument ( " Client-Agent " , default = " unknown:0:unknown " , type = str , required = False , help = " The client name and version. " , location = " headers " )
@api.expect ( get_parser )
@cache.cached ( timeout = 10 , query_string = True )
@api.marshal_with ( models . response_model_instances , code = 200 , description = ' Instances ' )
def get ( self , domain ) :
''' Display info about a specific instance
'''
self . args = self . get_parser . parse_args ( )
2023-06-24 12:56:09 +00:00
instance , nodeinfo , admin_usernames = ensure_instance_registered ( domain )
2023-06-22 13:40:28 +00:00
if not instance :
2023-06-24 00:23:53 +00:00
raise e . NotFound ( f " Something went wrong trying to register this instance. " )
2023-06-22 13:40:28 +00:00
return instance . get_details ( ) , 200
put_parser = reqparse . RequestParser ( )
put_parser . add_argument ( " Client-Agent " , default = " unknown:0:unknown " , type = str , required = False , help = " The client name and version. " , location = " headers " )
2023-06-24 01:14:20 +00:00
put_parser . add_argument ( " admin " , required = True , type = str , help = " The username of the admin who wants to register this domain " , location = " json " )
2023-06-24 01:15:23 +00:00
put_parser . add_argument ( " guarantor " , required = False , type = str , help = " (Optional) The domain of the guaranteeing instance. They will receive a PM to validate you " , location = " json " )
2023-09-13 22:26:03 +00:00
put_parser . add_argument ( " pm_proxy " , required = False , default = False , type = str , help = " (Optional) If you do receive the PM from @fediseer@fediseer.com, set this to true to make the Fediseer PM your your API key via @fediseer@botsin.space. For this to work, ensure that botsin.space is not blocked in your instance and optimally follow @fediseer@botsin.space as well. If set, this will be used permanently for communication to your instance. " , location = " json " )
2023-06-22 13:40:28 +00:00
2023-09-13 22:26:03 +00:00
@api.expect ( put_parser , models . input_instance_claim , validate = True )
2023-06-22 13:40:28 +00:00
@api.marshal_with ( models . response_model_instances , code = 200 , description = ' Instances ' )
@api.response ( 400 , ' Bad Request ' , models . response_model_error )
def put ( self , domain ) :
2023-06-24 01:13:06 +00:00
''' Claim an fediverse instance.
If the instance hasn ' t been recorded yet it will be polled and added.
You must specify an admin account which will recieve the new API key via Private Message .
2023-06-22 13:40:28 +00:00
'''
self . args = self . put_parser . parse_args ( )
2023-06-24 00:23:53 +00:00
if ' @ ' in self . args . admin :
raise e . BadRequest ( " Please send the username without any @ signs or domains " )
2023-06-24 12:56:09 +00:00
instance , nodeinfo , admin_usernames = ensure_instance_registered ( domain )
2023-06-22 14:36:53 +00:00
guarantor_instance = None
if self . args . guarantor :
guarantor_instance = database . find_instance_by_domain ( self . args . guarantor )
if not guarantor_instance :
2023-06-24 11:49:18 +00:00
raise e . BadRequest ( f " Requested guarantor domain { self . args . guarantor } is not registered with the Fediseer yet! " )
2023-06-24 00:23:53 +00:00
if self . args . admin not in admin_usernames :
2023-06-24 13:08:06 +00:00
if len ( admin_usernames ) == 0 :
raise e . Unauthorized ( f " We have not implemented admin lookup and messaging for this fediverse software at this point, so this instance cannot be claimed. Please consider sending a PR to add this functionality. " )
else :
raise e . Forbidden ( f " Only admins of that { instance . software } are allowed to claim it. " )
2023-06-24 00:23:53 +00:00
existing_claim = database . find_claim ( f " @ { self . args . admin } @ { domain } " )
if existing_claim :
raise e . Forbidden ( f " You have already claimed this instance as this admin. Please use the PATCH method to reset your API key. " )
2023-09-13 22:26:03 +00:00
if self . args . pm_proxy is not None :
proxy = enums . PMProxy [ self . args . pm_proxy ]
if instance . pm_proxy != proxy :
instance . pm_proxy = proxy
api_key = activitypub_pm . pm_new_api_key (
domain = domain ,
username = self . args . admin ,
software = instance . software ,
proxy = instance . pm_proxy ,
)
2023-06-22 13:40:28 +00:00
if not api_key :
raise e . BadRequest ( " Failed to generate API Key " )
2023-06-24 00:23:53 +00:00
new_user = User (
2023-06-22 13:40:28 +00:00
api_key = hash_api_key ( api_key ) ,
2023-06-24 00:23:53 +00:00
account = f " @ { self . args . admin } @ { domain } " ,
username = self . args . admin ,
2023-06-22 13:40:28 +00:00
)
2023-06-24 00:23:53 +00:00
db . session . add ( new_user )
db . session . commit ( )
new_claim = Claim (
user_id = new_user . id ,
instance_id = instance . id ,
)
db . session . add ( new_claim )
db . session . commit ( )
2023-06-22 14:36:53 +00:00
if guarantor_instance :
2023-09-13 22:26:03 +00:00
try :
activitypub_pm . pm_admins (
message = f " New instance { domain } was just registered with the Fediseer and have asked you to guarantee for them! " ,
domain = guarantor_instance . domain ,
software = guarantor_instance . software ,
instance = guarantor_instance ,
)
except :
pass
2023-06-24 00:23:53 +00:00
return instance . get_details ( ) , 200
2023-06-22 13:40:28 +00:00
patch_parser = reqparse . RequestParser ( )
patch_parser . add_argument ( " apikey " , type = str , required = True , help = " The sending instance ' s API key. " , location = ' headers ' )
patch_parser . add_argument ( " Client-Agent " , default = " unknown:0:unknown " , type = str , required = False , help = " The client name and version. " , location = " headers " )
2023-09-05 09:22:52 +00:00
patch_parser . add_argument ( " admin_username " , required = False , type = str , help = " If a username is given, their API key will be reset. Otherwise the user ' s whose API key was provided will be reset. This allows can be initiated by other instance admins or the fediseer. " , location = " json " )
2023-09-10 16:43:08 +00:00
patch_parser . add_argument ( " return_new_key " , default = False , required = False , type = bool , help = " If True, the key will be returned as part of the response instead of PM ' d. IT will still PM a notification to you. " , location = " json " )
patch_parser . add_argument ( " sysadmins " , default = None , required = False , type = int , help = " How many sysadmins this instance has. " , location = " json " )
patch_parser . add_argument ( " moderators " , default = None , required = False , type = int , help = " How many moderators this instance has. " , location = " json " )
2023-09-13 22:26:03 +00:00
patch_parser . add_argument ( " pm_proxy " , required = False , default = False , type = str , help = " (Optional) If you do receive the PM from @fediseer@fediseer.com, set this to true to make the Fediseer PM your your API key via @fediseer@botsin.space. For this to work, ensure that botsin.space is not blocked in your instance and optimally follow @fediseer@botsin.space as well. If set, this will be used permanently for communication to your instance. " , location = " json " )
2023-06-22 13:40:28 +00:00
2023-09-05 09:40:58 +00:00
@api.expect ( patch_parser , models . input_api_key_reset , validate = True )
2023-09-05 09:32:36 +00:00
@api.marshal_with ( models . response_model_api_key_reset , code = 200 , description = ' Instances ' , skip_none = True )
2023-06-22 13:40:28 +00:00
@api.response ( 401 , ' Invalid API Key ' , models . response_model_error )
@api.response ( 403 , ' Instance Not Registered ' , models . response_model_error )
def patch ( self , domain ) :
''' Regenerate API key for instance
'''
self . args = self . patch_parser . parse_args ( )
if not self . args . apikey :
2023-06-24 00:23:53 +00:00
raise e . Unauthorized ( " You must provide the API key that was PM ' d admin account " )
user = database . find_user_by_api_key ( self . args . apikey )
if not user :
raise e . Forbidden ( " You have not yet claimed an instance. Use the POST method to do so. " )
instance = database . find_instance_by_user ( user )
2023-09-05 09:29:40 +00:00
requestor_instance = instance
2023-09-10 16:43:08 +00:00
changed = False
new_key = None
if self . args . sysadmins is not None and instance . sysadmins != self . args . sysadmins :
instance . sysadmins = self . args . sysadmins
changed = True
if self . args . moderators is not None and instance . moderators != self . args . moderators :
instance . moderators = self . args . moderators
changed = True
2023-09-13 22:26:03 +00:00
if self . args . pm_proxy is not None :
logger . debug ( self . args . pm_proxy )
proxy = enums . PMProxy [ self . args . pm_proxy ]
if instance . pm_proxy != proxy :
activitypub_pm . pm_new_proxy_switch ( proxy , instance . pm_proxy , instance , user . username )
instance . pm_proxy = proxy
changed = True
2023-09-05 09:22:52 +00:00
if self . args . admin_username :
2023-06-24 00:23:53 +00:00
requestor = None
2023-09-05 09:22:52 +00:00
if self . args . admin_username != user . username or user . username == " fediseer " :
2023-06-24 00:23:53 +00:00
requestor = user . username
2023-09-05 09:22:52 +00:00
instance_to_reset = database . find_instance_by_account ( f " @ { self . args . admin_username } @ { domain } " )
if instance_to_reset is None :
raise e . NotFound ( f " No Instance found matching provided domain. Have you remembered to register it? " )
2023-06-24 00:23:53 +00:00
if instance != instance_to_reset and user . username != " fediseer " :
2023-08-09 14:20:10 +00:00
raise e . BadRequest ( " Only other admins of the same instance or the fediseer can request API key reset for others. " )
2023-09-05 09:29:40 +00:00
2023-06-24 00:23:53 +00:00
instance = instance_to_reset
2023-09-05 09:22:52 +00:00
user = database . find_user_by_account ( f " @ { self . args . admin_username } @ { domain } " )
if self . args . return_new_key :
if requestor is None :
2023-09-05 09:29:40 +00:00
requestor = f " { user . username } @ { requestor_instance . domain } "
2023-09-13 22:26:03 +00:00
new_key = activitypub_pm . pm_new_key_notification (
domain = domain ,
username = self . args . admin_username ,
software = instance . software ,
requestor = requestor ,
proxy = instance . pm_proxy ,
)
2023-09-05 09:22:52 +00:00
else :
2023-09-13 22:26:03 +00:00
new_key = activitypub_pm . pm_new_api_key (
domain = domain ,
username = self . args . admin_username ,
software = instance . software ,
requestor = requestor ,
proxy = instance . pm_proxy ,
)
2023-06-24 00:23:53 +00:00
user . api_key = hash_api_key ( new_key )
2023-09-10 16:43:08 +00:00
changed = True
db . session . commit ( )
if changed is True :
if self . args . return_new_key and new_key is True :
2023-09-05 09:29:40 +00:00
return { " message " : " Changed " , " new_key " : new_key } , 200
else :
return { " message " : " Changed " } , 200
2023-09-10 16:43:08 +00:00
else :
return { " message " : " OK " } , 200
2023-06-22 13:40:28 +00:00
delete_parser = reqparse . RequestParser ( )
delete_parser . add_argument ( " apikey " , type = str , required = True , help = " The sending instance ' s API key. " , location = ' headers ' )
delete_parser . add_argument ( " Client-Agent " , default = " unknown:0:unknown " , type = str , required = False , help = " The client name and version. " , location = " headers " )
2023-06-24 00:23:53 +00:00
delete_parser . add_argument ( " username " , required = False , type = str , help = " (Not Implemented) Provide the username of another admin to remove their API key " , location = " json " )
2023-06-22 13:40:28 +00:00
@api.expect ( delete_parser )
@api.marshal_with ( models . response_model_simple_response , code = 200 , description = ' Instances ' , skip_none = True )
@api.response ( 400 , ' Bad Request ' , models . response_model_error )
@api.response ( 401 , ' Invalid API Key ' , models . response_model_error )
@api.response ( 403 , ' Forbidden ' , models . response_model_error )
def delete ( self , domain ) :
2023-06-24 01:13:06 +00:00
''' Delete claim to instance (Not implemented)
2023-06-22 13:40:28 +00:00
'''
2023-06-24 00:23:53 +00:00
return e . BadRequest ( " Not implemented " )
2023-06-22 13:40:28 +00:00
self . args = self . patch_parser . parse_args ( )
if not self . args . apikey :
2023-06-24 00:23:53 +00:00
raise e . Unauthorized ( " You must provide the API key that was PM ' d to your account " )
2023-06-22 13:40:28 +00:00
instance = database . find_authenticated_instance ( domain , self . args . apikey )
if not instance :
raise e . BadRequest ( f " No Instance found matching provided API key and domain. Have you remembered to register it? " )
2023-06-24 00:23:53 +00:00
if domain == os . getenv ( ' FEDISEER_LEMMY_DOMAIN ' ) :
raise e . Forbidden ( " Cannot delete fediseer control instance " )
2023-06-22 13:40:28 +00:00
db . session . delete ( instance )
db . session . commit ( )
logger . warning ( f " { domain } deleted " )
return { " message " : ' Changed ' } , 200