| 
									
										
										
										
											2019-07-19 11:38:37 +00:00
										 |  |  | __filename__ = "availability.py" | 
					
						
							|  |  |  | __author__ = "Bob Mottram" | 
					
						
							|  |  |  | __license__ = "AGPL3+" | 
					
						
							| 
									
										
										
										
											2019-08-29 13:35:29 +00:00
										 |  |  | __version__ = "1.0.0" | 
					
						
							| 
									
										
										
										
											2019-07-19 11:38:37 +00:00
										 |  |  | __maintainer__ = "Bob Mottram" | 
					
						
							|  |  |  | __email__ = "bob@freedombone.net" | 
					
						
							|  |  |  | __status__ = "Production" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import json | 
					
						
							|  |  |  | import commentjson | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | from webfinger import webfingerHandle | 
					
						
							|  |  |  | from auth import createBasicAuthHeader | 
					
						
							|  |  |  | from posts import getPersonBox | 
					
						
							|  |  |  | from session import postJson | 
					
						
							|  |  |  | from utils import getNicknameFromActor | 
					
						
							|  |  |  | from utils import getDomainFromActor | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def setAvailability(baseDir: str,nickname: str,domain: str, \ | 
					
						
							|  |  |  |                     status: str) -> bool: | 
					
						
							|  |  |  |     """Set an availability status
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     # avoid giant strings | 
					
						
							|  |  |  |     if len(status)>128: | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     actorFilename=baseDir+'/accounts/'+nickname+'@'+domain+'.json' | 
					
						
							|  |  |  |     if not os.path.isfile(actorFilename): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     with open(actorFilename, 'r') as fp: | 
					
						
							|  |  |  |         actorJson=commentjson.load(fp) | 
					
						
							|  |  |  |         actorJson['availability']=status | 
					
						
							|  |  |  |         with open(actorFilename, 'w') as fp: | 
					
						
							|  |  |  |             commentjson.dump(actorJson, fp, indent=4, sort_keys=False)     | 
					
						
							|  |  |  |     return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def getAvailability(baseDir: str,nickname: str,domain: str) -> str: | 
					
						
							|  |  |  |     """Returns the availability for a given person
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     actorFilename=baseDir+'/accounts/'+nickname+'@'+domain+'.json' | 
					
						
							|  |  |  |     if not os.path.isfile(actorFilename): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     with open(actorFilename, 'r') as fp: | 
					
						
							|  |  |  |         actorJson=commentjson.load(fp) | 
					
						
							|  |  |  |         if not actorJson.get('availability'): | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         return actorJson['availability'] | 
					
						
							|  |  |  |     return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def outboxAvailability(baseDir: str,nickname: str,messageJson: {},debug: bool) -> bool: | 
					
						
							|  |  |  |     """Handles receiving an availability update
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not messageJson.get('type'): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if not messageJson['type']=='Availability': | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if not messageJson.get('actor'): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if not messageJson.get('object'): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if not isinstance(messageJson['object'], str): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     actorNickname=getNicknameFromActor(messageJson['actor']) | 
					
						
							|  |  |  |     if actorNickname!=nickname: | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     domain,port=getDomainFromActor(messageJson['actor']) | 
					
						
							|  |  |  |     status=messageJson['object'].replace('"','') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return setAvailability(baseDir,nickname,domain,status) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-20 09:16:03 +00:00
										 |  |  | def sendAvailabilityViaServer(baseDir: str,session, \ | 
					
						
							|  |  |  |                               nickname: str,password: str, \ | 
					
						
							| 
									
										
										
										
											2019-07-19 11:38:37 +00:00
										 |  |  |                               domain: str,port: int, \ | 
					
						
							|  |  |  |                               httpPrefix: str, \ | 
					
						
							|  |  |  |                               status: str, \ | 
					
						
							|  |  |  |                               cachedWebfingers: {},personCache: {}, \ | 
					
						
							| 
									
										
										
										
											2019-08-14 20:12:27 +00:00
										 |  |  |                               debug: bool,projectVersion: str) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-19 11:38:37 +00:00
										 |  |  |     """Sets the availability for a person via c2s
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not session: | 
					
						
							|  |  |  |         print('WARN: No session for sendAvailabilityViaServer') | 
					
						
							|  |  |  |         return 6 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     domainFull=domain | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |     if port: | 
					
						
							|  |  |  |         if port!=80 and port!=443: | 
					
						
							|  |  |  |             if ':' not in domain: | 
					
						
							|  |  |  |                 domainFull=domain+':'+str(port) | 
					
						
							| 
									
										
										
										
											2019-07-19 11:38:37 +00:00
										 |  |  |          | 
					
						
							|  |  |  |     toUrl = httpPrefix+'://'+domainFull+'/users/'+nickname | 
					
						
							|  |  |  |     ccUrl = httpPrefix+'://'+domainFull+'/users/'+nickname+'/followers' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     newAvailabilityJson = { | 
					
						
							|  |  |  |         'type': 'Availability', | 
					
						
							|  |  |  |         'actor': httpPrefix+'://'+domainFull+'/users/'+nickname, | 
					
						
							|  |  |  |         'object': '"'+status+'"', | 
					
						
							|  |  |  |         'to': [toUrl], | 
					
						
							|  |  |  |         'cc': [ccUrl] | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     handle=httpPrefix+'://'+domainFull+'/@'+nickname | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # lookup the inbox for the To handle | 
					
						
							| 
									
										
										
										
											2019-08-14 20:12:27 +00:00
										 |  |  |     wfRequest = webfingerHandle(session,handle,httpPrefix,cachedWebfingers, \ | 
					
						
							|  |  |  |                                 domain,projectVersion) | 
					
						
							| 
									
										
										
										
											2019-07-19 11:38:37 +00:00
										 |  |  |     if not wfRequest: | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: announce webfinger failed for '+handle) | 
					
						
							|  |  |  |         return 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     postToBox='outbox' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # get the actor inbox for the To handle | 
					
						
							| 
									
										
										
										
											2019-08-22 18:36:07 +00:00
										 |  |  |     inboxUrl,pubKeyId,pubKey,fromPersonId,sharedInbox,capabilityAcquisition,avatarUrl,displayName = \ | 
					
						
							| 
									
										
										
										
											2019-08-20 09:16:03 +00:00
										 |  |  |         getPersonBox(baseDir,session,wfRequest,personCache, \ | 
					
						
							| 
									
										
										
										
											2019-08-14 20:12:27 +00:00
										 |  |  |                      projectVersion,httpPrefix,domain,postToBox) | 
					
						
							| 
									
										
										
										
											2019-07-19 11:38:37 +00:00
										 |  |  |                       | 
					
						
							|  |  |  |     if not inboxUrl: | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: No '+postToBox+' was found for '+handle) | 
					
						
							|  |  |  |         return 3 | 
					
						
							|  |  |  |     if not fromPersonId: | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: No actor was found for '+handle) | 
					
						
							|  |  |  |         return 4 | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     authHeader=createBasicAuthHeader(Nickname,password) | 
					
						
							|  |  |  |       | 
					
						
							|  |  |  |     headers = {'host': domain, \ | 
					
						
							|  |  |  |                'Content-type': 'application/json', \ | 
					
						
							|  |  |  |                'Authorization': authHeader} | 
					
						
							|  |  |  |     postResult = \ | 
					
						
							|  |  |  |         postJson(session,newAvailabilityJson,[],inboxUrl,headers,"inbox:write") | 
					
						
							|  |  |  |     #if not postResult: | 
					
						
							|  |  |  |     #    if debug: | 
					
						
							|  |  |  |     #        print('DEBUG: POST announce failed for c2s to '+inboxUrl) | 
					
						
							|  |  |  |     #    return 5 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: c2s POST availability success') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return newAvailabilityJson |