acceptreject.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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: {},acceptedCaps=["inbox:write","objects:read"]) -> {}:
  56. # create capabilities accept
  57. ocapNew=capabilitiesAccept(baseDir,httpPrefix,nickname,domain,port,toUrl,True,acceptedCaps)
  58. return createAcceptReject(baseDir,federationList, \
  59. nickname,domain,port, \
  60. toUrl,ccUrl,httpPrefix, \
  61. objectJson,ocapNew,'Accept')
  62. def createReject(baseDir: str,federationList: [], \
  63. nickname: str,domain: str,port: int, \
  64. toUrl: str,ccUrl: str,httpPrefix: str, \
  65. objectJson: {}) -> {}:
  66. return createAcceptReject(baseDir,federationList, \
  67. nickname,domain,port, \
  68. toUrl,ccUrl, \
  69. httpPrefix,objectJson,None,'Reject')
  70. def acceptFollow(baseDir: str,domain : str,messageJson: {}, \
  71. federationList: [],debug : bool) -> None:
  72. """Receiving a follow Accept activity
  73. """
  74. if not messageJson.get('object'):
  75. return
  76. if not messageJson['object'].get('type'):
  77. return
  78. if not messageJson['object'].get('actor'):
  79. return
  80. # no, this isn't a mistake
  81. if not messageJson['object'].get('object'):
  82. return
  83. if not messageJson['object']['type']=='Follow':
  84. return
  85. if not messageJson.get('to'):
  86. if debug:
  87. print('DEBUG: No "to" parameter in follow Accept')
  88. return
  89. #if len(messageJson['object']['to'])!=1:
  90. # if debug:
  91. # print('DEBUG: "to" does not contain a single recipient')
  92. # print(str(messageJson['object']['to']))
  93. # if messageJson['object'].get('object'):
  94. # if not isinstance(messageJson['object']['object'], str):
  95. # messageJson['object']['to']=messageJson['object']['object']
  96. # else:
  97. # return
  98. # else:
  99. # return
  100. if debug:
  101. print('DEBUG: follow Accept received')
  102. thisActor=messageJson['object']['actor']
  103. nickname=getNicknameFromActor(thisActor)
  104. if not nickname:
  105. print('WARN: no nickname found in '+thisActor)
  106. return
  107. acceptedDomain,acceptedPort=getDomainFromActor(thisActor)
  108. if not acceptedDomain:
  109. if debug:
  110. print('DEBUG: domain not found in '+thisActor)
  111. return
  112. #if acceptedDomain != domain:
  113. # if debug:
  114. # print('DEBUG: domain mismatch '+acceptedDomain+' != '+domain)
  115. # return
  116. if not nickname:
  117. if debug:
  118. print('DEBUG: nickname not found in '+thisActor)
  119. return
  120. if acceptedPort:
  121. if not '/'+acceptedDomain+':'+str(acceptedPort)+'/users/'+nickname in thisActor:
  122. if debug:
  123. print('Port: '+str(acceptedPort))
  124. print('Expected: /'+acceptedDomain+':'+str(acceptedPort)+'/users/'+nickname)
  125. print('Actual: '+thisActor)
  126. print('DEBUG: unrecognized actor '+thisActor)
  127. return
  128. else:
  129. if not '/'+acceptedDomain+'/users/'+nickname in thisActor:
  130. if debug:
  131. print('Expected: /'+acceptedDomain+'/users/'+nickname)
  132. print('Actual: '+thisActor)
  133. print('DEBUG: unrecognized actor '+thisActor)
  134. return
  135. followedActor=messageJson['object']['object']
  136. followedDomain,port=getDomainFromActor(followedActor)
  137. if not followedDomain:
  138. return
  139. followedDomainFull=followedDomain
  140. if port:
  141. followedDomainFull=followedDomain+':'+str(port)
  142. followedNickname=getNicknameFromActor(followedActor)
  143. if not followedNickname:
  144. return
  145. acceptedDomainFull=acceptedDomain
  146. if acceptedPort:
  147. acceptedDomainFull=acceptedDomain+':'+str(acceptedPort)
  148. # are capabilities attached? If so then store them
  149. if messageJson.get('capabilities'):
  150. if isinstance(messageJson['capabilities'], dict):
  151. capabilitiesGrantedSave(baseDir, \
  152. nickname,acceptedDomainFull, \
  153. messageJson['capabilities'])
  154. if followPerson(baseDir, \
  155. nickname,acceptedDomainFull, \
  156. followedNickname,followedDomainFull, \
  157. federationList,debug):
  158. if debug:
  159. print('DEBUG: '+nickname+'@'+acceptedDomainFull+' followed '+followedNickname+'@'+followedDomainFull)
  160. else:
  161. if debug:
  162. print('DEBUG: Unable to create follow - '+nickname+'@'+acceptedDomain+' -> '+followedNickname+'@'+followedDomain)
  163. def receiveAcceptReject(session,baseDir: str, \
  164. httpPrefix: str,domain :str,port: int, \
  165. sendThreads: [],postLog: [],cachedWebfingers: {}, \
  166. personCache: {},messageJson: {},federationList: [], \
  167. debug : bool) -> bool:
  168. """Receives an Accept or Reject within the POST section of HTTPServer
  169. """
  170. if messageJson['type']!='Accept' and messageJson['type']!='Reject':
  171. return False
  172. if not messageJson.get('actor'):
  173. if debug:
  174. print('DEBUG: '+messageJson['type']+' has no actor')
  175. return False
  176. if '/users/' not in messageJson['actor'] and '/profile/' not in messageJson['actor']:
  177. if debug:
  178. print('DEBUG: "users" or "profile" missing from actor in '+messageJson['type'])
  179. return False
  180. domain,tempPort=getDomainFromActor(messageJson['actor'])
  181. if not domainPermitted(domain,federationList):
  182. if debug:
  183. print('DEBUG: '+messageJson['type']+' from domain not permitted - '+domain)
  184. return False
  185. nickname=getNicknameFromActor(messageJson['actor'])
  186. if not nickname:
  187. if debug:
  188. print('DEBUG: '+messageJson['type']+' does not contain a nickname')
  189. return False
  190. handle=nickname.lower()+'@'+domain.lower()
  191. # receive follow accept
  192. acceptFollow(baseDir,domain,messageJson,federationList,debug)
  193. if debug:
  194. print('DEBUG: Uh, '+messageJson['type']+', I guess')
  195. return True