epicyon/mastoapiv1.py

246 lines
9.0 KiB
Python
Raw Normal View History

2021-01-22 11:29:36 +00:00
__filename__ = "mastoapiv1.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
2021-01-26 10:07:42 +00:00
__version__ = "1.2.0"
2021-01-22 11:29:36 +00:00
__maintainer__ = "Bob Mottram"
2021-09-10 16:14:50 +00:00
__email__ = "bob@libreserver.org"
2021-01-22 11:29:36 +00:00
__status__ = "Production"
2021-06-26 11:16:41 +00:00
__module_group__ = "API"
2021-01-22 11:29:36 +00:00
import os
2021-12-26 15:13:34 +00:00
from utils import load_json
2021-12-26 14:08:58 +00:00
from utils import get_config_param
2021-12-26 12:02:29 +00:00
from utils import acct_dir
from metadata import metaDataInstance
2021-01-22 11:29:36 +00:00
def _getMastApiV1Id(path: str) -> int:
2021-01-22 13:32:37 +00:00
"""Extracts the mastodon Id number from the given path
"""
mastoId = None
idPath = '/api/v1/accounts/:'
if not path.startswith(idPath):
return None
mastoIdStr = path.replace(idPath, '')
if '/' in mastoIdStr:
mastoIdStr = mastoIdStr.split('/')[0]
if mastoIdStr.isdigit():
mastoId = int(mastoIdStr)
return mastoId
return None
def getMastoApiV1IdFromNickname(nickname: str) -> int:
"""Given an account nickname return the corresponding mastodon id
"""
return int.from_bytes(nickname.encode('utf-8'), 'little')
def _intToBytes(num: int) -> str:
if num == 0:
return b""
else:
return _intToBytes(num // 256) + bytes([num % 256])
def getNicknameFromMastoApiV1Id(mastoId: int) -> str:
"""Given the mastodon Id return the nickname
"""
nickname = _intToBytes(mastoId).decode()
return nickname[::-1]
2021-12-25 16:17:53 +00:00
def _getMastoApiV1Account(base_dir: str, nickname: str, domain: str) -> {}:
2021-01-22 11:29:36 +00:00
"""See https://github.com/McKael/mastodon-documentation/
blob/master/Using-the-API/API.md#account
Authorization has already been performed
"""
2021-12-26 12:02:29 +00:00
accountFilename = acct_dir(base_dir, nickname, domain) + '.json'
2021-01-22 11:29:36 +00:00
if not os.path.isfile(accountFilename):
return {}
2021-12-26 15:13:34 +00:00
accountJson = load_json(accountFilename)
2021-01-22 11:29:36 +00:00
if not accountJson:
return {}
mastoAccountJson = {
2021-01-22 13:32:37 +00:00
"id": getMastoApiV1IdFromNickname(nickname),
2021-01-22 11:29:36 +00:00
"username": nickname,
"acct": nickname,
2021-01-22 13:42:22 +00:00
"display_name": accountJson['name'],
2021-01-22 11:29:36 +00:00
"locked": accountJson['manuallyApprovesFollowers'],
2021-01-22 14:58:35 +00:00
"created_at": "2016-10-05T10:30:00Z",
2021-01-22 11:29:36 +00:00
"followers_count": 0,
"following_count": 0,
"statuses_count": 0,
"note": accountJson['summary'],
"url": accountJson['id'],
"avatar": accountJson['icon']['url'],
"avatar_static": accountJson['icon']['url'],
"header": accountJson['image']['url'],
"header_static": accountJson['image']['url']
}
return mastoAccountJson
2021-12-26 18:29:39 +00:00
def mastoApiV1Response(path: str, calling_domain: str,
uaStr: str,
authorized: bool,
2021-12-25 17:09:22 +00:00
http_prefix: str,
2021-12-25 16:17:53 +00:00
base_dir: str, nickname: str, domain: str,
2021-12-26 10:00:46 +00:00
domain_full: str,
2021-12-25 20:50:24 +00:00
onion_domain: str, i2p_domain: str,
translate: {},
registration: bool,
2021-12-25 23:03:28 +00:00
system_language: str,
2021-12-25 20:34:38 +00:00
project_version: str,
customEmoji: [],
2021-12-25 18:32:17 +00:00
show_node_info_accounts: bool,
2021-12-25 18:38:19 +00:00
broch_mode: bool) -> ({}, str):
"""This is a vestigil mastodon API for the purpose
of returning an empty result to sites like
https://mastopeek.app-dist.eu
"""
sendJson = None
sendJsonStr = ''
if not uaStr:
uaStr = ''
# parts of the api needing authorization
if authorized and nickname:
if path == '/api/v1/accounts/verify_credentials':
2021-12-25 16:17:53 +00:00
sendJson = _getMastoApiV1Account(base_dir, nickname, domain)
2021-10-23 20:17:55 +00:00
sendJsonStr = \
2021-10-23 20:18:17 +00:00
'masto API account sent for ' + nickname + ' ' + uaStr
2021-10-24 09:02:28 +00:00
# information about where the request is coming from
2021-12-26 18:29:39 +00:00
callingInfo = ' ' + uaStr + ', ' + calling_domain
2021-10-24 09:02:28 +00:00
# Parts of the api which don't need authorization
mastoId = _getMastApiV1Id(path)
if mastoId is not None:
pathNickname = getNicknameFromMastoApiV1Id(mastoId)
if pathNickname:
originalPath = path
if '/followers?' in path or \
'/following?' in path or \
'/search?' in path or \
'/relationships?' in path or \
'/statuses?' in path:
path = path.split('?')[0]
if path.endswith('/followers'):
sendJson = []
2021-10-23 18:51:30 +00:00
sendJsonStr = \
'masto API followers sent for ' + nickname + \
2021-10-24 09:02:28 +00:00
callingInfo
elif path.endswith('/following'):
sendJson = []
2021-10-23 18:51:30 +00:00
sendJsonStr = \
'masto API following sent for ' + nickname + \
2021-10-24 09:02:28 +00:00
callingInfo
elif path.endswith('/statuses'):
sendJson = []
2021-10-23 18:51:30 +00:00
sendJsonStr = \
'masto API statuses sent for ' + nickname + \
2021-10-24 09:02:28 +00:00
callingInfo
elif path.endswith('/search'):
sendJson = []
2021-10-23 18:51:30 +00:00
sendJsonStr = \
'masto API search sent ' + originalPath + \
2021-10-24 09:02:28 +00:00
callingInfo
elif path.endswith('/relationships'):
sendJson = []
sendJsonStr = \
2021-10-23 18:51:30 +00:00
'masto API relationships sent ' + originalPath + \
2021-10-24 09:02:28 +00:00
callingInfo
else:
sendJson = \
2021-12-25 16:17:53 +00:00
_getMastoApiV1Account(base_dir, pathNickname, domain)
2021-10-23 18:51:30 +00:00
sendJsonStr = \
'masto API account sent for ' + nickname + \
2021-10-24 09:02:28 +00:00
callingInfo
2021-08-02 11:54:47 +00:00
# NOTE: adding support for '/api/v1/directory seems to create
# federation problems, so avoid implementing that
if path.startswith('/api/v1/blocks'):
sendJson = []
2021-10-23 18:51:30 +00:00
sendJsonStr = \
2021-10-24 09:02:28 +00:00
'masto API instance blocks sent ' + path + callingInfo
elif path.startswith('/api/v1/favorites'):
sendJson = []
2021-10-24 09:02:28 +00:00
sendJsonStr = 'masto API favorites sent ' + path + callingInfo
elif path.startswith('/api/v1/follow_requests'):
sendJson = []
2021-10-23 18:51:30 +00:00
sendJsonStr = \
2021-10-24 09:02:28 +00:00
'masto API follow requests sent ' + path + callingInfo
elif path.startswith('/api/v1/mutes'):
sendJson = []
2021-10-23 18:51:30 +00:00
sendJsonStr = \
2021-10-24 09:02:28 +00:00
'masto API mutes sent ' + path + callingInfo
elif path.startswith('/api/v1/notifications'):
sendJson = []
2021-10-23 18:51:30 +00:00
sendJsonStr = \
2021-10-24 09:02:28 +00:00
'masto API notifications sent ' + path + callingInfo
elif path.startswith('/api/v1/reports'):
sendJson = []
2021-10-24 09:02:28 +00:00
sendJsonStr = 'masto API reports sent ' + path + callingInfo
elif path.startswith('/api/v1/statuses'):
sendJson = []
2021-10-24 09:02:28 +00:00
sendJsonStr = 'masto API statuses sent ' + path + callingInfo
elif path.startswith('/api/v1/timelines'):
2021-10-13 11:27:37 +00:00
sendJson = {
'error': 'This method requires an authenticated user'
}
2021-10-24 09:02:28 +00:00
sendJsonStr = 'masto API timelines sent ' + path + callingInfo
elif path.startswith('/api/v1/custom_emojis'):
sendJson = customEmoji
2021-10-23 18:51:30 +00:00
sendJsonStr = \
2021-10-24 09:02:28 +00:00
'masto API custom emojis sent ' + path + callingInfo
2021-12-26 14:08:58 +00:00
adminNickname = get_config_param(base_dir, 'admin')
if adminNickname and path == '/api/v1/instance':
instanceDescriptionShort = \
2021-12-26 14:08:58 +00:00
get_config_param(base_dir, 'instanceDescriptionShort')
if not instanceDescriptionShort:
instanceDescriptionShort = \
translate['Yet another Epicyon Instance']
2021-12-26 14:08:58 +00:00
instanceDescription = \
get_config_param(base_dir, 'instanceDescription')
instanceTitle = get_config_param(base_dir, 'instanceTitle')
2021-12-26 18:29:39 +00:00
if calling_domain.endswith('.onion') and onion_domain:
2021-12-26 10:00:46 +00:00
domain_full = onion_domain
2021-12-25 17:09:22 +00:00
http_prefix = 'http'
2021-12-26 18:29:39 +00:00
elif (calling_domain.endswith('.i2p') and i2p_domain):
2021-12-26 10:00:46 +00:00
domain_full = i2p_domain
2021-12-25 17:09:22 +00:00
http_prefix = 'http'
2021-12-25 18:38:19 +00:00
if broch_mode:
2021-12-25 18:32:17 +00:00
show_node_info_accounts = False
sendJson = \
2021-12-25 18:32:17 +00:00
metaDataInstance(show_node_info_accounts,
instanceTitle,
instanceDescriptionShort,
instanceDescription,
2021-12-25 17:09:22 +00:00
http_prefix,
2021-12-25 16:17:53 +00:00
base_dir,
adminNickname,
domain,
2021-12-26 10:00:46 +00:00
domain_full,
registration,
2021-12-25 23:03:28 +00:00
system_language,
2021-12-25 20:34:38 +00:00
project_version)
sendJsonStr = 'masto API instance metadata sent ' + uaStr
elif path.startswith('/api/v1/instance/peers'):
# This is just a dummy result.
# Showing the full list of peers would have privacy implications.
# On a large instance you are somewhat lost in the crowd, but on
# small instances a full list of peers would convey a lot of
# information about the interests of a small number of accounts
2021-12-26 10:00:46 +00:00
sendJson = ['mastodon.social', domain_full]
sendJsonStr = 'masto API peers metadata sent ' + uaStr
elif path.startswith('/api/v1/instance/activity'):
sendJson = []
sendJsonStr = 'masto API activity metadata sent ' + uaStr
return sendJson, sendJsonStr