forgefed_controller.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import json
  2. import requests
  3. from forgefed_constants import AP_NS_URLS , AP_POST_HEADERS , AP_SEC_URL , HTTP_SIG_AUTH , \
  4. RESP_NOT_FOUND , STATUS_OK
  5. from forgefed_model import ApManager , NewNote , GetActivity , GetPerson , \
  6. IsValidActivity , IsValidNoteActivity , ParsePersonId
  7. ## request handlers ##
  8. def GetActorDocument(person_id):
  9. person = GetPerson(person_id)
  10. #person = Alice
  11. dbg = str(person.publicKey) if person != None else 'NFG' ; print("GetActorDocument() person.publicKey=" + dbg)
  12. if person == None: return None
  13. #print("GetActorDocument() person.to_dict().publicKey=" + str(person.to_dict()['publicKey']))
  14. person_dict = person.to_dict()
  15. person_dict['@context' ] = AP_NS_URLS
  16. person_dict['publicKey'] = person.publicKey
  17. #person_json = json.dumps(person_dict())
  18. person_dict['publicKey']['https://forgefed.angeley.es/ns#isShared'] = False # vervis extension
  19. cprint("GetActorDocument() person_id=" + person_id + "\n\tresp=" + json.dumps(person_dict) , DBG_COLOR_OUTGOING)
  20. return person_dict if person_dict != '' else None
  21. def user_get_handler(person_id , ap_dict):
  22. person_dict = GetActorDocument(person_id)
  23. person_json = json.dumps(person_dict)
  24. return [ STATUS_OK , person_json ] if person_json != None else RESP_NOT_FOUND
  25. def webfinger_get_handler(person_id , unused):
  26. person_dict = GetActorDocument(person_id)
  27. webfinger_json = json.dumps( \
  28. { \
  29. "subject" : "acct:" + person_dict['preferredUsername'] , \
  30. "links" : \
  31. [ \
  32. { \
  33. "rel" : "self" , \
  34. "type" : "application/activity+json" , \
  35. "href" : person_dict['url'] \
  36. } \
  37. ] \
  38. }) if person_dict != None else {}
  39. return [ STATUS_OK , webfinger_json ] if webfinger_json != None else RESP_NOT_FOUND
  40. def inbox_get_handler(person_id , ap_dict):
  41. SignedPostReq(Bob.inbox , AliceNote.to_dict()) # DEBUG
  42. return [ STATUS_OK , "GET/inbox" ]
  43. def followers_get_handler(person_id , ap_dict): return [ STATUS_OK , "GET/followers" ]
  44. def following_get_handler(person_id , ap_dict): return [ STATUS_OK , "GET/following" ]
  45. def liked_get_handler(person_id , ap_dict): return [ STATUS_OK , "GET/liked" ]
  46. def likes_get_handler(person_id , ap_dict): return [ STATUS_OK , "GET/likes" ]
  47. def outbox_get_handler(person_id , ap_dict): return [ STATUS_OK , "GET/outbox" ]
  48. def inbox_post_handler(person_id , ap_dict):
  49. ## validate request ##
  50. person = GetPerson(person_id)
  51. if person == None: return RESP_NOT_FOUND
  52. ## handle request ##
  53. to_person_id = ap_dict['to' ][0]
  54. from_person_id = ap_dict['attributedTo']
  55. note_body = ap_dict['content' ]
  56. person_full_id = ParsePersonId(to_person_id)
  57. # DEBUG BEGIN
  58. #print("inbox_post_handler() IsValidNoteActivity=" + str(IsValidNoteActivity(ap_dict)) + \
  59. #" to_person_id == person_id=" + str(to_person_id == person_id))
  60. # DEBUG END
  61. if IsValidNoteActivity(ap_dict) and to_person_id == person_full_id:
  62. incoming_note = NewNote(from_id=from_person_id , to_id=person_id , body=note_body)
  63. ApManager.on_post_to_box('inbox' , incoming_note.to_dict())
  64. return [ STATUS_OK , "POST/inbox" ]
  65. else:
  66. return [ STATUS_OK , 'POST/UNHANDLED_ACTIVITY_TYPE' ]
  67. def followers_post_handler(person_id , ap_dict): return [ STATUS_OK , "POST/followers" ]
  68. def following_post_handler(person_id , ap_dict): return [ STATUS_OK , "POST/following" ]
  69. def liked_post_handler(person_id , ap_dict): return [ STATUS_OK , "POST/liked" ]
  70. def likes_post_handler(person_id , ap_dict): return [ STATUS_OK , "POST/likes" ]
  71. def outbox_post_handler(person_id , ap_dict): return [ STATUS_OK , "POST/outbox" ]
  72. ## outgoing requests ##
  73. def SignedGetReq(url):
  74. resp = requests.get(url , auth=HTTP_SIG_AUTH)
  75. # DEBUG BEGIN
  76. print("SignedGetReq() url=" + url + " resp=" + resp.text , DBG_COLOR_OUTGOING)
  77. # DEBUG END
  78. def SignedPostReq(url , activity_dict):
  79. if IsValidActivity(activity_dict):
  80. post_body = json.dumps(activity_dict).encode()
  81. resp = requests.post(url , headers=AP_POST_HEADERS , data=post_body , auth=HTTP_SIG_AUTH)
  82. if resp.status_code == 200: ApManager.on_post_to_box('outbox' , activity_dict)
  83. # DEBUG BEGIN
  84. cprint("SignedPostReq() url=" + url + "\n\tpost_body=" + str(post_body) + "\n\tstatus=" + str(resp.status_code) + "\n\tresp=" + resp.text , DBG_COLOR_OUTGOING)
  85. else: cprint("SignedPostReq() invalid - dropping\n\turl=" + url + "\n\tpost_body=" + str(activity_dict) , DBG_COLOR_OUTGOING)
  86. # DEBUG END
  87. # WIP BEGIN
  88. #def key_resolver(key_id, algorithm):
  89. #return public_keys[key_id]
  90. #HTTPSignatureAuth.verify(request, key_resolver=key_resolver)
  91. # WIP END
  92. ## event handlers ##
  93. def OnBoxRecv(box , activity_id):
  94. # NOTE: this fires after message is written to the DB
  95. print("OnBoxRecv() box=" + box + " activity_id=" + activity_id)
  96. activity = GetActivity(activity_id)
  97. if activity != None:
  98. activity_msg = activity_id + " => " + activity['attributedTo'] + " -> " + activity['to']
  99. if box == 'inbox' : print("received activity: " + activity_msg)
  100. if box == 'outbox' : print("sent activity: " + activity_msg)
  101. ApManager.set_callback(OnBoxRecv)
  102. print("ready")
  103. # DEBUG BEGIN
  104. from termcolor import cprint
  105. from forgefed_constants import DBG_COLOR_OUTGOING , TEST_REMOTE_ACTOR_ID , TEST_REMOTE_ACTOR_URL , \
  106. TEST_REMOTE_INBOX_URL
  107. from forgefed_model import Actors , CreatePerson
  108. Alice = CreatePerson('alice')
  109. Bob = CreatePerson(TEST_REMOTE_ACTOR_ID , TEST_REMOTE_ACTOR_URL , TEST_REMOTE_INBOX_URL)
  110. AliceNote = NewNote(from_id=Alice.id , to_id=Bob.id , body='Hello Note')
  111. Actors[Alice.preferredUsername] = Alice
  112. Actors[Bob .preferredUsername] = Bob
  113. #print("Alice=" + str(Alice ) + " => " + str(GetPerson (Alice .preferredUsername)))
  114. #print("Bob=" + str(Bob ) + " => " + str(GetPerson (Bob .preferredUsername)))
  115. #print("AliceNote=" + str(AliceNote) + " => " + str(GetActivity(AliceNote.id)))
  116. #from forgefed_model import Db ; from pprint import pprint ; print("Db=") ; pprint(vars(Db))
  117. #SignedGetReq(TEST_REMOTE_ACTOR_URL)
  118. #SignedPostReq(Bob.inbox , {"k1":"v1"})
  119. #SignedPostReq(Bob.inbox , AliceNote.to_dict())
  120. # DEBUG END