config.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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. PREVIEW_LIMIT = conf.get("preview_limit",0)
  59. USER_AGENT = (
  60. f"{requests.utils.default_user_agent()} (microblog.pub/{VERSION}; +{BASE_URL})"
  61. )
  62. mongo_client = MongoClient(
  63. host=[os.getenv("MICROBLOGPUB_MONGODB_HOST", "localhost:27017")]
  64. )
  65. DB_NAME = "{}_{}".format(USERNAME, DOMAIN.replace(".", "_"))
  66. DB = mongo_client[DB_NAME]
  67. GRIDFS = mongo_client[f"{DB_NAME}_gridfs"]
  68. MEDIA_CACHE = MediaCache(GRIDFS, USER_AGENT)
  69. def create_indexes():
  70. DB.command("compact", "activities")
  71. DB.activities.create_index([("remote_id", pymongo.ASCENDING)])
  72. DB.activities.create_index([("activity.object.id", pymongo.ASCENDING)])
  73. DB.activities.create_index([("meta.thread_root_parent", pymongo.ASCENDING)])
  74. DB.activities.create_index(
  75. [
  76. ("meta.thread_root_parent", pymongo.ASCENDING),
  77. ("meta.deleted", pymongo.ASCENDING),
  78. ]
  79. )
  80. DB.activities.create_index(
  81. [("activity.object.id", pymongo.ASCENDING), ("meta.deleted", pymongo.ASCENDING)]
  82. )
  83. DB.cache2.create_index(
  84. [
  85. ("path", pymongo.ASCENDING),
  86. ("type", pymongo.ASCENDING),
  87. ("arg", pymongo.ASCENDING),
  88. ]
  89. )
  90. DB.cache2.create_index("date", expireAfterSeconds=3600 * 12)
  91. # Index for the block query
  92. DB.activities.create_index(
  93. [
  94. ("box", pymongo.ASCENDING),
  95. ("type", pymongo.ASCENDING),
  96. ("meta.undo", pymongo.ASCENDING),
  97. ]
  98. )
  99. # Index for count queries
  100. DB.activities.create_index(
  101. [
  102. ("box", pymongo.ASCENDING),
  103. ("type", pymongo.ASCENDING),
  104. ("meta.undo", pymongo.ASCENDING),
  105. ("meta.deleted", pymongo.ASCENDING),
  106. ]
  107. )
  108. DB.activities.create_index([("box", pymongo.ASCENDING)])
  109. # Outbox query
  110. DB.activities.create_index(
  111. [
  112. ("box", pymongo.ASCENDING),
  113. ("type", pymongo.ASCENDING),
  114. ("meta.undo", pymongo.ASCENDING),
  115. ("meta.deleted", pymongo.ASCENDING),
  116. ("meta.public", pymongo.ASCENDING),
  117. ]
  118. )
  119. DB.activities.create_index(
  120. [
  121. ("type", pymongo.ASCENDING),
  122. ("activity.object.type", pymongo.ASCENDING),
  123. ("activity.object.inReplyTo", pymongo.ASCENDING),
  124. ("meta.deleted", pymongo.ASCENDING),
  125. ]
  126. )
  127. def _drop_db():
  128. if not DEBUG_MODE:
  129. return
  130. mongo_client.drop_database(DB_NAME)
  131. KEY = get_key(ID, USERNAME, DOMAIN)
  132. JWT_SECRET = get_secret_key("jwt")
  133. JWT = JSONWebSignatureSerializer(JWT_SECRET)
  134. def _admin_jwt_token() -> str:
  135. return JWT.dumps( # type: ignore
  136. {"me": "ADMIN", "ts": datetime.now().timestamp()}
  137. ).decode( # type: ignore
  138. "utf-8"
  139. )
  140. ADMIN_API_KEY = get_secret_key("admin_api_key", _admin_jwt_token)
  141. ME = {
  142. "@context":[
  143. "https://www.w3.org/ns/activitystreams",
  144. "https://w3id.org/security/v1",
  145. {
  146. "manuallyApprovesFollowers":"as:manuallyApprovesFollowers",
  147. "toot":"http://joinmastodon.org/ns#",
  148. "featured":{
  149. "@id":"toot:featured",
  150. "@type":"@id"
  151. },
  152. "alsoKnownAs":{
  153. "@id":"as:alsoKnownAs",
  154. "@type":"@id"
  155. },
  156. "movedTo":{
  157. "@id":"as:movedTo",
  158. "@type":"@id"
  159. },
  160. "schema":"http://schema.org#",
  161. "PropertyValue":"schema:PropertyValue",
  162. "value":"schema:value",
  163. "Hashtag":"as:Hashtag",
  164. "Emoji":"toot:Emoji",
  165. "IdentityProof":"toot:IdentityProof",
  166. "focalPoint":{
  167. "@container":"@list",
  168. "@id":"toot:focalPoint"
  169. }
  170. }
  171. ],
  172. "type": "Person",
  173. "id": ID,
  174. "following": ID + "/following",
  175. "followers": ID + "/followers",
  176. "featured": ID + "/featured",
  177. "liked": ID + "/liked",
  178. "inbox": ID + "/inbox",
  179. "outbox": ID + "/outbox",
  180. "preferredUsername": USERNAME,
  181. "name": NAME,
  182. "summary": SUMMARY,
  183. "endpoints": {},
  184. "url": ID,
  185. "manuallyApprovesFollowers": False,
  186. "attachment": [],
  187. "icon": {
  188. "mediaType": mimetypes.guess_type(ICON_URL)[0],
  189. "type": "Image",
  190. "url": ICON_URL,
  191. },
  192. "publicKey": KEY.to_dict(),
  193. }
  194. # TODO(tsileo): read the config from the YAML if set
  195. EMOJIS = "😺 😸 😹 😻 😼 😽 🙀 😿 😾"