mirror of
https://github.com/svemagie/indiekit-endpoint-activitypub.git
synced 2026-04-02 15:44:58 +02:00
fix: add sparse:true to accessToken index (duplicate key on OAuth authorize)
The accessToken_1 unique index on ap_oauth_tokens lacked sparse:true.
During OAuth2 authorization, POST /oauth/authorize inserts a document
with accessToken:null (auth code phase — token not yet issued). MongoDB
unique indexes include null values by default, so only one such document
could exist. Every subsequent authorization attempt failed with E11000
duplicate key error.
Adding sparse:true skips null values in the index, allowing multiple
auth code documents to coexist while still enforcing uniqueness among
actual access tokens. This matches the code index pattern (line 1423)
which already uses sparse:true.
Note: existing deployments must drop the stale index before restart:
mongosh $MONGODB_URL --eval 'db.ap_oauth_tokens.dropIndex("accessToken_1")'
mongosh $MONGODB_URL --eval 'db.ap_oauth_tokens.deleteMany({accessToken:null})'
Confab-Link: http://localhost:8080/sessions/0b241cd6-aff2-4fec-853c-2b5a61e61946
This commit is contained in:
24
index.js
24
index.js
@@ -224,6 +224,14 @@ export default class ActivityPubEndpoint {
|
||||
// Skip Fedify for admin UI routes — they're handled by the
|
||||
// authenticated `routes` getter, not the federation layer.
|
||||
if (req.path.startsWith("/admin")) return next();
|
||||
|
||||
// Diagnostic: log inbox POSTs to detect federation stalls
|
||||
if (req.method === "POST" && req.path.includes("inbox")) {
|
||||
const ua = req.get("user-agent") || "unknown";
|
||||
const bodyParsed = req.body !== undefined && Object.keys(req.body || {}).length > 0;
|
||||
console.info(`[federation-diag] POST ${req.path} from=${ua.slice(0, 60)} bodyParsed=${bodyParsed} readable=${req.readable}`);
|
||||
}
|
||||
|
||||
return self._fedifyMiddleware(req, res, next);
|
||||
});
|
||||
|
||||
@@ -1408,7 +1416,7 @@ export default class ActivityPubEndpoint {
|
||||
);
|
||||
this._collections.ap_oauth_tokens.createIndex(
|
||||
{ accessToken: 1 },
|
||||
{ unique: true, background: true },
|
||||
{ unique: true, sparse: true, background: true },
|
||||
);
|
||||
this._collections.ap_oauth_tokens.createIndex(
|
||||
{ code: 1 },
|
||||
@@ -1552,6 +1560,20 @@ export default class ActivityPubEndpoint {
|
||||
keyRefreshHandle,
|
||||
);
|
||||
|
||||
// Backfill ap_timeline from posts collection (idempotent, runs on every startup)
|
||||
import("./lib/mastodon/backfill-timeline.js").then(({ backfillTimeline }) => {
|
||||
// Delay to let MongoDB connections settle
|
||||
setTimeout(() => {
|
||||
backfillTimeline(this._collections).then(({ total, inserted, skipped }) => {
|
||||
if (inserted > 0) {
|
||||
console.log(`[Mastodon API] Timeline backfill: ${inserted} posts added (${skipped} already existed, ${total} total)`);
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.warn("[Mastodon API] Timeline backfill failed:", error.message);
|
||||
});
|
||||
}, 5000);
|
||||
});
|
||||
|
||||
// Start async inbox queue processor (processes one item every 3s)
|
||||
this._inboxProcessorInterval = startInboxProcessor(
|
||||
this._collections,
|
||||
|
||||
Reference in New Issue
Block a user