availability.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. __filename__ = "availability.py"
  2. __author__ = "Bob Mottram"
  3. __license__ = "AGPL3+"
  4. __version__ = "1.1.0"
  5. __maintainer__ = "Bob Mottram"
  6. __email__ = "bob@freedombone.net"
  7. __status__ = "Production"
  8. import os
  9. from webfinger import webfingerHandle
  10. from auth import createBasicAuthHeader
  11. from posts import getPersonBox
  12. from session import postJson
  13. from utils import getNicknameFromActor
  14. from utils import getDomainFromActor
  15. from utils import loadJson
  16. from utils import saveJson
  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. actorJson = loadJson(actorFilename)
  28. if actorJson:
  29. actorJson['availability'] = status
  30. saveJson(actorJson, actorFilename)
  31. return True
  32. def getAvailability(baseDir: str, nickname: str, domain: str) -> str:
  33. """Returns the availability for a given person
  34. """
  35. actorFilename = baseDir + '/accounts/' + nickname + '@' + domain + '.json'
  36. if not os.path.isfile(actorFilename):
  37. return False
  38. actorJson = loadJson(actorFilename)
  39. if actorJson:
  40. if not actorJson.get('availability'):
  41. return None
  42. return actorJson['availability']
  43. return None
  44. def outboxAvailability(baseDir: str, nickname: str, messageJson: {},
  45. debug: bool) -> bool:
  46. """Handles receiving an availability update
  47. """
  48. if not messageJson.get('type'):
  49. return False
  50. if not messageJson['type'] == 'Availability':
  51. return False
  52. if not messageJson.get('actor'):
  53. return False
  54. if not messageJson.get('object'):
  55. return False
  56. if not isinstance(messageJson['object'], str):
  57. return False
  58. actorNickname = getNicknameFromActor(messageJson['actor'])
  59. if actorNickname != nickname:
  60. return False
  61. domain, port = getDomainFromActor(messageJson['actor'])
  62. status = messageJson['object'].replace('"', '')
  63. return setAvailability(baseDir, nickname, domain, status)
  64. def sendAvailabilityViaServer(baseDir: str, session,
  65. nickname: str, password: str,
  66. domain: str, port: int,
  67. httpPrefix: str,
  68. status: str,
  69. cachedWebfingers: {}, personCache: {},
  70. debug: bool, projectVersion: str) -> {}:
  71. """Sets the availability for a person via c2s
  72. """
  73. if not session:
  74. print('WARN: No session for sendAvailabilityViaServer')
  75. return 6
  76. domainFull = domain
  77. if port:
  78. if port != 80 and port != 443:
  79. if ':' not in domain:
  80. domainFull = domain + ':' + str(port)
  81. toUrl = httpPrefix + '://' + domainFull + '/users/' + nickname
  82. ccUrl = httpPrefix + '://' + domainFull + '/users/' + nickname + \
  83. '/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,
  94. cachedWebfingers,
  95. domain, projectVersion)
  96. if not wfRequest:
  97. if debug:
  98. print('DEBUG: announce webfinger failed for ' + handle)
  99. return 1
  100. if not isinstance(wfRequest, dict):
  101. print('WARN: Webfinger for ' + handle + ' did not return a dict. ' +
  102. str(wfRequest))
  103. return 1
  104. postToBox = 'outbox'
  105. # get the actor inbox for the To handle
  106. (inboxUrl, pubKeyId, pubKey,
  107. fromPersonId, sharedInbox,
  108. capabilityAcquisition,
  109. avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
  110. personCache, projectVersion,
  111. httpPrefix, nickname,
  112. domain, postToBox)
  113. if not inboxUrl:
  114. if debug:
  115. print('DEBUG: No ' + postToBox + ' was found for ' + handle)
  116. return 3
  117. if not fromPersonId:
  118. if debug:
  119. print('DEBUG: No actor was found for ' + handle)
  120. return 4
  121. authHeader = createBasicAuthHeader(nickname, password)
  122. headers = {
  123. 'host': domain,
  124. 'Content-type': 'application/json',
  125. 'Authorization': authHeader
  126. }
  127. postResult = postJson(session, newAvailabilityJson, [],
  128. inboxUrl, headers, "inbox:write")
  129. if not postResult:
  130. print('WARN: failed to post availability')
  131. if debug:
  132. print('DEBUG: c2s POST availability success')
  133. return newAvailabilityJson