2c0cfffd54
Implement the Mastodon Client REST API (/api/v1/*, /api/v2/*) and OAuth2 server within the ActivityPub plugin, enabling Mastodon-compatible clients to connect to the Fedify-based server. Core features: - OAuth2 with PKCE (S256) — app registration, authorization, token exchange - Instance info + nodeinfo for client discovery - Account lookup, verification, relationships, follow/unfollow/mute/block - Home/public/hashtag timelines with cursor-based pagination - Status viewing, creation, deletion, thread context - Favourite, boost, bookmark interactions with AP federation - Notifications with type filtering and pagination - Search across accounts, statuses, and hashtags - Markers for read position tracking - Bookmarks and favourites collection lists - 25+ stub endpoints preventing client errors on unimplemented features Architecture: - 24 new files under lib/mastodon/ (entities, helpers, middleware, routes) - Virtual endpoint at "/" via Indiekit.addEndpoint() for domain-root access - CORS + JSON error handling for browser-based clients - Six-layer mute/block filtering reusing existing moderation infrastructure BREAKING CHANGE: bumps to v3.0.0 — adds new MongoDB collections (ap_oauth_apps, ap_oauth_tokens, ap_markers) and new route registrations Confab-Link: http://localhost:8080/sessions/5360e3f5-b3cc-4bf3-8c31-5448e2b23947
58 lines
1.4 KiB
JavaScript
58 lines
1.4 KiB
JavaScript
/**
|
|
* Bearer token validation middleware for Mastodon Client API.
|
|
*
|
|
* Extracts the Bearer token from the Authorization header,
|
|
* validates it against the ap_oauth_tokens collection,
|
|
* and attaches token data to `req.mastodonToken`.
|
|
*/
|
|
|
|
/**
|
|
* Require a valid Bearer token. Returns 401 if invalid/missing.
|
|
*/
|
|
export async function tokenRequired(req, res, next) {
|
|
const token = await resolveToken(req);
|
|
|
|
if (!token) {
|
|
return res.status(401).json({
|
|
error: "The access token is invalid",
|
|
});
|
|
}
|
|
|
|
req.mastodonToken = token;
|
|
next();
|
|
}
|
|
|
|
/**
|
|
* Optional token — sets req.mastodonToken to null if absent.
|
|
* For public endpoints that personalize when authenticated.
|
|
*/
|
|
export async function optionalToken(req, res, next) {
|
|
req.mastodonToken = await resolveToken(req);
|
|
next();
|
|
}
|
|
|
|
/**
|
|
* Extract and validate Bearer token from request.
|
|
* @returns {object|null} Token document or null
|
|
*/
|
|
async function resolveToken(req) {
|
|
const authHeader = req.get("authorization");
|
|
if (!authHeader?.startsWith("Bearer ")) return null;
|
|
|
|
const accessToken = authHeader.slice(7);
|
|
if (!accessToken) return null;
|
|
|
|
const collections = req.app.locals.mastodonCollections;
|
|
const token = await collections.ap_oauth_tokens.findOne({
|
|
accessToken,
|
|
revokedAt: null,
|
|
});
|
|
|
|
if (!token) return null;
|
|
|
|
// Check expiry if set
|
|
if (token.expiresAt && token.expiresAt < new Date()) return null;
|
|
|
|
return token;
|
|
}
|