acceptreject.py 8.1 KB

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