From 9f90203f20b891bc4b4daeccabe045befd7b4b1c Mon Sep 17 00:00:00 2001 From: devin ivy Date: Wed, 21 Feb 2024 20:14:45 -0500 Subject: [PATCH] Optional service config in pds distribution (#2211) * make appview and mod services optional on pds * pds: allow configuring a reporting service optionally separate from an administrative mod service * tidy --- .../src/api/app/bsky/actor/getPreferences.ts | 1 + .../pds/src/api/app/bsky/actor/getProfile.ts | 4 +- .../pds/src/api/app/bsky/actor/getProfiles.ts | 4 +- .../src/api/app/bsky/actor/getSuggestions.ts | 4 +- .../src/api/app/bsky/actor/putPreferences.ts | 1 + .../src/api/app/bsky/actor/searchActors.ts | 4 +- .../app/bsky/actor/searchActorsTypeahead.ts | 4 +- .../src/api/app/bsky/feed/getActorFeeds.ts | 4 +- .../src/api/app/bsky/feed/getActorLikes.ts | 4 +- .../src/api/app/bsky/feed/getAuthorFeed.ts | 4 +- packages/pds/src/api/app/bsky/feed/getFeed.ts | 7 ++- .../src/api/app/bsky/feed/getFeedGenerator.ts | 4 +- .../api/app/bsky/feed/getFeedGenerators.ts | 4 +- .../pds/src/api/app/bsky/feed/getLikes.ts | 4 +- .../pds/src/api/app/bsky/feed/getListFeed.ts | 4 +- .../src/api/app/bsky/feed/getPostThread.ts | 8 ++- .../pds/src/api/app/bsky/feed/getPosts.ts | 4 +- .../src/api/app/bsky/feed/getRepostedBy.ts | 4 +- .../api/app/bsky/feed/getSuggestedFeeds.ts | 4 +- .../pds/src/api/app/bsky/feed/getTimeline.ts | 4 +- .../pds/src/api/app/bsky/feed/searchPosts.ts | 4 +- .../pds/src/api/app/bsky/graph/getBlocks.ts | 4 +- .../src/api/app/bsky/graph/getFollowers.ts | 4 +- .../pds/src/api/app/bsky/graph/getFollows.ts | 4 +- .../pds/src/api/app/bsky/graph/getList.ts | 4 +- .../src/api/app/bsky/graph/getListBlocks.ts | 4 +- .../src/api/app/bsky/graph/getListMutes.ts | 4 +- .../pds/src/api/app/bsky/graph/getLists.ts | 4 +- .../pds/src/api/app/bsky/graph/getMutes.ts | 4 +- .../bsky/graph/getSuggestedFollowsByActor.ts | 4 +- .../pds/src/api/app/bsky/graph/muteActor.ts | 4 +- .../src/api/app/bsky/graph/muteActorList.ts | 4 +- .../pds/src/api/app/bsky/graph/unmuteActor.ts | 4 +- .../src/api/app/bsky/graph/unmuteActorList.ts | 4 +- .../app/bsky/notification/getUnreadCount.ts | 4 +- .../bsky/notification/listNotifications.ts | 4 +- .../api/app/bsky/notification/registerPush.ts | 15 +++-- .../api/app/bsky/notification/updateSeen.ts | 4 +- .../unspecced/getPopularFeedGenerators.ts | 4 +- .../bsky/unspecced/getTaggedSuggestions.ts | 4 +- .../admin/createCommunicationTemplate.ts | 5 +- .../admin/deleteCommunicationTemplate.ts | 4 +- .../com/atproto/admin/emitModerationEvent.ts | 5 +- .../com/atproto/admin/getModerationEvent.ts | 4 +- .../src/api/com/atproto/admin/getRecord.ts | 4 +- .../pds/src/api/com/atproto/admin/getRepo.ts | 4 +- .../admin/listCommunicationTemplates.ts | 5 +- .../atproto/admin/queryModerationEvents.ts | 4 +- .../atproto/admin/queryModerationStatuses.ts | 4 +- .../src/api/com/atproto/admin/searchRepos.ts | 4 +- .../src/api/com/atproto/admin/sendEmail.ts | 32 +++++----- .../admin/updateCommunicationTemplate.ts | 4 +- .../api/com/atproto/identity/resolveHandle.ts | 2 +- .../com/atproto/moderation/createReport.ts | 10 +++- .../pds/src/api/com/atproto/repo/getRecord.ts | 4 ++ packages/pds/src/auth-verifier.ts | 5 +- packages/pds/src/config/config.ts | 60 +++++++++++++++---- packages/pds/src/config/env.ts | 8 +++ packages/pds/src/context.ts | 38 ++++++++---- .../tests/proxied/read-after-write.test.ts | 5 +- 60 files changed, 280 insertions(+), 103 deletions(-) diff --git a/packages/pds/src/api/app/bsky/actor/getPreferences.ts b/packages/pds/src/api/app/bsky/actor/getPreferences.ts index d89666358ae..0068281a2dc 100644 --- a/packages/pds/src/api/app/bsky/actor/getPreferences.ts +++ b/packages/pds/src/api/app/bsky/actor/getPreferences.ts @@ -3,6 +3,7 @@ import AppContext from '../../../../context' import { AuthScope } from '../../../../auth-verifier' export default function (server: Server, ctx: AppContext) { + if (!ctx.cfg.bskyAppView) return server.app.bsky.actor.getPreferences({ auth: ctx.authVerifier.access, handler: async ({ auth }) => { diff --git a/packages/pds/src/api/app/bsky/actor/getProfile.ts b/packages/pds/src/api/app/bsky/actor/getProfile.ts index d772b2b2ac2..74de7f3af6d 100644 --- a/packages/pds/src/api/app/bsky/actor/getProfile.ts +++ b/packages/pds/src/api/app/bsky/actor/getProfile.ts @@ -12,13 +12,15 @@ import { pipethrough } from '../../../../pipethrough' const METHOD_NSID = 'app.bsky.actor.getProfile' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.actor.getProfile({ auth: ctx.authVerifier.accessOrRole, handler: async ({ req, auth, params }) => { const requester = auth.credentials.type === 'access' ? auth.credentials.did : null const res = await pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, METHOD_NSID, params, requester ? await ctx.appviewAuthHeaders(requester) : authPassthru(req), diff --git a/packages/pds/src/api/app/bsky/actor/getProfiles.ts b/packages/pds/src/api/app/bsky/actor/getProfiles.ts index edbc880f43d..3ab9338c7c5 100644 --- a/packages/pds/src/api/app/bsky/actor/getProfiles.ts +++ b/packages/pds/src/api/app/bsky/actor/getProfiles.ts @@ -11,13 +11,15 @@ import { const METHOD_NSID = 'app.bsky.actor.getProfiles' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.actor.getProfiles({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did const res = await pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, METHOD_NSID, params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/actor/getSuggestions.ts b/packages/pds/src/api/app/bsky/actor/getSuggestions.ts index 548d4f1611e..6bfd65adf74 100644 --- a/packages/pds/src/api/app/bsky/actor/getSuggestions.ts +++ b/packages/pds/src/api/app/bsky/actor/getSuggestions.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.actor.getSuggestions({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.actor.getSuggestions', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/actor/putPreferences.ts b/packages/pds/src/api/app/bsky/actor/putPreferences.ts index f6274d42278..7b3755f891e 100644 --- a/packages/pds/src/api/app/bsky/actor/putPreferences.ts +++ b/packages/pds/src/api/app/bsky/actor/putPreferences.ts @@ -4,6 +4,7 @@ import AppContext from '../../../../context' import { AccountPreference } from '../../../../actor-store/preference/reader' export default function (server: Server, ctx: AppContext) { + if (!ctx.cfg.bskyAppView) return server.app.bsky.actor.putPreferences({ auth: ctx.authVerifier.accessCheckTakedown, handler: async ({ auth, input }) => { diff --git a/packages/pds/src/api/app/bsky/actor/searchActors.ts b/packages/pds/src/api/app/bsky/actor/searchActors.ts index 57f502acb3c..53c97566818 100644 --- a/packages/pds/src/api/app/bsky/actor/searchActors.ts +++ b/packages/pds/src/api/app/bsky/actor/searchActors.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.actor.searchActors({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.actor.searchActors', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/actor/searchActorsTypeahead.ts b/packages/pds/src/api/app/bsky/actor/searchActorsTypeahead.ts index dbf57900509..51e778b24ee 100644 --- a/packages/pds/src/api/app/bsky/actor/searchActorsTypeahead.ts +++ b/packages/pds/src/api/app/bsky/actor/searchActorsTypeahead.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.actor.searchActorsTypeahead({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.actor.searchActorsTypeahead', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/feed/getActorFeeds.ts b/packages/pds/src/api/app/bsky/feed/getActorFeeds.ts index ca5d8d5d48e..123bce1785b 100644 --- a/packages/pds/src/api/app/bsky/feed/getActorFeeds.ts +++ b/packages/pds/src/api/app/bsky/feed/getActorFeeds.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getActorFeeds({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.feed.getActorFeeds', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/feed/getActorLikes.ts b/packages/pds/src/api/app/bsky/feed/getActorLikes.ts index 4ba8bb49f49..d8e2f839904 100644 --- a/packages/pds/src/api/app/bsky/feed/getActorLikes.ts +++ b/packages/pds/src/api/app/bsky/feed/getActorLikes.ts @@ -12,13 +12,15 @@ import { pipethrough } from '../../../../pipethrough' const METHOD_NSID = 'app.bsky.feed.getActorLikes' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getActorLikes({ auth: ctx.authVerifier.accessOrRole, handler: async ({ req, params, auth }) => { const requester = auth.credentials.type === 'access' ? auth.credentials.did : null const res = await pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, METHOD_NSID, params, requester ? await ctx.appviewAuthHeaders(requester) : authPassthru(req), diff --git a/packages/pds/src/api/app/bsky/feed/getAuthorFeed.ts b/packages/pds/src/api/app/bsky/feed/getAuthorFeed.ts index f142a6c34e9..c90760bbfd9 100644 --- a/packages/pds/src/api/app/bsky/feed/getAuthorFeed.ts +++ b/packages/pds/src/api/app/bsky/feed/getAuthorFeed.ts @@ -13,13 +13,15 @@ import { pipethrough } from '../../../../pipethrough' const METHOD_NSID = 'app.bsky.feed.getAuthorFeed' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getAuthorFeed({ auth: ctx.authVerifier.accessOrRole, handler: async ({ req, params, auth }) => { const requester = auth.credentials.type === 'access' ? auth.credentials.did : null const res = await pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, METHOD_NSID, params, requester ? await ctx.appviewAuthHeaders(requester) : authPassthru(req), diff --git a/packages/pds/src/api/app/bsky/feed/getFeed.ts b/packages/pds/src/api/app/bsky/feed/getFeed.ts index ea63cf1bd47..89c84b18ba8 100644 --- a/packages/pds/src/api/app/bsky/feed/getFeed.ts +++ b/packages/pds/src/api/app/bsky/feed/getFeed.ts @@ -3,13 +3,16 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { appViewAgent } = ctx + const { bskyAppView } = ctx.cfg + if (!appViewAgent || !bskyAppView) return server.app.bsky.feed.getFeed({ auth: ctx.authVerifier.access, handler: async ({ req, params, auth }) => { const requester = auth.credentials.did const { data: feed } = - await ctx.appViewAgent.api.app.bsky.feed.getFeedGenerator( + await appViewAgent.api.app.bsky.feed.getFeedGenerator( { feed: params.feed }, await ctx.appviewAuthHeaders(requester), ) @@ -21,7 +24,7 @@ export default function (server: Server, ctx: AppContext) { serviceAuthHeaders.headers['accept-language'] = req.headers['accept-language'] return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.feed.getFeed', params, serviceAuthHeaders, diff --git a/packages/pds/src/api/app/bsky/feed/getFeedGenerator.ts b/packages/pds/src/api/app/bsky/feed/getFeedGenerator.ts index deb5025f0fe..f71ea74117f 100644 --- a/packages/pds/src/api/app/bsky/feed/getFeedGenerator.ts +++ b/packages/pds/src/api/app/bsky/feed/getFeedGenerator.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getFeedGenerator({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.feed.getFeedGenerator', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/feed/getFeedGenerators.ts b/packages/pds/src/api/app/bsky/feed/getFeedGenerators.ts index 12755d0feea..c07c3dac228 100644 --- a/packages/pds/src/api/app/bsky/feed/getFeedGenerators.ts +++ b/packages/pds/src/api/app/bsky/feed/getFeedGenerators.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getFeedGenerators({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.feed.getFeedGenerators', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/feed/getLikes.ts b/packages/pds/src/api/app/bsky/feed/getLikes.ts index cb5f2cd6fbc..90a96681c85 100644 --- a/packages/pds/src/api/app/bsky/feed/getLikes.ts +++ b/packages/pds/src/api/app/bsky/feed/getLikes.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getLikes({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.feed.getLikes', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/feed/getListFeed.ts b/packages/pds/src/api/app/bsky/feed/getListFeed.ts index cbbc757dd52..3447a721904 100644 --- a/packages/pds/src/api/app/bsky/feed/getListFeed.ts +++ b/packages/pds/src/api/app/bsky/feed/getListFeed.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getListFeed({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.feed.getListFeed', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/feed/getPostThread.ts b/packages/pds/src/api/app/bsky/feed/getPostThread.ts index d4aec88970a..da09523875b 100644 --- a/packages/pds/src/api/app/bsky/feed/getPostThread.ts +++ b/packages/pds/src/api/app/bsky/feed/getPostThread.ts @@ -1,3 +1,4 @@ +import assert from 'node:assert' import { AtUri } from '@atproto/syntax' import { Headers, XRPCError } from '@atproto/xrpc' import { Server } from '../../../../lexicon' @@ -26,6 +27,8 @@ import { pipethrough } from '../../../../pipethrough' const METHOD_NSID = 'app.bsky.feed.getPostThread' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getPostThread({ auth: ctx.authVerifier.accessOrRole, handler: async ({ req, params, auth }) => { @@ -34,7 +37,7 @@ export default function (server: Server, ctx: AppContext) { if (!requester) { return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, METHOD_NSID, params, authPassthru(req), @@ -43,7 +46,7 @@ export default function (server: Server, ctx: AppContext) { try { const res = await pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, METHOD_NSID, params, await ctx.appviewAuthHeaders(requester), @@ -200,6 +203,7 @@ const readAfterWriteNotFound = async ( const highestParent = getHighestParent(thread) if (highestParent) { try { + assert(ctx.appViewAgent) const parentsRes = await ctx.appViewAgent.api.app.bsky.feed.getPostThread( { uri: highestParent, parentHeight: params.parentHeight, depth: 0 }, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/feed/getPosts.ts b/packages/pds/src/api/app/bsky/feed/getPosts.ts index 5caa986f9f4..89d0d08587d 100644 --- a/packages/pds/src/api/app/bsky/feed/getPosts.ts +++ b/packages/pds/src/api/app/bsky/feed/getPosts.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getPosts({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.feed.getPosts', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/feed/getRepostedBy.ts b/packages/pds/src/api/app/bsky/feed/getRepostedBy.ts index dcb00d5ce64..971d150824c 100644 --- a/packages/pds/src/api/app/bsky/feed/getRepostedBy.ts +++ b/packages/pds/src/api/app/bsky/feed/getRepostedBy.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getRepostedBy({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.feed.getRepostedBy', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/feed/getSuggestedFeeds.ts b/packages/pds/src/api/app/bsky/feed/getSuggestedFeeds.ts index ee1161ca0ff..6da81787533 100644 --- a/packages/pds/src/api/app/bsky/feed/getSuggestedFeeds.ts +++ b/packages/pds/src/api/app/bsky/feed/getSuggestedFeeds.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getSuggestedFeeds({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.feed.getSuggestedFeeds', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/feed/getTimeline.ts b/packages/pds/src/api/app/bsky/feed/getTimeline.ts index ffce48244b5..90fc5bac42f 100644 --- a/packages/pds/src/api/app/bsky/feed/getTimeline.ts +++ b/packages/pds/src/api/app/bsky/feed/getTimeline.ts @@ -11,12 +11,14 @@ import { pipethrough } from '../../../../pipethrough' const METHOD_NSID = 'app.bsky.feed.getTimeline' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getTimeline({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did const res = await pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, METHOD_NSID, params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/feed/searchPosts.ts b/packages/pds/src/api/app/bsky/feed/searchPosts.ts index 24bc33f6034..7cc09c864e5 100644 --- a/packages/pds/src/api/app/bsky/feed/searchPosts.ts +++ b/packages/pds/src/api/app/bsky/feed/searchPosts.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.searchPosts({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.feed.searchPosts', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/graph/getBlocks.ts b/packages/pds/src/api/app/bsky/graph/getBlocks.ts index f50066e5e8f..1b29f9b62d2 100644 --- a/packages/pds/src/api/app/bsky/graph/getBlocks.ts +++ b/packages/pds/src/api/app/bsky/graph/getBlocks.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getBlocks({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.graph.getBlocks', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/graph/getFollowers.ts b/packages/pds/src/api/app/bsky/graph/getFollowers.ts index 4a07284b525..0a158f2bbe5 100644 --- a/packages/pds/src/api/app/bsky/graph/getFollowers.ts +++ b/packages/pds/src/api/app/bsky/graph/getFollowers.ts @@ -4,13 +4,15 @@ import { authPassthru } from '../../../proxy' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getFollowers({ auth: ctx.authVerifier.accessOrRole, handler: async ({ req, params, auth }) => { const requester = auth.credentials.type === 'access' ? auth.credentials.did : null return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.graph.getFollowers', params, requester ? await ctx.appviewAuthHeaders(requester) : authPassthru(req), diff --git a/packages/pds/src/api/app/bsky/graph/getFollows.ts b/packages/pds/src/api/app/bsky/graph/getFollows.ts index 2f3c2f2041a..6802acda888 100644 --- a/packages/pds/src/api/app/bsky/graph/getFollows.ts +++ b/packages/pds/src/api/app/bsky/graph/getFollows.ts @@ -4,13 +4,15 @@ import { authPassthru } from '../../../proxy' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getFollows({ auth: ctx.authVerifier.accessOrRole, handler: async ({ req, params, auth }) => { const requester = auth.credentials.type === 'access' ? auth.credentials.did : null return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.graph.getFollows', params, requester ? await ctx.appviewAuthHeaders(requester) : authPassthru(req), diff --git a/packages/pds/src/api/app/bsky/graph/getList.ts b/packages/pds/src/api/app/bsky/graph/getList.ts index 60ea41cfd2f..6ef1dbf7ee0 100644 --- a/packages/pds/src/api/app/bsky/graph/getList.ts +++ b/packages/pds/src/api/app/bsky/graph/getList.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getList({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.graph.getList', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/graph/getListBlocks.ts b/packages/pds/src/api/app/bsky/graph/getListBlocks.ts index fed639e1dc8..d9aed6e7cd6 100644 --- a/packages/pds/src/api/app/bsky/graph/getListBlocks.ts +++ b/packages/pds/src/api/app/bsky/graph/getListBlocks.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getListBlocks({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.graph.getListBlocks', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/graph/getListMutes.ts b/packages/pds/src/api/app/bsky/graph/getListMutes.ts index f3856a7fdc0..575c09d5b1a 100644 --- a/packages/pds/src/api/app/bsky/graph/getListMutes.ts +++ b/packages/pds/src/api/app/bsky/graph/getListMutes.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getListMutes({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.graph.getListMutes', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/graph/getLists.ts b/packages/pds/src/api/app/bsky/graph/getLists.ts index 4af580e280c..c824c9cdb4b 100644 --- a/packages/pds/src/api/app/bsky/graph/getLists.ts +++ b/packages/pds/src/api/app/bsky/graph/getLists.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getLists({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.graph.getLists', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/graph/getMutes.ts b/packages/pds/src/api/app/bsky/graph/getMutes.ts index 103c0bf4f2f..d422237dd0f 100644 --- a/packages/pds/src/api/app/bsky/graph/getMutes.ts +++ b/packages/pds/src/api/app/bsky/graph/getMutes.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getMutes({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.graph.getMutes', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts b/packages/pds/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts index b4422b7090e..dfe453be8f6 100644 --- a/packages/pds/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts +++ b/packages/pds/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getSuggestedFollowsByActor({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.graph.getSuggestedFollowsByActor', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/graph/muteActor.ts b/packages/pds/src/api/app/bsky/graph/muteActor.ts index 2b2f218b44d..c88a05b9eaf 100644 --- a/packages/pds/src/api/app/bsky/graph/muteActor.ts +++ b/packages/pds/src/api/app/bsky/graph/muteActor.ts @@ -2,12 +2,14 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { + const { appViewAgent } = ctx + if (!appViewAgent) return server.app.bsky.graph.muteActor({ auth: ctx.authVerifier.access, handler: async ({ auth, input }) => { const requester = auth.credentials.did - await ctx.appViewAgent.api.app.bsky.graph.muteActor(input.body, { + await appViewAgent.api.app.bsky.graph.muteActor(input.body, { ...(await ctx.appviewAuthHeaders(requester)), encoding: 'application/json', }) diff --git a/packages/pds/src/api/app/bsky/graph/muteActorList.ts b/packages/pds/src/api/app/bsky/graph/muteActorList.ts index 97d524900f7..74c2357d3d9 100644 --- a/packages/pds/src/api/app/bsky/graph/muteActorList.ts +++ b/packages/pds/src/api/app/bsky/graph/muteActorList.ts @@ -2,12 +2,14 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { + const { appViewAgent } = ctx + if (!appViewAgent) return server.app.bsky.graph.muteActorList({ auth: ctx.authVerifier.access, handler: async ({ auth, input }) => { const requester = auth.credentials.did - await ctx.appViewAgent.api.app.bsky.graph.muteActorList(input.body, { + await appViewAgent.api.app.bsky.graph.muteActorList(input.body, { ...(await ctx.appviewAuthHeaders(requester)), encoding: 'application/json', }) diff --git a/packages/pds/src/api/app/bsky/graph/unmuteActor.ts b/packages/pds/src/api/app/bsky/graph/unmuteActor.ts index 0f7a1610321..e73c5d08e5a 100644 --- a/packages/pds/src/api/app/bsky/graph/unmuteActor.ts +++ b/packages/pds/src/api/app/bsky/graph/unmuteActor.ts @@ -2,12 +2,14 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { + const { appViewAgent } = ctx + if (!appViewAgent) return server.app.bsky.graph.unmuteActor({ auth: ctx.authVerifier.access, handler: async ({ auth, input }) => { const requester = auth.credentials.did - await ctx.appViewAgent.api.app.bsky.graph.unmuteActor(input.body, { + await appViewAgent.api.app.bsky.graph.unmuteActor(input.body, { ...(await ctx.appviewAuthHeaders(requester)), encoding: 'application/json', }) diff --git a/packages/pds/src/api/app/bsky/graph/unmuteActorList.ts b/packages/pds/src/api/app/bsky/graph/unmuteActorList.ts index aaf5225bded..e36afeaf0a3 100644 --- a/packages/pds/src/api/app/bsky/graph/unmuteActorList.ts +++ b/packages/pds/src/api/app/bsky/graph/unmuteActorList.ts @@ -2,12 +2,14 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { + const { appViewAgent } = ctx + if (!appViewAgent) return server.app.bsky.graph.unmuteActorList({ auth: ctx.authVerifier.access, handler: async ({ auth, input }) => { const requester = auth.credentials.did - await ctx.appViewAgent.api.app.bsky.graph.unmuteActorList(input.body, { + await appViewAgent.api.app.bsky.graph.unmuteActorList(input.body, { ...(await ctx.appviewAuthHeaders(requester)), encoding: 'application/json', }) diff --git a/packages/pds/src/api/app/bsky/notification/getUnreadCount.ts b/packages/pds/src/api/app/bsky/notification/getUnreadCount.ts index 0827f47bb9e..d6b8a235ba3 100644 --- a/packages/pds/src/api/app/bsky/notification/getUnreadCount.ts +++ b/packages/pds/src/api/app/bsky/notification/getUnreadCount.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.notification.getUnreadCount({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.notification.getUnreadCount', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/notification/listNotifications.ts b/packages/pds/src/api/app/bsky/notification/listNotifications.ts index ad5d8635b41..005473eb6f4 100644 --- a/packages/pds/src/api/app/bsky/notification/listNotifications.ts +++ b/packages/pds/src/api/app/bsky/notification/listNotifications.ts @@ -3,12 +3,14 @@ import AppContext from '../../../../context' import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.notification.listNotifications({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.notification.listNotifications', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/notification/registerPush.ts b/packages/pds/src/api/app/bsky/notification/registerPush.ts index efe26ce9366..ec6084c41aa 100644 --- a/packages/pds/src/api/app/bsky/notification/registerPush.ts +++ b/packages/pds/src/api/app/bsky/notification/registerPush.ts @@ -6,6 +6,8 @@ import { AtpAgent } from '@atproto/api' import { getDidDoc } from '../util/resolver' export default function (server: Server, ctx: AppContext) { + const { appViewAgent } = ctx + if (!appViewAgent) return server.app.bsky.notification.registerPush({ auth: ctx.authVerifier.accessDeactived, handler: async ({ auth, input }) => { @@ -16,14 +18,11 @@ export default function (server: Server, ctx: AppContext) { const authHeaders = await ctx.serviceAuthHeaders(did, serviceDid) - if (ctx.cfg.bskyAppView.did === serviceDid) { - await ctx.appViewAgent.api.app.bsky.notification.registerPush( - input.body, - { - ...authHeaders, - encoding: 'application/json', - }, - ) + if (ctx.cfg.bskyAppView?.did === serviceDid) { + await appViewAgent.api.app.bsky.notification.registerPush(input.body, { + ...authHeaders, + encoding: 'application/json', + }) return } diff --git a/packages/pds/src/api/app/bsky/notification/updateSeen.ts b/packages/pds/src/api/app/bsky/notification/updateSeen.ts index dc0217ffb67..18a0ea3fa11 100644 --- a/packages/pds/src/api/app/bsky/notification/updateSeen.ts +++ b/packages/pds/src/api/app/bsky/notification/updateSeen.ts @@ -2,12 +2,14 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { + const { appViewAgent } = ctx + if (!appViewAgent) return server.app.bsky.notification.updateSeen({ auth: ctx.authVerifier.access, handler: async ({ input, auth }) => { const requester = auth.credentials.did - await ctx.appViewAgent.api.app.bsky.notification.updateSeen(input.body, { + await appViewAgent.api.app.bsky.notification.updateSeen(input.body, { ...(await ctx.appviewAuthHeaders(requester)), encoding: 'application/json', }) diff --git a/packages/pds/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts b/packages/pds/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts index 56f0c6134af..da7be6fb649 100644 --- a/packages/pds/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts +++ b/packages/pds/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts @@ -4,12 +4,14 @@ import { pipethrough } from '../../../../pipethrough' // THIS IS A TEMPORARY UNSPECCED ROUTE export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.unspecced.getPopularFeedGenerators({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.unspecced.getPopularFeedGenerators', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/unspecced/getTaggedSuggestions.ts b/packages/pds/src/api/app/bsky/unspecced/getTaggedSuggestions.ts index 80c868490c4..68e84985441 100644 --- a/packages/pds/src/api/app/bsky/unspecced/getTaggedSuggestions.ts +++ b/packages/pds/src/api/app/bsky/unspecced/getTaggedSuggestions.ts @@ -4,12 +4,14 @@ import { pipethrough } from '../../../../pipethrough' // THIS IS A TEMPORARY UNSPECCED ROUTE export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.unspecced.getTaggedSuggestions({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did return pipethrough( - ctx.cfg.bskyAppView.url, + bskyAppView.url, 'app.bsky.unspecced.getTaggedSuggestions', params, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/com/atproto/admin/createCommunicationTemplate.ts b/packages/pds/src/api/com/atproto/admin/createCommunicationTemplate.ts index 5d1c9bf1ee1..7b6939270a2 100644 --- a/packages/pds/src/api/com/atproto/admin/createCommunicationTemplate.ts +++ b/packages/pds/src/api/com/atproto/admin/createCommunicationTemplate.ts @@ -3,15 +3,16 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.createCommunicationTemplate({ auth: ctx.authVerifier.role, handler: async ({ req, input }) => { const { data: result } = - await ctx.moderationAgent.com.atproto.admin.createCommunicationTemplate( + await moderationAgent.com.atproto.admin.createCommunicationTemplate( input.body, authPassthru(req, true), ) - return { encoding: 'application/json', body: result, diff --git a/packages/pds/src/api/com/atproto/admin/deleteCommunicationTemplate.ts b/packages/pds/src/api/com/atproto/admin/deleteCommunicationTemplate.ts index 2f497f9089e..d10c2564571 100644 --- a/packages/pds/src/api/com/atproto/admin/deleteCommunicationTemplate.ts +++ b/packages/pds/src/api/com/atproto/admin/deleteCommunicationTemplate.ts @@ -3,10 +3,12 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.deleteCommunicationTemplate({ auth: ctx.authVerifier.role, handler: async ({ req, input }) => { - await ctx.moderationAgent.com.atproto.admin.deleteCommunicationTemplate( + await moderationAgent.com.atproto.admin.deleteCommunicationTemplate( input.body, authPassthru(req, true), ) diff --git a/packages/pds/src/api/com/atproto/admin/emitModerationEvent.ts b/packages/pds/src/api/com/atproto/admin/emitModerationEvent.ts index b2befdd53cc..65bb4c36d0e 100644 --- a/packages/pds/src/api/com/atproto/admin/emitModerationEvent.ts +++ b/packages/pds/src/api/com/atproto/admin/emitModerationEvent.ts @@ -3,15 +3,16 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.emitModerationEvent({ auth: ctx.authVerifier.role, handler: async ({ req, input }) => { const { data: result } = - await ctx.moderationAgent.com.atproto.admin.emitModerationEvent( + await moderationAgent.com.atproto.admin.emitModerationEvent( input.body, authPassthru(req, true), ) - return { encoding: 'application/json', body: result, diff --git a/packages/pds/src/api/com/atproto/admin/getModerationEvent.ts b/packages/pds/src/api/com/atproto/admin/getModerationEvent.ts index d368c3bfd72..a5e579baa58 100644 --- a/packages/pds/src/api/com/atproto/admin/getModerationEvent.ts +++ b/packages/pds/src/api/com/atproto/admin/getModerationEvent.ts @@ -3,11 +3,13 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.getModerationEvent({ auth: ctx.authVerifier.role, handler: async ({ req, params }) => { const { data } = - await ctx.moderationAgent.com.atproto.admin.getModerationEvent( + await moderationAgent.com.atproto.admin.getModerationEvent( params, authPassthru(req), ) diff --git a/packages/pds/src/api/com/atproto/admin/getRecord.ts b/packages/pds/src/api/com/atproto/admin/getRecord.ts index 90575354028..3cff5508683 100644 --- a/packages/pds/src/api/com/atproto/admin/getRecord.ts +++ b/packages/pds/src/api/com/atproto/admin/getRecord.ts @@ -3,11 +3,13 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.getRecord({ auth: ctx.authVerifier.role, handler: async ({ req, params }) => { const { data: recordDetailAppview } = - await ctx.moderationAgent.com.atproto.admin.getRecord( + await moderationAgent.com.atproto.admin.getRecord( params, authPassthru(req), ) diff --git a/packages/pds/src/api/com/atproto/admin/getRepo.ts b/packages/pds/src/api/com/atproto/admin/getRepo.ts index 85592c52b14..880b407ce79 100644 --- a/packages/pds/src/api/com/atproto/admin/getRepo.ts +++ b/packages/pds/src/api/com/atproto/admin/getRepo.ts @@ -3,10 +3,12 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.getRepo({ auth: ctx.authVerifier.role, handler: async ({ req, params }) => { - const res = await ctx.moderationAgent.com.atproto.admin.getRepo( + const res = await moderationAgent.com.atproto.admin.getRepo( params, authPassthru(req), ) diff --git a/packages/pds/src/api/com/atproto/admin/listCommunicationTemplates.ts b/packages/pds/src/api/com/atproto/admin/listCommunicationTemplates.ts index 41e5d025522..dfe3a74bce8 100644 --- a/packages/pds/src/api/com/atproto/admin/listCommunicationTemplates.ts +++ b/packages/pds/src/api/com/atproto/admin/listCommunicationTemplates.ts @@ -3,15 +3,16 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.listCommunicationTemplates({ auth: ctx.authVerifier.role, handler: async ({ req }) => { const { data: result } = - await ctx.moderationAgent.com.atproto.admin.listCommunicationTemplates( + await moderationAgent.com.atproto.admin.listCommunicationTemplates( {}, authPassthru(req, true), ) - return { encoding: 'application/json', body: result, diff --git a/packages/pds/src/api/com/atproto/admin/queryModerationEvents.ts b/packages/pds/src/api/com/atproto/admin/queryModerationEvents.ts index 00e12439649..2d33ca6d466 100644 --- a/packages/pds/src/api/com/atproto/admin/queryModerationEvents.ts +++ b/packages/pds/src/api/com/atproto/admin/queryModerationEvents.ts @@ -3,11 +3,13 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.queryModerationEvents({ auth: ctx.authVerifier.role, handler: async ({ req, params }) => { const { data: result } = - await ctx.moderationAgent.com.atproto.admin.queryModerationEvents( + await moderationAgent.com.atproto.admin.queryModerationEvents( params, authPassthru(req), ) diff --git a/packages/pds/src/api/com/atproto/admin/queryModerationStatuses.ts b/packages/pds/src/api/com/atproto/admin/queryModerationStatuses.ts index d2b2f36a1fe..c31125ce114 100644 --- a/packages/pds/src/api/com/atproto/admin/queryModerationStatuses.ts +++ b/packages/pds/src/api/com/atproto/admin/queryModerationStatuses.ts @@ -3,11 +3,13 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.queryModerationStatuses({ auth: ctx.authVerifier.role, handler: async ({ req, params }) => { const { data } = - await ctx.moderationAgent.com.atproto.admin.queryModerationStatuses( + await moderationAgent.com.atproto.admin.queryModerationStatuses( params, authPassthru(req), ) diff --git a/packages/pds/src/api/com/atproto/admin/searchRepos.ts b/packages/pds/src/api/com/atproto/admin/searchRepos.ts index 5e21b2ab894..d09ff7b2327 100644 --- a/packages/pds/src/api/com/atproto/admin/searchRepos.ts +++ b/packages/pds/src/api/com/atproto/admin/searchRepos.ts @@ -3,11 +3,13 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.searchRepos({ auth: ctx.authVerifier.role, handler: async ({ req, params }) => { const { data: result } = - await ctx.moderationAgent.com.atproto.admin.searchRepos( + await moderationAgent.com.atproto.admin.searchRepos( params, authPassthru(req), ) diff --git a/packages/pds/src/api/com/atproto/admin/sendEmail.ts b/packages/pds/src/api/com/atproto/admin/sendEmail.ts index b61e9e0d158..e23d6bea5c1 100644 --- a/packages/pds/src/api/com/atproto/admin/sendEmail.ts +++ b/packages/pds/src/api/com/atproto/admin/sendEmail.ts @@ -43,21 +43,25 @@ export default function (server: Server, ctx: AppContext) { { content }, { subject, to: account.email }, ) - await ctx.moderationAgent.api.com.atproto.admin.emitModerationEvent( - { - event: { - $type: 'com.atproto.admin.defs#modEventEmail', - subjectLine: subject, - comment, - }, - subject: { - $type: 'com.atproto.admin.defs#repoRef', - did: recipientDid, + + if (ctx.moderationAgent) { + await ctx.moderationAgent.api.com.atproto.admin.emitModerationEvent( + { + event: { + $type: 'com.atproto.admin.defs#modEventEmail', + subjectLine: subject, + comment, + }, + subject: { + $type: 'com.atproto.admin.defs#repoRef', + did: recipientDid, + }, + createdBy: senderDid, }, - createdBy: senderDid, - }, - { ...authPassthru(req), encoding: 'application/json' }, - ) + { ...authPassthru(req), encoding: 'application/json' }, + ) + } + return { encoding: 'application/json', body: { sent: true }, diff --git a/packages/pds/src/api/com/atproto/admin/updateCommunicationTemplate.ts b/packages/pds/src/api/com/atproto/admin/updateCommunicationTemplate.ts index abec4b275e6..c548a83bf03 100644 --- a/packages/pds/src/api/com/atproto/admin/updateCommunicationTemplate.ts +++ b/packages/pds/src/api/com/atproto/admin/updateCommunicationTemplate.ts @@ -3,11 +3,13 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.updateCommunicationTemplate({ auth: ctx.authVerifier.role, handler: async ({ req, input }) => { const { data: result } = - await ctx.moderationAgent.com.atproto.admin.updateCommunicationTemplate( + await moderationAgent.com.atproto.admin.updateCommunicationTemplate( input.body, authPassthru(req, true), ) diff --git a/packages/pds/src/api/com/atproto/identity/resolveHandle.ts b/packages/pds/src/api/com/atproto/identity/resolveHandle.ts index 67e0af41520..40122e2f3b6 100644 --- a/packages/pds/src/api/com/atproto/identity/resolveHandle.ts +++ b/packages/pds/src/api/com/atproto/identity/resolveHandle.ts @@ -33,7 +33,7 @@ export default function (server: Server, ctx: AppContext) { } // this is not someone on our server, but we help with resolving anyway - if (!did) { + if (!did && ctx.appViewAgent) { did = await tryResolveFromAppView(ctx.appViewAgent, handle) } diff --git a/packages/pds/src/api/com/atproto/moderation/createReport.ts b/packages/pds/src/api/com/atproto/moderation/createReport.ts index 7b3cc998e22..64ed5c20005 100644 --- a/packages/pds/src/api/com/atproto/moderation/createReport.ts +++ b/packages/pds/src/api/com/atproto/moderation/createReport.ts @@ -1,16 +1,22 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { InvalidRequestError } from '@atproto/xrpc-server' export default function (server: Server, ctx: AppContext) { server.com.atproto.moderation.createReport({ auth: ctx.authVerifier.accessCheckTakedown, handler: async ({ input, auth }) => { const requester = auth.credentials.did + if (!ctx.reportingAgent) { + throw new InvalidRequestError( + 'Your hosting service is not configured with a moderation provider. If this seems in error, reach out to your hosting provider.', + ) + } const { data: result } = - await ctx.moderationAgent.com.atproto.moderation.createReport( + await ctx.reportingAgent.com.atproto.moderation.createReport( input.body, { - ...(await ctx.moderationAuthHeaders(requester)), + ...(await ctx.reportingAuthHeaders(requester)), encoding: 'application/json', }, ) diff --git a/packages/pds/src/api/com/atproto/repo/getRecord.ts b/packages/pds/src/api/com/atproto/repo/getRecord.ts index 20abb3c46a8..3d8b44099d4 100644 --- a/packages/pds/src/api/com/atproto/repo/getRecord.ts +++ b/packages/pds/src/api/com/atproto/repo/getRecord.ts @@ -28,6 +28,10 @@ export default function (server: Server, ctx: AppContext) { } } + if (!ctx.cfg.bskyAppView) { + throw new InvalidRequestError(`Could not locate record`) + } + return await pipethrough( ctx.cfg.bskyAppView.url, 'com.atproto.repo.getRecord', diff --git a/packages/pds/src/auth-verifier.ts b/packages/pds/src/auth-verifier.ts index 9d1f7b8bd19..668791c187f 100644 --- a/packages/pds/src/auth-verifier.ts +++ b/packages/pds/src/auth-verifier.ts @@ -97,7 +97,7 @@ export type AuthVerifierOpts = { dids: { pds: string entryway?: string - admin: string + admin?: string } } @@ -254,6 +254,9 @@ export class AuthVerifier { } adminService = async (reqCtx: ReqCtx): Promise => { + if (!this.dids.admin) { + throw new AuthRequiredError('Untrusted issuer', 'UntrustedIss') + } const payload = await this.verifyServiceJwt(reqCtx, { aud: this.dids.entryway ?? this.dids.pds, iss: [this.dids.admin], diff --git a/packages/pds/src/config/config.ts b/packages/pds/src/config/config.ts index 34f113df985..e433f7ed251 100644 --- a/packages/pds/src/config/config.ts +++ b/packages/pds/src/config/config.ts @@ -168,19 +168,46 @@ export const envToCfg = (env: ServerEnvironment): ServerConfig => { repoBackfillLimitMs: env.repoBackfillLimitMs ?? DAY, } - assert(env.bskyAppViewUrl) - assert(env.bskyAppViewDid) - const bskyAppViewCfg: ServerConfig['bskyAppView'] = { - url: env.bskyAppViewUrl, - did: env.bskyAppViewDid, - cdnUrlPattern: env.bskyAppViewCdnUrlPattern, + let bskyAppViewCfg: ServerConfig['bskyAppView'] = null + if (env.bskyAppViewUrl) { + assert( + env.bskyAppViewDid, + 'if bsky appview service url is configured, must configure its did as well.', + ) + bskyAppViewCfg = { + url: env.bskyAppViewUrl, + did: env.bskyAppViewDid, + cdnUrlPattern: env.bskyAppViewCdnUrlPattern, + } } - assert(env.modServiceUrl) - assert(env.modServiceDid) - const modServiceCfg: ServerConfig['modService'] = { - url: env.modServiceUrl, - did: env.modServiceDid, + let modServiceCfg: ServerConfig['modService'] = null + if (env.modServiceUrl) { + assert( + env.modServiceDid, + 'if mod service url is configured, must configure its did as well.', + ) + modServiceCfg = { + url: env.modServiceUrl, + did: env.modServiceDid, + } + } + + let reportServiceCfg: ServerConfig['reportService'] = null + if (env.reportServiceUrl) { + assert( + env.reportServiceDid, + 'if report service url is configured, must configure its did as well.', + ) + reportServiceCfg = { + url: env.reportServiceUrl, + did: env.reportServiceDid, + } + } + + // if there's a mod service, default report service into it + if (modServiceCfg && !reportServiceCfg) { + reportServiceCfg = modServiceCfg } const redisCfg: ServerConfig['redis'] = env.redisScratchAddress @@ -216,6 +243,7 @@ export const envToCfg = (env: ServerEnvironment): ServerConfig => { subscription: subscriptionCfg, bskyAppView: bskyAppViewCfg, modService: modServiceCfg, + reportService: reportServiceCfg, redis: redisCfg, rateLimits: rateLimitsCfg, crawlers: crawlersCfg, @@ -233,8 +261,9 @@ export type ServerConfig = { email: EmailConfig | null moderationEmail: EmailConfig | null subscription: SubscriptionConfig - bskyAppView: BksyAppViewConfig - modService: ModServiceConfig + bskyAppView: BksyAppViewConfig | null + modService: ModServiceConfig | null + reportService: ReportServiceConfig | null redis: RedisScratchConfig | null rateLimits: RateLimitsConfig crawlers: string[] @@ -344,3 +373,8 @@ export type ModServiceConfig = { url: string did: string } + +export type ReportServiceConfig = { + url: string + did: string +} diff --git a/packages/pds/src/config/env.ts b/packages/pds/src/config/env.ts index d096cda994e..abe1904ad5f 100644 --- a/packages/pds/src/config/env.ts +++ b/packages/pds/src/config/env.ts @@ -76,6 +76,10 @@ export const readEnv = (): ServerEnvironment => { modServiceUrl: envStr('PDS_MOD_SERVICE_URL'), modServiceDid: envStr('PDS_MOD_SERVICE_DID'), + // report service + reportServiceUrl: envStr('PDS_REPORT_SERVICE_URL'), + reportServiceDid: envStr('PDS_REPORT_SERVICE_DID'), + // rate limits rateLimitsEnabled: envBool('PDS_RATE_LIMITS_ENABLED'), rateLimitBypassKey: envStr('PDS_RATE_LIMIT_BYPASS_KEY'), @@ -176,6 +180,10 @@ export type ServerEnvironment = { modServiceUrl?: string modServiceDid?: string + // report service + reportServiceUrl?: string + reportServiceDid?: string + // rate limits rateLimitsEnabled?: boolean rateLimitBypassKey?: string diff --git a/packages/pds/src/context.ts b/packages/pds/src/context.ts index 6a5b2927df1..a9fe996056f 100644 --- a/packages/pds/src/context.ts +++ b/packages/pds/src/context.ts @@ -1,3 +1,4 @@ +import assert from 'node:assert' import * as nodemailer from 'nodemailer' import { Redis } from 'ioredis' import * as plc from '@did-plc/lib' @@ -42,8 +43,9 @@ export type AppContextOptions = { backgroundQueue: BackgroundQueue redisScratch?: Redis crawlers: Crawlers - appViewAgent: AtpAgent - moderationAgent: AtpAgent + appViewAgent?: AtpAgent + moderationAgent?: AtpAgent + reportingAgent?: AtpAgent entrywayAgent?: AtpAgent authVerifier: AuthVerifier plcRotationKey: crypto.Keypair @@ -67,8 +69,9 @@ export class AppContext { public backgroundQueue: BackgroundQueue public redisScratch?: Redis public crawlers: Crawlers - public appViewAgent: AtpAgent - public moderationAgent: AtpAgent + public appViewAgent: AtpAgent | undefined + public moderationAgent: AtpAgent | undefined + public reportingAgent: AtpAgent | undefined public entrywayAgent: AtpAgent | undefined public authVerifier: AuthVerifier public plcRotationKey: crypto.Keypair @@ -90,6 +93,7 @@ export class AppContext { this.crawlers = opts.crawlers this.appViewAgent = opts.appViewAgent this.moderationAgent = opts.moderationAgent + this.reportingAgent = opts.reportingAgent this.entrywayAgent = opts.entrywayAgent this.authVerifier = opts.authVerifier this.plcRotationKey = opts.plcRotationKey @@ -161,9 +165,15 @@ export class AppContext { ? getRedisClient(cfg.redis.address, cfg.redis.password) : undefined - const appViewAgent = new AtpAgent({ service: cfg.bskyAppView.url }) - const moderationAgent = new AtpAgent({ service: cfg.modService.url }) - + const appViewAgent = cfg.bskyAppView + ? new AtpAgent({ service: cfg.bskyAppView.url }) + : undefined + const moderationAgent = cfg.modService + ? new AtpAgent({ service: cfg.modService.url }) + : undefined + const reportingAgent = cfg.reportService + ? new AtpAgent({ service: cfg.reportService.url }) + : undefined const entrywayAgent = cfg.entryway ? new AtpAgent({ service: cfg.entryway.url }) : undefined @@ -189,7 +199,7 @@ export class AppContext { dids: { pds: cfg.service.did, entryway: cfg.entryway?.did, - admin: cfg.modService.did, + admin: cfg.modService?.did, }, }) @@ -211,8 +221,8 @@ export class AppContext { accountManager, appViewAgent, pdsHostname: cfg.service.hostname, - appviewDid: cfg.bskyAppView.did, - appviewCdnUrlPattern: cfg.bskyAppView.cdnUrlPattern, + appviewDid: cfg.bskyAppView?.did, + appviewCdnUrlPattern: cfg.bskyAppView?.cdnUrlPattern, }) return new AppContext({ @@ -231,6 +241,7 @@ export class AppContext { crawlers, appViewAgent, moderationAgent, + reportingAgent, entrywayAgent, authVerifier, plcRotationKey, @@ -240,13 +251,20 @@ export class AppContext { } async appviewAuthHeaders(did: string) { + assert(this.cfg.bskyAppView) return this.serviceAuthHeaders(did, this.cfg.bskyAppView.did) } async moderationAuthHeaders(did: string) { + assert(this.cfg.modService) return this.serviceAuthHeaders(did, this.cfg.modService.did) } + async reportingAuthHeaders(did: string) { + assert(this.cfg.reportService) + return this.serviceAuthHeaders(did, this.cfg.reportService.did) + } + async serviceAuthHeaders(did: string, aud: string) { const keypair = await this.actorStore.keypair(did) return createServiceAuthHeaders({ diff --git a/packages/pds/tests/proxied/read-after-write.test.ts b/packages/pds/tests/proxied/read-after-write.test.ts index ca01b135c5b..1bd6a463c34 100644 --- a/packages/pds/tests/proxied/read-after-write.test.ts +++ b/packages/pds/tests/proxied/read-after-write.test.ts @@ -1,4 +1,5 @@ -import util from 'util' +import util from 'node:util' +import assert from 'node:assert' import AtpAgent from '@atproto/api' import { TestNetwork, SeedClient, RecordRef } from '@atproto/dev-env' import basicSeed from '../seeds/basic' @@ -43,6 +44,7 @@ describe('proxy read after write', () => { }) it('handles image formatting', async () => { + assert(network.pds.ctx.cfg.bskyAppView) const blob = await sc.uploadFile( alice, '../dev-env/src/seed/img/key-landscape-small.jpg', @@ -123,6 +125,7 @@ describe('proxy read after write', () => { }) it('handles read after write on threads with record embeds', async () => { + assert(network.pds.ctx.cfg.bskyAppView) const img = await sc.uploadFile( alice, '../dev-env/src/seed/img/key-landscape-small.jpg',