availability.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. __filename__ = "availability.py"
  2. __author__ = "Bob Mottram"
  3. __license__ = "AGPL3+"
  4. __version__ = "1.0.0"
  5. __maintainer__ = "Bob Mottram"
  6. __email__ = "bob@freedombone.net"
  7. __status__ = "Production"
  8. import json
  9. import commentjson
  10. import os
  11. from webfinger import webfingerHandle
  12. from auth import createBasicAuthHeader
  13. from posts import getPersonBox
  14. from session import postJson
  15. from utils import getNicknameFromActor
  16. from utils import getDomainFromActor
  17. def setAvailability(baseDir: str,nickname: str,domain: str, \
  18. status: str) -> bool:
  19. """Set an availability status
  20. """
  21. # avoid giant strings
  22. if len(status)>128:
  23. return False
  24. actorFilename=baseDir+'/accounts/'+nickname+'@'+domain+'.json'
  25. if not os.path.isfile(actorFilename):
  26. return False
  27. with open(actorFilename, 'r') as fp:
  28. actorJson=commentjson.load(fp)
  29. actorJson['availability']=status
  30. with open(actorFilename, 'w') as fp:
  31. commentjson.dump(actorJson, fp, indent=4, sort_keys=False)
  32. return True
  33. def getAvailability(baseDir: str,nickname: str,domain: str) -> str:
  34. """Returns the availability for a given person
  35. """
  36. actorFilename=baseDir+'/accounts/'+nickname+'@'+domain+'.json'
  37. if not os.path.isfile(actorFilename):
  38. return False
  39. with open(actorFilename, 'r') as fp:
  40. actorJson=commentjson.load(fp)
  41. if not actorJson.get('availability'):
  42. return None
  43. return actorJson['availability']
  44. return None
  45. def outboxAvailability(baseDir: str,nickname: str,messageJson: {}, \
  46. debug: bool) -> bool:
  47. """Handles receiving an availability update
  48. """
  49. if not messageJson.get('type'):
  50. return False
  51. if not messageJson['type']=='Availability':
  52. return False
  53. if not messageJson.get('actor'):
  54. return False
  55. if not messageJson.get('object'):
  56. return False
  57. if not isinstance(messageJson['object'], str):
  58. return False
  59. actorNickname=getNicknameFromActor(messageJson['actor'])
  60. if actorNickname!=nickname:
  61. return False
  62. domain,port=getDomainFromActor(messageJson['actor'])
  63. status=messageJson['object'].replace('"','')
  64. return setAvailability(baseDir,nickname,domain,status)
  65. def sendAvailabilityViaServer(baseDir: str,session, \
  66. nickname: str,password: str, \
  67. domain: str,port: int, \
  68. httpPrefix: str, \
  69. status: str, \
  70. cachedWebfingers: {},personCache: {}, \
  71. debug: bool,projectVersion: str) -> {}:
  72. """Sets the availability for a person via c2s
  73. """
  74. if not session:
  75. print('WARN: No session for sendAvailabilityViaServer')
  76. return 6
  77. domainFull=domain
  78. if port:
  79. if port!=80 and port!=443:
  80. if ':' not in domain:
  81. domainFull=domain+':'+str(port)
  82. toUrl = httpPrefix+'://'+domainFull+'/users/'+nickname
  83. ccUrl = httpPrefix+'://'+domainFull+'/users/'+nickname+'/followers'
  84. newAvailabilityJson = {
  85. 'type': 'Availability',
  86. 'actor': httpPrefix+'://'+domainFull+'/users/'+nickname,
  87. 'object': '"'+status+'"',
  88. 'to': [toUrl],
  89. 'cc': [ccUrl]
  90. }
  91. handle=httpPrefix+'://'+domainFull+'/@'+nickname
  92. # lookup the inbox for the To handle
  93. wfRequest = webfingerHandle(session,handle,httpPrefix,cachedWebfingers, \
  94. domain,projectVersion)
  95. if not wfRequest:
  96. if debug:
  97. print('DEBUG: announce webfinger failed for '+handle)
  98. return 1
  99. postToBox='outbox'
  100. # get the actor inbox for the To handle
  101. inboxUrl,pubKeyId,pubKey,fromPersonId,sharedInbox,capabilityAcquisition,avatarUrl,displayName = \
  102. getPersonBox(baseDir,session,wfRequest,personCache, \
  103. projectVersion,httpPrefix,domain,postToBox)
  104. if not inboxUrl:
  105. if debug:
  106. print('DEBUG: No '+postToBox+' was found for '+handle)
  107. return 3
  108. if not fromPersonId:
  109. if debug:
  110. print('DEBUG: No actor was found for '+handle)
  111. return 4
  112. authHeader=createBasicAuthHeader(Nickname,password)
  113. headers = {'host': domain, \
  114. 'Content-type': 'application/json', \
  115. 'Authorization': authHeader}
  116. postResult = \
  117. postJson(session,newAvailabilityJson,[],inboxUrl,headers,"inbox:write")
  118. #if not postResult:
  119. # if debug:
  120. # print('DEBUG: POST announce failed for c2s to '+inboxUrl)
  121. # return 5
  122. if debug:
  123. print('DEBUG: c2s POST availability success')
  124. return newAvailabilityJson