acceptreject.py 8.1 KB

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