config.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. import mimetypes
  2. import os
  3. import subprocess
  4. from datetime import datetime
  5. from enum import Enum
  6. import requests
  7. import sass
  8. import yaml
  9. from itsdangerous import JSONWebSignatureSerializer
  10. from little_boxes import strtobool
  11. from little_boxes.activitypub import DEFAULT_CTX
  12. from pymongo import MongoClient
  13. import pymongo
  14. from utils.key import KEY_DIR
  15. from utils.key import get_key
  16. from utils.key import get_secret_key
  17. from utils.media import MediaCache
  18. def noop():
  19. pass
  20. CUSTOM_CACHE_HOOKS = False
  21. try:
  22. from cache_hooks import purge as custom_cache_purge_hook
  23. except ModuleNotFoundError:
  24. custom_cache_purge_hook = noop
  25. VERSION = (
  26. subprocess.check_output(["git", "describe", "--always"]).split()[0].decode("utf-8")
  27. )
  28. DEBUG_MODE = strtobool(os.getenv("MICROBLOGPUB_DEBUG", "false"))
  29. HEADERS = [
  30. "application/activity+json",
  31. "application/ld+json;profile=https://www.w3.org/ns/activitystreams",
  32. 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
  33. "application/ld+json",
  34. ]
  35. with open(os.path.join(KEY_DIR, "me.yml")) as f:
  36. conf = yaml.load(f)
  37. USERNAME = conf["username"]
  38. NAME = conf["name"]
  39. DOMAIN = conf["domain"]
  40. PUBLIC_DOMAIN = conf["public_url"]
  41. SCHEME = "https" if conf.get("https", True) else "http"
  42. BASE_URL = SCHEME + "://" + conf["public_url"]
  43. ACTOR_URL = SCHEME + "://" + conf["domain"]
  44. ID = BASE_URL
  45. SUMMARY = conf["summary"]
  46. ICON_URL = conf.get("icon_url",conf["default_icon"])
  47. PASS = conf["pass"]
  48. EXTRA_INBOXES = conf.get("extra_inboxes", [])
  49. COPYRIGHT = conf["copyright"]
  50. IMPRINT = conf["imprint_url"]
  51. PRIVACY = conf["privacy_url"]
  52. SOURCE_URL = conf["source_url"]
  53. DEFAULT_ICON = conf["default_icon"]
  54. FAVICON = conf["favicon_url"]
  55. HIDE_FOLLOWING = conf.get("hide_following", False)
  56. LIMIT = conf.get("limit",10)
  57. PORT = conf.get("port",5000)
  58. USER_AGENT = (
  59. f"{requests.utils.default_user_agent()} (microblog.pub/{VERSION}; +{BASE_URL})"
  60. )
  61. mongo_client = MongoClient(
  62. host=[os.getenv("MICROBLOGPUB_MONGODB_HOST", "localhost:27017")]
  63. )
  64. DB_NAME = "{}_{}".format(USERNAME, DOMAIN.replace(".", "_"))
  65. DB = mongo_client[DB_NAME]
  66. GRIDFS = mongo_client[f"{DB_NAME}_gridfs"]
  67. MEDIA_CACHE = MediaCache(GRIDFS, USER_AGENT)
  68. def create_indexes():
  69. DB.command("compact", "activities")
  70. DB.activities.create_index([("remote_id", pymongo.ASCENDING)])
  71. DB.activities.create_index([("activity.object.id", pymongo.ASCENDING)])
  72. DB.activities.create_index([("meta.thread_root_parent", pymongo.ASCENDING)])
  73. DB.activities.create_index(
  74. [
  75. ("meta.thread_root_parent", pymongo.ASCENDING),
  76. ("meta.deleted", pymongo.ASCENDING),
  77. ]
  78. )
  79. DB.activities.create_index(
  80. [("activity.object.id", pymongo.ASCENDING), ("meta.deleted", pymongo.ASCENDING)]
  81. )
  82. DB.cache2.create_index(
  83. [
  84. ("path", pymongo.ASCENDING),
  85. ("type", pymongo.ASCENDING),
  86. ("arg", pymongo.ASCENDING),
  87. ]
  88. )
  89. DB.cache2.create_index("date", expireAfterSeconds=3600 * 12)
  90. # Index for the block query
  91. DB.activities.create_index(
  92. [
  93. ("box", pymongo.ASCENDING),
  94. ("type", pymongo.ASCENDING),
  95. ("meta.undo", pymongo.ASCENDING),
  96. ]
  97. )
  98. # Index for count queries
  99. DB.activities.create_index(
  100. [
  101. ("box", pymongo.ASCENDING),
  102. ("type", pymongo.ASCENDING),
  103. ("meta.undo", pymongo.ASCENDING),
  104. ("meta.deleted", pymongo.ASCENDING),
  105. ]
  106. )
  107. DB.activities.create_index([("box", pymongo.ASCENDING)])
  108. # Outbox query
  109. DB.activities.create_index(
  110. [
  111. ("box", pymongo.ASCENDING),
  112. ("type", pymongo.ASCENDING),
  113. ("meta.undo", pymongo.ASCENDING),
  114. ("meta.deleted", pymongo.ASCENDING),
  115. ("meta.public", pymongo.ASCENDING),
  116. ]
  117. )
  118. DB.activities.create_index(
  119. [
  120. ("type", pymongo.ASCENDING),
  121. ("activity.object.type", pymongo.ASCENDING),
  122. ("activity.object.inReplyTo", pymongo.ASCENDING),
  123. ("meta.deleted", pymongo.ASCENDING),
  124. ]
  125. )
  126. def _drop_db():
  127. if not DEBUG_MODE:
  128. return
  129. mongo_client.drop_database(DB_NAME)
  130. KEY = get_key(ID, USERNAME, DOMAIN)
  131. JWT_SECRET = get_secret_key("jwt")
  132. JWT = JSONWebSignatureSerializer(JWT_SECRET)
  133. def _admin_jwt_token() -> str:
  134. return JWT.dumps( # type: ignore
  135. {"me": "ADMIN", "ts": datetime.now().timestamp()}
  136. ).decode( # type: ignore
  137. "utf-8"
  138. )
  139. ADMIN_API_KEY = get_secret_key("admin_api_key", _admin_jwt_token)
  140. ME = {
  141. "@context":[
  142. "https://www.w3.org/ns/activitystreams",
  143. "https://w3id.org/security/v1",
  144. {
  145. "manuallyApprovesFollowers":"as:manuallyApprovesFollowers",
  146. "toot":"http://joinmastodon.org/ns#",
  147. "featured":{
  148. "@id":"toot:featured",
  149. "@type":"@id"
  150. },
  151. "alsoKnownAs":{
  152. "@id":"as:alsoKnownAs",
  153. "@type":"@id"
  154. },
  155. "movedTo":{
  156. "@id":"as:movedTo",
  157. "@type":"@id"
  158. },
  159. "schema":"http://schema.org#",
  160. "PropertyValue":"schema:PropertyValue",
  161. "value":"schema:value",
  162. "Hashtag":"as:Hashtag",
  163. "Emoji":"toot:Emoji",
  164. "IdentityProof":"toot:IdentityProof",
  165. "focalPoint":{
  166. "@container":"@list",
  167. "@id":"toot:focalPoint"
  168. }
  169. }
  170. ],
  171. "type": "Person",
  172. "id": ID,
  173. "following": ID + "/following",
  174. "followers": ID + "/followers",
  175. "featured": ID + "/featured",
  176. "liked": ID + "/liked",
  177. "inbox": ID + "/inbox",
  178. "outbox": ID + "/outbox",
  179. "preferredUsername": USERNAME,
  180. "name": NAME,
  181. "summary": SUMMARY,
  182. "endpoints": {},
  183. "url": ID,
  184. "manuallyApprovesFollowers": False,
  185. "attachment": [],
  186. "icon": {
  187. "mediaType": mimetypes.guess_type(ICON_URL)[0],
  188. "type": "Image",
  189. "url": ICON_URL,
  190. },
  191. "publicKey": KEY.to_dict(),
  192. }
  193. # TODO(tsileo): read the config from the YAML if set
  194. EMOJIS = "😺 😸 😹 😻 😼 😽 🙀 😿 😾"