forgefed_wsgi.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. # $ sudo pacman -S python-cryptography python-jinja python-pip python-requests
  2. # $ pip install activitypub --user
  3. # $ pip install requests-http-signature --user
  4. #import site ; site.addsitedir('~/.local/lib/python3.7/site-packages/')
  5. import json
  6. import re
  7. from forgefed_constants import PATH_REGEX , RESP_INVALID_ACTIVITY , RESP_NOT_FOUND
  8. from forgefed_controller import *
  9. from forgefed_model import GetPerson
  10. ROUTES = \
  11. { \
  12. 'GET-/.well-known/webfinger' : webfinger_get_handler , \
  13. 'GET-' : user_get_handler , \
  14. 'GET-inbox' : inbox_get_handler , \
  15. 'GET-followers' : followers_get_handler , \
  16. 'GET-following' : following_get_handler , \
  17. 'GET-liked' : liked_get_handler , \
  18. 'GET-likes' : likes_get_handler , \
  19. 'GET-outbox' : outbox_get_handler , \
  20. 'POST-inbox' : inbox_post_handler , \
  21. 'POST-followers' : followers_post_handler , \
  22. 'POST-following' : following_post_handler , \
  23. 'POST-liked' : liked_post_handler , \
  24. 'POST-likes' : likes_post_handler , \
  25. 'POST-outbox' : outbox_post_handler
  26. }
  27. def application(env , start_response):
  28. # DEBUG BEGIN
  29. import datetime ; cprint("\nnew request " + str(datetime.datetime.now()) , DBG_COLOR_INCOMING)
  30. #status = STATUS_OK
  31. #body = 'Hello World!'
  32. #body = 'env =>' + str(env).replace(',' , ',\n\t').replace('{' , '{ ').replace('}' , ' }')
  33. # DEBUG END
  34. ## parse request ##
  35. full_path = env.get('PATH_INFO' )
  36. method = env.get('REQUEST_METHOD')
  37. if method == 'GET' : ap_dict = ''
  38. elif method == 'POST':
  39. try:
  40. req_body_len = int(env.get('CONTENT_LENGTH' , 0))
  41. req_body = env['wsgi.input'].read(req_body_len).decode('utf8')
  42. ap_dict = json.loads(req_body)
  43. except (ValueError):
  44. method = 'INVALID_JSON_POST' # invalidate the request route
  45. req_body = None
  46. ap_dict = None
  47. path = re.sub(PATH_REGEX , '/' , full_path).split('/')
  48. person_id = path[1] if len(path) >= 2 else ''
  49. channel = path[2] if len(path) >= 3 else ''
  50. person = GetPerson(person_id)
  51. routes_key = method + '-' + channel if person != None else ''
  52. if full_path == '/.well-known/webfinger':
  53. routes_key = method + '-' + full_path
  54. query = env.get('QUERY_STRING')
  55. print("query=" + query)
  56. person_id = re.sub(r'resource=acct:' , '' , query)
  57. route_fn = ROUTES.get(routes_key)
  58. is_valid_req = route_fn != None
  59. is_valid_payload = method != 'POST' or IsValidActivity(ap_dict)
  60. # DEBUG BEGIN
  61. if method != 'POST': req_body = ''
  62. DbgTraceReq(full_path , path , person_id , channel , method , req_body , ap_dict , routes_key , route_fn)
  63. # DEBUG END
  64. ## handle request ##
  65. resp = route_fn(person_id , ap_dict) if is_valid_req and is_valid_payload else \
  66. RESP_INVALID_ACTIVITY if is_valid_req else \
  67. RESP_NOT_FOUND
  68. status = resp[0] if len(resp) == 2 else '442 BORKED'
  69. body = resp[1] if len(resp) == 2 else 'INVALID_RESP'
  70. content_type = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' if routes_key == 'GET-' else 'text/plain'
  71. #content_type = 'application/ld+json' if routes_key == 'GET-' else \
  72. #'application/activity+json' if routes_key == 'GET-inbox' or \
  73. #routes_key == 'GET-outbox' else 'text/plain'
  74. content_len = str(len(body))
  75. headers = [ ('Content-type' , content_type) ,
  76. ('Content-Length' , content_len ) ]
  77. # DEBUG BEGIN
  78. DbgTraceResp(status , body)
  79. # DEBUG END
  80. ## respond ##
  81. start_response(status , headers)
  82. return [ body.encode('utf8') ]
  83. # DEBUG BEGIN
  84. from termcolor import cprint
  85. from forgefed_constants import DBG_COLOR_INCOMING
  86. def DbgTraceReq(full_path , path , person_id , channel , method , req_body , ap_dict , routes_key , route_fn):
  87. apdict = json.dumps(ap_dict , sort_keys=True , indent=2)
  88. cprint("full_path = " + full_path , DBG_COLOR_INCOMING)
  89. cprint("path = " + '/'.join(path) , DBG_COLOR_INCOMING)
  90. cprint("person_id = " + person_id , DBG_COLOR_INCOMING)
  91. cprint("channel = " + channel , DBG_COLOR_INCOMING)
  92. cprint("method = " + method , DBG_COLOR_INCOMING)
  93. cprint("req_body = " + req_body , DBG_COLOR_INCOMING)
  94. cprint("ap_dict = " + apdict , DBG_COLOR_INCOMING)
  95. cprint("routes_key = " + routes_key , DBG_COLOR_INCOMING)
  96. cprint("route_fn = " + str(route_fn) , DBG_COLOR_INCOMING)
  97. def DbgTraceResp(status , body):
  98. cprint("status = " + status , DBG_COLOR_INCOMING)
  99. cprint("body = " + body , DBG_COLOR_INCOMING)
  100. # DEBUG END