acceptreject.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. __filename__ = "acceptreject.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. from capabilities import capabilitiesAccept
  10. from capabilities import capabilitiesGrantedSave
  11. from utils import getStatusNumber
  12. from utils import createOutboxDir
  13. from utils import urlPermitted
  14. from utils import getDomainFromActor
  15. from utils import getNicknameFromActor
  16. from utils import domainPermitted
  17. from utils import followPerson
  18. def createAcceptReject(baseDir: str,federationList: [], \
  19. nickname: str,domain: str,port: int, \
  20. toUrl: str,ccUrl: str,httpPrefix: str, \
  21. objectJson: {},ocapJson,acceptType: str) -> {}:
  22. """Accepts or rejects something (eg. a follow request or offer)
  23. Typically toUrl will be https://www.w3.org/ns/activitystreams#Public
  24. and ccUrl might be a specific person favorited or repeated and
  25. the followers url objectUrl is typically the url of the message,
  26. corresponding to url or atomUri in createPostBase
  27. """
  28. if not objectJson.get('actor'):
  29. return None
  30. if not urlPermitted(objectJson['actor'],federationList,"inbox:write"):
  31. return None
  32. if port:
  33. if port!=80 and port!=443:
  34. if ':' not in domain:
  35. domain=domain+':'+str(port)
  36. newAccept = {
  37. "@context": "https://www.w3.org/ns/activitystreams",
  38. 'type': acceptType,
  39. 'actor': httpPrefix+'://'+domain+'/users/'+nickname,
  40. 'to': [toUrl],
  41. 'cc': [],
  42. 'object': objectJson
  43. }
  44. if ccUrl:
  45. if len(ccUrl)>0:
  46. newAccept['cc']=[ccUrl]
  47. # attach capabilities for follow accept
  48. if ocapJson:
  49. newAccept['capabilities']=ocapJson
  50. return newAccept
  51. def createAccept(baseDir: str,federationList: [], \
  52. nickname: str,domain: str,port: int, \
  53. toUrl: str,ccUrl: str,httpPrefix: str, \
  54. objectJson: {}, \
  55. acceptedCaps=["inbox:write","objects:read"]) -> {}:
  56. # create capabilities accept
  57. ocapNew= \
  58. capabilitiesAccept(baseDir,httpPrefix, \
  59. nickname,domain,port,toUrl,True,acceptedCaps)
  60. return createAcceptReject(baseDir,federationList, \
  61. nickname,domain,port, \
  62. toUrl,ccUrl,httpPrefix, \
  63. objectJson,ocapNew,'Accept')
  64. def createReject(baseDir: str,federationList: [], \
  65. nickname: str,domain: str,port: int, \
  66. toUrl: str,ccUrl: str,httpPrefix: str, \
  67. objectJson: {}) -> {}:
  68. return createAcceptReject(baseDir,federationList, \
  69. nickname,domain,port, \
  70. toUrl,ccUrl, \
  71. httpPrefix,objectJson,None,'Reject')
  72. def acceptFollow(baseDir: str,domain : str,messageJson: {}, \
  73. federationList: [],debug : bool) -> None:
  74. """Receiving a follow Accept activity
  75. """
  76. if not messageJson.get('object'):
  77. return
  78. if not messageJson['object'].get('type'):
  79. return
  80. if not messageJson['object']['type']=='Follow':
  81. return
  82. if debug:
  83. print('DEBUG: receiving Follow activity')
  84. if not messageJson['object'].get('actor'):
  85. print('DEBUG: no actor in Follow activity')
  86. return
  87. # no, this isn't a mistake
  88. if not messageJson['object'].get('object'):
  89. print('DEBUG: no object within Follow activity')
  90. return
  91. if not messageJson.get('to'):
  92. if debug:
  93. print('DEBUG: No "to" parameter in follow Accept')
  94. return
  95. if debug:
  96. print('DEBUG: follow Accept received')
  97. thisActor=messageJson['object']['actor']
  98. nickname=getNicknameFromActor(thisActor)
  99. if not nickname:
  100. print('WARN: no nickname found in '+thisActor)
  101. return
  102. acceptedDomain,acceptedPort=getDomainFromActor(thisActor)
  103. if not acceptedDomain:
  104. if debug:
  105. print('DEBUG: domain not found in '+thisActor)
  106. return
  107. if not nickname:
  108. if debug:
  109. print('DEBUG: nickname not found in '+thisActor)
  110. return
  111. if acceptedPort:
  112. if '/'+acceptedDomain+':'+str(acceptedPort)+'/users/'+nickname not in thisActor:
  113. if debug:
  114. print('Port: '+str(acceptedPort))
  115. print('Expected: /'+acceptedDomain+':'+str(acceptedPort)+ \
  116. '/users/'+nickname)
  117. print('Actual: '+thisActor)
  118. print('DEBUG: unrecognized actor '+thisActor)
  119. return
  120. else:
  121. if not '/'+acceptedDomain+'/users/'+nickname in thisActor:
  122. if debug:
  123. print('Expected: /'+acceptedDomain+'/users/'+nickname)
  124. print('Actual: '+thisActor)
  125. print('DEBUG: unrecognized actor '+thisActor)
  126. return
  127. followedActor=messageJson['object']['object']
  128. followedDomain,port=getDomainFromActor(followedActor)
  129. if not followedDomain:
  130. print('DEBUG: no domain found within Follow activity object '+followedActor)
  131. return
  132. followedDomainFull=followedDomain
  133. if port:
  134. followedDomainFull=followedDomain+':'+str(port)
  135. followedNickname=getNicknameFromActor(followedActor)
  136. if not followedNickname:
  137. print('DEBUG: no nickname found within Follow activity object '+followedActor)
  138. return
  139. acceptedDomainFull=acceptedDomain
  140. if acceptedPort:
  141. acceptedDomainFull=acceptedDomain+':'+str(acceptedPort)
  142. # are capabilities attached? If so then store them
  143. if messageJson.get('capabilities'):
  144. if isinstance(messageJson['capabilities'], dict):
  145. capabilitiesGrantedSave(baseDir, \
  146. nickname,acceptedDomainFull, \
  147. messageJson['capabilities'])
  148. if followPerson(baseDir, \
  149. nickname,acceptedDomainFull, \
  150. followedNickname,followedDomainFull, \
  151. federationList,debug):
  152. if debug:
  153. print('DEBUG: '+nickname+'@'+acceptedDomainFull+ \
  154. ' followed '+followedNickname+'@'+followedDomainFull)
  155. else:
  156. if debug:
  157. print('DEBUG: Unable to create follow - '+ \
  158. nickname+'@'+acceptedDomain+' -> '+ \
  159. followedNickname+'@'+followedDomain)
  160. def receiveAcceptReject(session,baseDir: str, \
  161. httpPrefix: str,domain :str,port: int, \
  162. sendThreads: [],postLog: [],cachedWebfingers: {}, \
  163. personCache: {},messageJson: {},federationList: [], \
  164. debug : bool) -> bool:
  165. """Receives an Accept or Reject within the POST section of HTTPServer
  166. """
  167. if messageJson['type']!='Accept' and messageJson['type']!='Reject':
  168. return False
  169. if not messageJson.get('actor'):
  170. if debug:
  171. print('DEBUG: '+messageJson['type']+' has no actor')
  172. return False
  173. if '/users/' not in messageJson['actor'] and \
  174. '/channel/' not in messageJson['actor'] and \
  175. '/profile/' not in messageJson['actor']:
  176. if debug:
  177. print('DEBUG: "users" or "profile" missing from actor in '+ \
  178. messageJson['type']+'. Assuming single user instance.')
  179. domain,tempPort=getDomainFromActor(messageJson['actor'])
  180. if not domainPermitted(domain,federationList):
  181. if debug:
  182. print('DEBUG: '+messageJson['type']+ \
  183. ' from domain not permitted - '+domain)
  184. return False
  185. nickname=getNicknameFromActor(messageJson['actor'])
  186. if not nickname:
  187. # single user instance
  188. nickname='dev'
  189. if debug:
  190. print('DEBUG: '+messageJson['type']+ \
  191. ' does not contain a nickname. Assuming single user instance.')
  192. handle=nickname.lower()+'@'+domain.lower()
  193. # receive follow accept
  194. acceptFollow(baseDir,domain,messageJson,federationList,debug)
  195. if debug:
  196. print('DEBUG: Uh, '+messageJson['type']+', I guess')
  197. return True