diff --git a/packages/pds/src/api/app/bsky/actor/getPreferences.ts b/packages/pds/src/api/app/bsky/actor/getPreferences.ts index 1bca50f0bd1..cb595508764 100644 --- a/packages/pds/src/api/app/bsky/actor/getPreferences.ts +++ b/packages/pds/src/api/app/bsky/actor/getPreferences.ts @@ -1,10 +1,10 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' -import { AuthScope } from '../../../../auth' +import { AuthScope } from '../../../../auth-verifier' export default function (server: Server, ctx: AppContext) { server.app.bsky.actor.getPreferences({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth }) => { const requester = auth.credentials.did const { services, db } = ctx diff --git a/packages/pds/src/api/app/bsky/actor/getProfile.ts b/packages/pds/src/api/app/bsky/actor/getProfile.ts index c200e1dd75f..9dd4b028983 100644 --- a/packages/pds/src/api/app/bsky/actor/getProfile.ts +++ b/packages/pds/src/api/app/bsky/actor/getProfile.ts @@ -7,7 +7,7 @@ import { LocalRecords } from '../../../../services/local' export default function (server: Server, ctx: AppContext) { server.app.bsky.actor.getProfile({ - auth: ctx.accessOrRoleVerifier, + auth: ctx.authVerifier.accessOrRole, handler: async ({ req, auth, params }) => { const requester = auth.credentials.type === 'access' ? auth.credentials.did : null diff --git a/packages/pds/src/api/app/bsky/actor/getProfiles.ts b/packages/pds/src/api/app/bsky/actor/getProfiles.ts index ebec9e36938..0af2bff9564 100644 --- a/packages/pds/src/api/app/bsky/actor/getProfiles.ts +++ b/packages/pds/src/api/app/bsky/actor/getProfiles.ts @@ -6,7 +6,7 @@ import { handleReadAfterWrite } from '../util/read-after-write' export default function (server: Server, ctx: AppContext) { server.app.bsky.actor.getProfiles({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.actor.getProfiles( diff --git a/packages/pds/src/api/app/bsky/actor/getSuggestions.ts b/packages/pds/src/api/app/bsky/actor/getSuggestions.ts index e6c72e5c830..70f6bb6adef 100644 --- a/packages/pds/src/api/app/bsky/actor/getSuggestions.ts +++ b/packages/pds/src/api/app/bsky/actor/getSuggestions.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.actor.getSuggestions({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.actor.getSuggestions( diff --git a/packages/pds/src/api/app/bsky/actor/putPreferences.ts b/packages/pds/src/api/app/bsky/actor/putPreferences.ts index 27528595116..7f7bdd86e39 100644 --- a/packages/pds/src/api/app/bsky/actor/putPreferences.ts +++ b/packages/pds/src/api/app/bsky/actor/putPreferences.ts @@ -5,7 +5,7 @@ import { InvalidRequestError } from '@atproto/xrpc-server' export default function (server: Server, ctx: AppContext) { server.app.bsky.actor.putPreferences({ - auth: ctx.accessVerifierCheckTakedown, + auth: ctx.authVerifier.accessCheckTakedown, handler: async ({ auth, input }) => { const { preferences } = input.body const requester = auth.credentials.did diff --git a/packages/pds/src/api/app/bsky/actor/searchActors.ts b/packages/pds/src/api/app/bsky/actor/searchActors.ts index 3f1bd2355d6..86b028f5242 100644 --- a/packages/pds/src/api/app/bsky/actor/searchActors.ts +++ b/packages/pds/src/api/app/bsky/actor/searchActors.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.actor.searchActors({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.actor.searchActors( diff --git a/packages/pds/src/api/app/bsky/actor/searchActorsTypeahead.ts b/packages/pds/src/api/app/bsky/actor/searchActorsTypeahead.ts index a637aea69c7..9e969c4700a 100644 --- a/packages/pds/src/api/app/bsky/actor/searchActorsTypeahead.ts +++ b/packages/pds/src/api/app/bsky/actor/searchActorsTypeahead.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.actor.searchActorsTypeahead({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did const res = diff --git a/packages/pds/src/api/app/bsky/feed/getActorFeeds.ts b/packages/pds/src/api/app/bsky/feed/getActorFeeds.ts index da99617178f..1a5f3a15ed3 100644 --- a/packages/pds/src/api/app/bsky/feed/getActorFeeds.ts +++ b/packages/pds/src/api/app/bsky/feed/getActorFeeds.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.feed.getActorFeeds({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.feed.getActorFeeds( diff --git a/packages/pds/src/api/app/bsky/feed/getActorLikes.ts b/packages/pds/src/api/app/bsky/feed/getActorLikes.ts index 9c0c38c5a20..4029dbc74dd 100644 --- a/packages/pds/src/api/app/bsky/feed/getActorLikes.ts +++ b/packages/pds/src/api/app/bsky/feed/getActorLikes.ts @@ -7,7 +7,7 @@ import { LocalRecords } from '../../../../services/local' export default function (server: Server, ctx: AppContext) { server.app.bsky.feed.getActorLikes({ - auth: ctx.accessOrRoleVerifier, + auth: ctx.authVerifier.accessOrRole, handler: async ({ req, params, auth }) => { const requester = auth.credentials.type === 'access' ? auth.credentials.did : null diff --git a/packages/pds/src/api/app/bsky/feed/getAuthorFeed.ts b/packages/pds/src/api/app/bsky/feed/getAuthorFeed.ts index 6563812fb9a..d887d5bae89 100644 --- a/packages/pds/src/api/app/bsky/feed/getAuthorFeed.ts +++ b/packages/pds/src/api/app/bsky/feed/getAuthorFeed.ts @@ -8,7 +8,7 @@ import { isReasonRepost } from '../../../../lexicon/types/app/bsky/feed/defs' export default function (server: Server, ctx: AppContext) { server.app.bsky.feed.getAuthorFeed({ - auth: ctx.accessOrRoleVerifier, + auth: ctx.authVerifier.accessOrRole, handler: async ({ req, params, auth }) => { const requester = auth.credentials.type === 'access' ? auth.credentials.did : null diff --git a/packages/pds/src/api/app/bsky/feed/getFeed.ts b/packages/pds/src/api/app/bsky/feed/getFeed.ts index 051b0c7bcdf..3a768905dc2 100644 --- a/packages/pds/src/api/app/bsky/feed/getFeed.ts +++ b/packages/pds/src/api/app/bsky/feed/getFeed.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.feed.getFeed({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did diff --git a/packages/pds/src/api/app/bsky/feed/getFeedGenerator.ts b/packages/pds/src/api/app/bsky/feed/getFeedGenerator.ts index 28c404b58e8..78ee243bc08 100644 --- a/packages/pds/src/api/app/bsky/feed/getFeedGenerator.ts +++ b/packages/pds/src/api/app/bsky/feed/getFeedGenerator.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.feed.getFeedGenerator({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.feed.getFeedGenerator( diff --git a/packages/pds/src/api/app/bsky/feed/getFeedGenerators.ts b/packages/pds/src/api/app/bsky/feed/getFeedGenerators.ts index 12cf9e91c0a..064525afcec 100644 --- a/packages/pds/src/api/app/bsky/feed/getFeedGenerators.ts +++ b/packages/pds/src/api/app/bsky/feed/getFeedGenerators.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.feed.getFeedGenerators({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.feed.getFeedGenerators( diff --git a/packages/pds/src/api/app/bsky/feed/getLikes.ts b/packages/pds/src/api/app/bsky/feed/getLikes.ts index 771cc511cd4..20d96690ac6 100644 --- a/packages/pds/src/api/app/bsky/feed/getLikes.ts +++ b/packages/pds/src/api/app/bsky/feed/getLikes.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.feed.getLikes({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.feed.getLikes( diff --git a/packages/pds/src/api/app/bsky/feed/getListFeed.ts b/packages/pds/src/api/app/bsky/feed/getListFeed.ts index 34b8630a933..7cc5d1f2bd2 100644 --- a/packages/pds/src/api/app/bsky/feed/getListFeed.ts +++ b/packages/pds/src/api/app/bsky/feed/getListFeed.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.feed.getListFeed({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.feed.getListFeed( diff --git a/packages/pds/src/api/app/bsky/feed/getPostThread.ts b/packages/pds/src/api/app/bsky/feed/getPostThread.ts index 270c1044497..01670e9e9ad 100644 --- a/packages/pds/src/api/app/bsky/feed/getPostThread.ts +++ b/packages/pds/src/api/app/bsky/feed/getPostThread.ts @@ -26,7 +26,7 @@ import { authPassthru } from '../../../com/atproto/admin/util' export default function (server: Server, ctx: AppContext) { server.app.bsky.feed.getPostThread({ - auth: ctx.accessOrRoleVerifier, + auth: ctx.authVerifier.accessOrRole, handler: async ({ req, params, auth }) => { const requester = auth.credentials.type === 'access' ? auth.credentials.did : null diff --git a/packages/pds/src/api/app/bsky/feed/getPosts.ts b/packages/pds/src/api/app/bsky/feed/getPosts.ts index 1b755450f63..2f7a75d71fc 100644 --- a/packages/pds/src/api/app/bsky/feed/getPosts.ts +++ b/packages/pds/src/api/app/bsky/feed/getPosts.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.feed.getPosts({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.feed.getPosts( diff --git a/packages/pds/src/api/app/bsky/feed/getRepostedBy.ts b/packages/pds/src/api/app/bsky/feed/getRepostedBy.ts index 30e72b434e6..b84a9dc27b7 100644 --- a/packages/pds/src/api/app/bsky/feed/getRepostedBy.ts +++ b/packages/pds/src/api/app/bsky/feed/getRepostedBy.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.feed.getRepostedBy({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.feed.getRepostedBy( diff --git a/packages/pds/src/api/app/bsky/feed/getSuggestedFeeds.ts b/packages/pds/src/api/app/bsky/feed/getSuggestedFeeds.ts index 733405b3b42..179570f6d4f 100644 --- a/packages/pds/src/api/app/bsky/feed/getSuggestedFeeds.ts +++ b/packages/pds/src/api/app/bsky/feed/getSuggestedFeeds.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.feed.getSuggestedFeeds({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.feed.getSuggestedFeeds( diff --git a/packages/pds/src/api/app/bsky/feed/getTimeline.ts b/packages/pds/src/api/app/bsky/feed/getTimeline.ts index 2c3e2ed44d6..33cdafb9f25 100644 --- a/packages/pds/src/api/app/bsky/feed/getTimeline.ts +++ b/packages/pds/src/api/app/bsky/feed/getTimeline.ts @@ -6,7 +6,7 @@ import { LocalRecords } from '../../../../services/local' export default function (server: Server, ctx: AppContext) { server.app.bsky.feed.getTimeline({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.feed.getTimeline( diff --git a/packages/pds/src/api/app/bsky/graph/getBlocks.ts b/packages/pds/src/api/app/bsky/graph/getBlocks.ts index f66eb64b945..14aa3b3de5f 100644 --- a/packages/pds/src/api/app/bsky/graph/getBlocks.ts +++ b/packages/pds/src/api/app/bsky/graph/getBlocks.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.graph.getBlocks({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.graph.getBlocks( diff --git a/packages/pds/src/api/app/bsky/graph/getFollowers.ts b/packages/pds/src/api/app/bsky/graph/getFollowers.ts index 389f92d4e14..fd3a7612454 100644 --- a/packages/pds/src/api/app/bsky/graph/getFollowers.ts +++ b/packages/pds/src/api/app/bsky/graph/getFollowers.ts @@ -4,7 +4,7 @@ import { authPassthru } from '../../../../api/com/atproto/admin/util' export default function (server: Server, ctx: AppContext) { server.app.bsky.graph.getFollowers({ - auth: ctx.accessOrRoleVerifier, + auth: ctx.authVerifier.accessOrRole, handler: async ({ req, params, auth }) => { const requester = auth.credentials.type === 'access' ? auth.credentials.did : null diff --git a/packages/pds/src/api/app/bsky/graph/getFollows.ts b/packages/pds/src/api/app/bsky/graph/getFollows.ts index 343fd81d414..31936dc879e 100644 --- a/packages/pds/src/api/app/bsky/graph/getFollows.ts +++ b/packages/pds/src/api/app/bsky/graph/getFollows.ts @@ -4,7 +4,7 @@ import { authPassthru } from '../../../../api/com/atproto/admin/util' export default function (server: Server, ctx: AppContext) { server.app.bsky.graph.getFollows({ - auth: ctx.accessOrRoleVerifier, + auth: ctx.authVerifier.accessOrRole, handler: async ({ req, params, auth }) => { const requester = auth.credentials.type === 'access' ? auth.credentials.did : null diff --git a/packages/pds/src/api/app/bsky/graph/getList.ts b/packages/pds/src/api/app/bsky/graph/getList.ts index 061d6759c2c..6b4f3762d38 100644 --- a/packages/pds/src/api/app/bsky/graph/getList.ts +++ b/packages/pds/src/api/app/bsky/graph/getList.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.graph.getList({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.graph.getList( diff --git a/packages/pds/src/api/app/bsky/graph/getListBlocks.ts b/packages/pds/src/api/app/bsky/graph/getListBlocks.ts index 83975782fa4..4e1ba8de8ca 100644 --- a/packages/pds/src/api/app/bsky/graph/getListBlocks.ts +++ b/packages/pds/src/api/app/bsky/graph/getListBlocks.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.graph.getListBlocks({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.graph.getListBlocks( diff --git a/packages/pds/src/api/app/bsky/graph/getListMutes.ts b/packages/pds/src/api/app/bsky/graph/getListMutes.ts index 05f6ce1ab09..fc0d8c2f051 100644 --- a/packages/pds/src/api/app/bsky/graph/getListMutes.ts +++ b/packages/pds/src/api/app/bsky/graph/getListMutes.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.graph.getListMutes({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.graph.getListMutes( diff --git a/packages/pds/src/api/app/bsky/graph/getLists.ts b/packages/pds/src/api/app/bsky/graph/getLists.ts index 6c8f6452ea4..0c680321f9c 100644 --- a/packages/pds/src/api/app/bsky/graph/getLists.ts +++ b/packages/pds/src/api/app/bsky/graph/getLists.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.graph.getLists({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.graph.getLists( diff --git a/packages/pds/src/api/app/bsky/graph/getMutes.ts b/packages/pds/src/api/app/bsky/graph/getMutes.ts index 12ff1a032a0..51177137b3a 100644 --- a/packages/pds/src/api/app/bsky/graph/getMutes.ts +++ b/packages/pds/src/api/app/bsky/graph/getMutes.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.graph.getMutes({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did const res = await ctx.appViewAgent.api.app.bsky.graph.getMutes( diff --git a/packages/pds/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts b/packages/pds/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts index 53125cbc517..b8d578bfd25 100644 --- a/packages/pds/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts +++ b/packages/pds/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.graph.getSuggestedFollowsByActor({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did const res = diff --git a/packages/pds/src/api/app/bsky/graph/muteActor.ts b/packages/pds/src/api/app/bsky/graph/muteActor.ts index 9f753bac926..7e38d21ee42 100644 --- a/packages/pds/src/api/app/bsky/graph/muteActor.ts +++ b/packages/pds/src/api/app/bsky/graph/muteActor.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.graph.muteActor({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth, input }) => { const requester = auth.credentials.did diff --git a/packages/pds/src/api/app/bsky/graph/muteActorList.ts b/packages/pds/src/api/app/bsky/graph/muteActorList.ts index 441571a26b9..c224d85e3f3 100644 --- a/packages/pds/src/api/app/bsky/graph/muteActorList.ts +++ b/packages/pds/src/api/app/bsky/graph/muteActorList.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.graph.muteActorList({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth, input }) => { const requester = auth.credentials.did diff --git a/packages/pds/src/api/app/bsky/graph/unmuteActor.ts b/packages/pds/src/api/app/bsky/graph/unmuteActor.ts index 586b12565d6..37166420f31 100644 --- a/packages/pds/src/api/app/bsky/graph/unmuteActor.ts +++ b/packages/pds/src/api/app/bsky/graph/unmuteActor.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.graph.unmuteActor({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth, input }) => { const requester = auth.credentials.did diff --git a/packages/pds/src/api/app/bsky/graph/unmuteActorList.ts b/packages/pds/src/api/app/bsky/graph/unmuteActorList.ts index e8ba9f8c4d4..0dea669feb6 100644 --- a/packages/pds/src/api/app/bsky/graph/unmuteActorList.ts +++ b/packages/pds/src/api/app/bsky/graph/unmuteActorList.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.graph.unmuteActorList({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth, input }) => { const requester = auth.credentials.did diff --git a/packages/pds/src/api/app/bsky/notification/getUnreadCount.ts b/packages/pds/src/api/app/bsky/notification/getUnreadCount.ts index c8b723403d5..da8be8aec50 100644 --- a/packages/pds/src/api/app/bsky/notification/getUnreadCount.ts +++ b/packages/pds/src/api/app/bsky/notification/getUnreadCount.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.notification.getUnreadCount({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did const res = diff --git a/packages/pds/src/api/app/bsky/notification/listNotifications.ts b/packages/pds/src/api/app/bsky/notification/listNotifications.ts index 48e75304af5..21f4e8db642 100644 --- a/packages/pds/src/api/app/bsky/notification/listNotifications.ts +++ b/packages/pds/src/api/app/bsky/notification/listNotifications.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.notification.listNotifications({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did const res = diff --git a/packages/pds/src/api/app/bsky/notification/registerPush.ts b/packages/pds/src/api/app/bsky/notification/registerPush.ts index d5db39f1ac7..e6a5bf1b14f 100644 --- a/packages/pds/src/api/app/bsky/notification/registerPush.ts +++ b/packages/pds/src/api/app/bsky/notification/registerPush.ts @@ -7,7 +7,7 @@ import { getDidDoc } from '../util/resolver' export default function (server: Server, ctx: AppContext) { server.app.bsky.notification.registerPush({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth, input }) => { const { serviceDid } = input.body const { diff --git a/packages/pds/src/api/app/bsky/notification/updateSeen.ts b/packages/pds/src/api/app/bsky/notification/updateSeen.ts index 44fe4bc13cc..3678cacd37f 100644 --- a/packages/pds/src/api/app/bsky/notification/updateSeen.ts +++ b/packages/pds/src/api/app/bsky/notification/updateSeen.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.app.bsky.notification.updateSeen({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ input, auth }) => { const requester = auth.credentials.did diff --git a/packages/pds/src/api/app/bsky/unspecced/getPopular.ts b/packages/pds/src/api/app/bsky/unspecced/getPopular.ts index f890ea7baed..0ba5a8f7b60 100644 --- a/packages/pds/src/api/app/bsky/unspecced/getPopular.ts +++ b/packages/pds/src/api/app/bsky/unspecced/getPopular.ts @@ -4,7 +4,7 @@ import AppContext from '../../../../context' // THIS IS A TEMPORARY UNSPECCED ROUTE export default function (server: Server, ctx: AppContext) { server.app.bsky.unspecced.getPopular({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did const HOT_CLASSIC_URI = diff --git a/packages/pds/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts b/packages/pds/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts index abc556cdb70..0d7eb366a03 100644 --- a/packages/pds/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts +++ b/packages/pds/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts @@ -4,7 +4,7 @@ import AppContext from '../../../../context' // THIS IS A TEMPORARY UNSPECCED ROUTE export default function (server: Server, ctx: AppContext) { server.app.bsky.unspecced.getPopularFeedGenerators({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did const res = diff --git a/packages/pds/src/api/com/atproto/admin/disableAccountInvites.ts b/packages/pds/src/api/com/atproto/admin/disableAccountInvites.ts index 9c2b64b9697..17e0ac01198 100644 --- a/packages/pds/src/api/com/atproto/admin/disableAccountInvites.ts +++ b/packages/pds/src/api/com/atproto/admin/disableAccountInvites.ts @@ -4,7 +4,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.disableAccountInvites({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ input, auth }) => { if (!auth.credentials.admin) { throw new AuthRequiredError('Insufficient privileges') diff --git a/packages/pds/src/api/com/atproto/admin/disableInviteCodes.ts b/packages/pds/src/api/com/atproto/admin/disableInviteCodes.ts index d1fd4658b43..d9d8516b88f 100644 --- a/packages/pds/src/api/com/atproto/admin/disableInviteCodes.ts +++ b/packages/pds/src/api/com/atproto/admin/disableInviteCodes.ts @@ -4,7 +4,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.disableInviteCodes({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ input, auth }) => { if (!auth.credentials.admin) { throw new AuthRequiredError('Insufficient privileges') diff --git a/packages/pds/src/api/com/atproto/admin/enableAccountInvites.ts b/packages/pds/src/api/com/atproto/admin/enableAccountInvites.ts index 1bb588368e4..073404455f1 100644 --- a/packages/pds/src/api/com/atproto/admin/enableAccountInvites.ts +++ b/packages/pds/src/api/com/atproto/admin/enableAccountInvites.ts @@ -4,7 +4,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.enableAccountInvites({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ input, auth }) => { if (!auth.credentials.admin) { throw new AuthRequiredError('Insufficient privileges') diff --git a/packages/pds/src/api/com/atproto/admin/getInviteCodes.ts b/packages/pds/src/api/com/atproto/admin/getInviteCodes.ts index 02e9c0af82f..2c584281d5a 100644 --- a/packages/pds/src/api/com/atproto/admin/getInviteCodes.ts +++ b/packages/pds/src/api/com/atproto/admin/getInviteCodes.ts @@ -10,7 +10,7 @@ import { export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.getInviteCodes({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ params }) => { const { sort, limit, cursor } = params const ref = ctx.db.db.dynamic.ref diff --git a/packages/pds/src/api/com/atproto/admin/getModerationAction.ts b/packages/pds/src/api/com/atproto/admin/getModerationAction.ts index 258ca9d94a1..02d14a0ce1c 100644 --- a/packages/pds/src/api/com/atproto/admin/getModerationAction.ts +++ b/packages/pds/src/api/com/atproto/admin/getModerationAction.ts @@ -5,7 +5,7 @@ import { isRepoView } from '../../../../lexicon/types/com/atproto/admin/defs' export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.getModerationAction({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ req, params, auth }) => { const access = auth.credentials const { db, services } = ctx diff --git a/packages/pds/src/api/com/atproto/admin/getModerationActions.ts b/packages/pds/src/api/com/atproto/admin/getModerationActions.ts index 0ef48e99851..f36f44c4917 100644 --- a/packages/pds/src/api/com/atproto/admin/getModerationActions.ts +++ b/packages/pds/src/api/com/atproto/admin/getModerationActions.ts @@ -4,7 +4,7 @@ import { authPassthru } from './util' export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.getModerationActions({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ req, params }) => { if (ctx.cfg.bskyAppView.proxyModeration) { const { data: result } = diff --git a/packages/pds/src/api/com/atproto/admin/getModerationReport.ts b/packages/pds/src/api/com/atproto/admin/getModerationReport.ts index b75268ebdf8..11a7a943542 100644 --- a/packages/pds/src/api/com/atproto/admin/getModerationReport.ts +++ b/packages/pds/src/api/com/atproto/admin/getModerationReport.ts @@ -5,7 +5,7 @@ import { isRepoView } from '../../../../lexicon/types/com/atproto/admin/defs' export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.getModerationReport({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ req, params, auth }) => { const access = auth.credentials const { db, services } = ctx diff --git a/packages/pds/src/api/com/atproto/admin/getModerationReports.ts b/packages/pds/src/api/com/atproto/admin/getModerationReports.ts index 2d5dd329bc4..20a7bb6c88d 100644 --- a/packages/pds/src/api/com/atproto/admin/getModerationReports.ts +++ b/packages/pds/src/api/com/atproto/admin/getModerationReports.ts @@ -4,7 +4,7 @@ import { authPassthru } from './util' export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.getModerationReports({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ req, params }) => { if (ctx.cfg.bskyAppView.proxyModeration) { const { data: result } = diff --git a/packages/pds/src/api/com/atproto/admin/getRecord.ts b/packages/pds/src/api/com/atproto/admin/getRecord.ts index b68d01aefda..9ec3a0606ae 100644 --- a/packages/pds/src/api/com/atproto/admin/getRecord.ts +++ b/packages/pds/src/api/com/atproto/admin/getRecord.ts @@ -6,7 +6,7 @@ import { authPassthru, mergeRepoViewPdsDetails } from './util' export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.getRecord({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ req, params, auth }) => { const access = auth.credentials const { db, services } = ctx diff --git a/packages/pds/src/api/com/atproto/admin/getRepo.ts b/packages/pds/src/api/com/atproto/admin/getRepo.ts index 19e07862851..9c786772a36 100644 --- a/packages/pds/src/api/com/atproto/admin/getRepo.ts +++ b/packages/pds/src/api/com/atproto/admin/getRepo.ts @@ -5,7 +5,7 @@ import { authPassthru, mergeRepoViewPdsDetails } from './util' export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.getRepo({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ req, params, auth }) => { const access = auth.credentials const { db, services } = ctx diff --git a/packages/pds/src/api/com/atproto/admin/resolveModerationReports.ts b/packages/pds/src/api/com/atproto/admin/resolveModerationReports.ts index 52279745e46..229433fa50c 100644 --- a/packages/pds/src/api/com/atproto/admin/resolveModerationReports.ts +++ b/packages/pds/src/api/com/atproto/admin/resolveModerationReports.ts @@ -4,7 +4,7 @@ import { authPassthru } from './util' export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.resolveModerationReports({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ req, input }) => { if (ctx.cfg.bskyAppView.proxyModeration) { const { data: result } = diff --git a/packages/pds/src/api/com/atproto/admin/reverseModerationAction.ts b/packages/pds/src/api/com/atproto/admin/reverseModerationAction.ts index a8e8d62a3ad..dc5a22e600e 100644 --- a/packages/pds/src/api/com/atproto/admin/reverseModerationAction.ts +++ b/packages/pds/src/api/com/atproto/admin/reverseModerationAction.ts @@ -13,7 +13,7 @@ import { authPassthru } from './util' export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.reverseModerationAction({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ req, input, auth }) => { const access = auth.credentials const { db, services } = ctx diff --git a/packages/pds/src/api/com/atproto/admin/searchRepos.ts b/packages/pds/src/api/com/atproto/admin/searchRepos.ts index da2d7fa3788..8195c8c2d98 100644 --- a/packages/pds/src/api/com/atproto/admin/searchRepos.ts +++ b/packages/pds/src/api/com/atproto/admin/searchRepos.ts @@ -6,7 +6,7 @@ import { authPassthru } from './util' export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.searchRepos({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ req, params, auth }) => { if (ctx.cfg.bskyAppView.proxyModeration) { // @TODO merge invite details to this list view. could also add diff --git a/packages/pds/src/api/com/atproto/admin/sendEmail.ts b/packages/pds/src/api/com/atproto/admin/sendEmail.ts index 2d8c400ff95..b1d53c9db44 100644 --- a/packages/pds/src/api/com/atproto/admin/sendEmail.ts +++ b/packages/pds/src/api/com/atproto/admin/sendEmail.ts @@ -4,7 +4,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.sendEmail({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ input, auth }) => { if (!auth.credentials.admin && !auth.credentials.moderator) { throw new AuthRequiredError('Insufficient privileges') diff --git a/packages/pds/src/api/com/atproto/admin/takeModerationAction.ts b/packages/pds/src/api/com/atproto/admin/takeModerationAction.ts index fb593b1c957..d81bd0233f3 100644 --- a/packages/pds/src/api/com/atproto/admin/takeModerationAction.ts +++ b/packages/pds/src/api/com/atproto/admin/takeModerationAction.ts @@ -15,7 +15,7 @@ import { authPassthru } from './util' export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.takeModerationAction({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ req, input, auth }) => { const access = auth.credentials const { db, services } = ctx diff --git a/packages/pds/src/api/com/atproto/admin/updateAccountEmail.ts b/packages/pds/src/api/com/atproto/admin/updateAccountEmail.ts index 851613a6bad..04bb8bdfb1a 100644 --- a/packages/pds/src/api/com/atproto/admin/updateAccountEmail.ts +++ b/packages/pds/src/api/com/atproto/admin/updateAccountEmail.ts @@ -4,7 +4,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.updateAccountEmail({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ input, auth }) => { if (!auth.credentials.admin) { throw new AuthRequiredError('Insufficient privileges') diff --git a/packages/pds/src/api/com/atproto/admin/updateAccountHandle.ts b/packages/pds/src/api/com/atproto/admin/updateAccountHandle.ts index 44c2ee5d8b1..368c2dae586 100644 --- a/packages/pds/src/api/com/atproto/admin/updateAccountHandle.ts +++ b/packages/pds/src/api/com/atproto/admin/updateAccountHandle.ts @@ -10,7 +10,7 @@ import { httpLogger } from '../../../../logger' export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.updateAccountHandle({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ input, auth }) => { if (!auth.credentials.admin) { throw new AuthRequiredError('Insufficient privileges') diff --git a/packages/pds/src/api/com/atproto/identity/updateHandle.ts b/packages/pds/src/api/com/atproto/identity/updateHandle.ts index 6db63fab0c0..44a2aaded72 100644 --- a/packages/pds/src/api/com/atproto/identity/updateHandle.ts +++ b/packages/pds/src/api/com/atproto/identity/updateHandle.ts @@ -11,7 +11,7 @@ import { DAY, MINUTE } from '@atproto/common' export default function (server: Server, ctx: AppContext) { server.com.atproto.identity.updateHandle({ - auth: ctx.accessVerifierCheckTakedown, + auth: ctx.authVerifier.accessCheckTakedown, rateLimit: [ { durationMs: 5 * MINUTE, diff --git a/packages/pds/src/api/com/atproto/moderation/createReport.ts b/packages/pds/src/api/com/atproto/moderation/createReport.ts index 83cd5f454e0..ecdcc6e87cf 100644 --- a/packages/pds/src/api/com/atproto/moderation/createReport.ts +++ b/packages/pds/src/api/com/atproto/moderation/createReport.ts @@ -4,7 +4,7 @@ import { getReasonType, getSubject } from './util' export default function (server: Server, ctx: AppContext) { server.com.atproto.moderation.createReport({ - auth: ctx.accessVerifierCheckTakedown, + auth: ctx.authVerifier.accessCheckTakedown, handler: async ({ input, auth }) => { const requester = auth.credentials.did diff --git a/packages/pds/src/api/com/atproto/repo/applyWrites.ts b/packages/pds/src/api/com/atproto/repo/applyWrites.ts index d5be8bb720d..b2dcaaab918 100644 --- a/packages/pds/src/api/com/atproto/repo/applyWrites.ts +++ b/packages/pds/src/api/com/atproto/repo/applyWrites.ts @@ -32,7 +32,7 @@ const ratelimitPoints = ({ input }: { input: HandlerInput }) => { export default function (server: Server, ctx: AppContext) { server.com.atproto.repo.applyWrites({ - auth: ctx.accessVerifierCheckTakedown, + auth: ctx.authVerifier.accessCheckTakedown, rateLimit: [ { name: 'repo-write-hour', diff --git a/packages/pds/src/api/com/atproto/repo/createRecord.ts b/packages/pds/src/api/com/atproto/repo/createRecord.ts index 26bc5614785..2c61d20448d 100644 --- a/packages/pds/src/api/com/atproto/repo/createRecord.ts +++ b/packages/pds/src/api/com/atproto/repo/createRecord.ts @@ -15,7 +15,7 @@ import { ConcurrentWriteError } from '../../../../services/repo' export default function (server: Server, ctx: AppContext) { server.com.atproto.repo.createRecord({ - auth: ctx.accessVerifierCheckTakedown, + auth: ctx.authVerifier.accessCheckTakedown, rateLimit: [ { name: 'repo-write-hour', diff --git a/packages/pds/src/api/com/atproto/repo/deleteRecord.ts b/packages/pds/src/api/com/atproto/repo/deleteRecord.ts index 99f171e0849..efc5a64fadf 100644 --- a/packages/pds/src/api/com/atproto/repo/deleteRecord.ts +++ b/packages/pds/src/api/com/atproto/repo/deleteRecord.ts @@ -8,7 +8,7 @@ import { ConcurrentWriteError } from '../../../../services/repo' export default function (server: Server, ctx: AppContext) { server.com.atproto.repo.deleteRecord({ - auth: ctx.accessVerifierCheckTakedown, + auth: ctx.authVerifier.accessCheckTakedown, rateLimit: [ { name: 'repo-write-hour', diff --git a/packages/pds/src/api/com/atproto/repo/putRecord.ts b/packages/pds/src/api/com/atproto/repo/putRecord.ts index 8fdcc776bb9..9d7d4332b2e 100644 --- a/packages/pds/src/api/com/atproto/repo/putRecord.ts +++ b/packages/pds/src/api/com/atproto/repo/putRecord.ts @@ -15,7 +15,7 @@ import { ConcurrentWriteError } from '../../../../services/repo' export default function (server: Server, ctx: AppContext) { server.com.atproto.repo.putRecord({ - auth: ctx.accessVerifierCheckTakedown, + auth: ctx.authVerifier.accessCheckTakedown, rateLimit: [ { name: 'repo-write-hour', diff --git a/packages/pds/src/api/com/atproto/repo/uploadBlob.ts b/packages/pds/src/api/com/atproto/repo/uploadBlob.ts index b5a6eaecaef..ba93648470a 100644 --- a/packages/pds/src/api/com/atproto/repo/uploadBlob.ts +++ b/packages/pds/src/api/com/atproto/repo/uploadBlob.ts @@ -3,7 +3,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.com.atproto.repo.uploadBlob({ - auth: ctx.accessVerifierCheckTakedown, + auth: ctx.authVerifier.accessCheckTakedown, handler: async ({ auth, input }) => { const requester = auth.credentials.did const blob = await ctx.services diff --git a/packages/pds/src/api/com/atproto/server/confirmEmail.ts b/packages/pds/src/api/com/atproto/server/confirmEmail.ts index f1452825771..fe1f05d87f8 100644 --- a/packages/pds/src/api/com/atproto/server/confirmEmail.ts +++ b/packages/pds/src/api/com/atproto/server/confirmEmail.ts @@ -4,7 +4,7 @@ import { InvalidRequestError } from '@atproto/xrpc-server' export default function (server: Server, ctx: AppContext) { server.com.atproto.server.confirmEmail({ - auth: ctx.accessVerifierCheckTakedown, + auth: ctx.authVerifier.accessCheckTakedown, handler: async ({ auth, input }) => { const did = auth.credentials.did const { token, email } = input.body diff --git a/packages/pds/src/api/com/atproto/server/createAccount.ts b/packages/pds/src/api/com/atproto/server/createAccount.ts index 334c2f2b132..cbff7a908a8 100644 --- a/packages/pds/src/api/com/atproto/server/createAccount.ts +++ b/packages/pds/src/api/com/atproto/server/createAccount.ts @@ -104,9 +104,9 @@ export default function (server: Server, ctx: AppContext) { .execute() } - const access = ctx.auth.createAccessToken({ did }) - const refresh = ctx.auth.createRefreshToken({ did }) - await ctx.services.auth(dbTxn).grantRefreshToken(refresh.payload, null) + const { access, refresh } = await ctx.services + .auth(dbTxn) + .createSession(did, null) // Setup repo root await repoTxn.createRepo(did, [], now) diff --git a/packages/pds/src/api/com/atproto/server/createAppPassword.ts b/packages/pds/src/api/com/atproto/server/createAppPassword.ts index e86044ae524..43ea255cab0 100644 --- a/packages/pds/src/api/com/atproto/server/createAppPassword.ts +++ b/packages/pds/src/api/com/atproto/server/createAppPassword.ts @@ -3,7 +3,7 @@ import { Server } from '../../../../lexicon' export default function (server: Server, ctx: AppContext) { server.com.atproto.server.createAppPassword({ - auth: ctx.accessVerifierNotAppPassword, + auth: ctx.authVerifier.accessNotAppPassword, handler: async ({ auth, input }) => { const { name } = input.body const appPassword = await ctx.services diff --git a/packages/pds/src/api/com/atproto/server/createInviteCode.ts b/packages/pds/src/api/com/atproto/server/createInviteCode.ts index 6c8e8b8b714..e1b71320795 100644 --- a/packages/pds/src/api/com/atproto/server/createInviteCode.ts +++ b/packages/pds/src/api/com/atproto/server/createInviteCode.ts @@ -5,7 +5,7 @@ import { genInvCode } from './util' export default function (server: Server, ctx: AppContext) { server.com.atproto.server.createInviteCode({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ input, req, auth }) => { if (!auth.credentials.admin) { throw new AuthRequiredError('Insufficient privileges') diff --git a/packages/pds/src/api/com/atproto/server/createInviteCodes.ts b/packages/pds/src/api/com/atproto/server/createInviteCodes.ts index d2d043e6ec7..f5f9cb972fc 100644 --- a/packages/pds/src/api/com/atproto/server/createInviteCodes.ts +++ b/packages/pds/src/api/com/atproto/server/createInviteCodes.ts @@ -8,7 +8,7 @@ import { AccountCodes } from '../../../../lexicon/types/com/atproto/server/creat export default function (server: Server, ctx: AppContext) { server.com.atproto.server.createInviteCodes({ - auth: ctx.roleVerifier, + auth: ctx.authVerifier.role, handler: async ({ input, req, auth }) => { if (!auth.credentials.admin) { throw new AuthRequiredError('Insufficient privileges') diff --git a/packages/pds/src/api/com/atproto/server/createSession.ts b/packages/pds/src/api/com/atproto/server/createSession.ts index 6d8d57e471e..93e64d7bbcd 100644 --- a/packages/pds/src/api/com/atproto/server/createSession.ts +++ b/packages/pds/src/api/com/atproto/server/createSession.ts @@ -2,7 +2,6 @@ import { AuthRequiredError } from '@atproto/xrpc-server' import AppContext from '../../../../context' import { softDeleted } from '../../../../db/util' import { Server } from '../../../../lexicon' -import { AuthScope } from '../../../../auth' import { DAY, MINUTE } from '@atproto/common' export default function (server: Server, ctx: AppContext) { @@ -55,12 +54,10 @@ export default function (server: Server, ctx: AppContext) { ) } - const access = ctx.auth.createAccessToken({ - did: user.did, - scope: appPasswordName === null ? AuthScope.Access : AuthScope.AppPass, - }) - const refresh = ctx.auth.createRefreshToken({ did: user.did }) - await authService.grantRefreshToken(refresh.payload, appPasswordName) + const { access, refresh } = await authService.createSession( + user.did, + appPasswordName, + ) return { encoding: 'application/json', diff --git a/packages/pds/src/api/com/atproto/server/deleteSession.ts b/packages/pds/src/api/com/atproto/server/deleteSession.ts index 28610df39d2..2fa93528515 100644 --- a/packages/pds/src/api/com/atproto/server/deleteSession.ts +++ b/packages/pds/src/api/com/atproto/server/deleteSession.ts @@ -1,21 +1,19 @@ -import { AuthRequiredError } from '@atproto/xrpc-server' -import { AuthScope } from '../../../../auth' +import { AuthScope } from '../../../../auth-verifier' import AppContext from '../../../../context' import { Server } from '../../../../lexicon' export default function (server: Server, ctx: AppContext) { server.com.atproto.server.deleteSession(async ({ req }) => { - const token = ctx.auth.getToken(req) - if (!token) { - throw new AuthRequiredError() - } - const refreshToken = ctx.auth.verifyToken(token, [AuthScope.Refresh], { - ignoreExpiration: true, - }) - if (!refreshToken.jti) { + const result = ctx.authVerifier.validateBearerToken( + req, + [AuthScope.Refresh], + { ignoreExpiration: true }, + ) + const id = result.payload.jti + if (!id) { throw new Error('Unexpected missing refresh token id') } - await ctx.services.auth(ctx.db).revokeRefreshToken(refreshToken.jti) + await ctx.services.auth(ctx.db).revokeRefreshToken(id) }) } diff --git a/packages/pds/src/api/com/atproto/server/getAccountInviteCodes.ts b/packages/pds/src/api/com/atproto/server/getAccountInviteCodes.ts index 275398f7609..31cfe60ad3a 100644 --- a/packages/pds/src/api/com/atproto/server/getAccountInviteCodes.ts +++ b/packages/pds/src/api/com/atproto/server/getAccountInviteCodes.ts @@ -6,7 +6,7 @@ import { CodeDetail } from '../../../../services/account' export default function (server: Server, ctx: AppContext) { server.com.atproto.server.getAccountInviteCodes({ - auth: ctx.accessVerifierNotAppPassword, + auth: ctx.authVerifier.accessNotAppPassword, handler: async ({ params, auth }) => { const requester = auth.credentials.did const { includeUsed, createAvailable } = params diff --git a/packages/pds/src/api/com/atproto/server/getSession.ts b/packages/pds/src/api/com/atproto/server/getSession.ts index eb33180e6ff..fa192f0057f 100644 --- a/packages/pds/src/api/com/atproto/server/getSession.ts +++ b/packages/pds/src/api/com/atproto/server/getSession.ts @@ -4,7 +4,7 @@ import { Server } from '../../../../lexicon' export default function (server: Server, ctx: AppContext) { server.com.atproto.server.getSession({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth }) => { const did = auth.credentials.did const user = await ctx.services.account(ctx.db).getAccount(did) diff --git a/packages/pds/src/api/com/atproto/server/listAppPasswords.ts b/packages/pds/src/api/com/atproto/server/listAppPasswords.ts index 3c7eff512f7..75cd6392c9f 100644 --- a/packages/pds/src/api/com/atproto/server/listAppPasswords.ts +++ b/packages/pds/src/api/com/atproto/server/listAppPasswords.ts @@ -3,7 +3,7 @@ import { Server } from '../../../../lexicon' export default function (server: Server, ctx: AppContext) { server.com.atproto.server.listAppPasswords({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth }) => { const passwords = await ctx.services .account(ctx.db) diff --git a/packages/pds/src/api/com/atproto/server/refreshSession.ts b/packages/pds/src/api/com/atproto/server/refreshSession.ts index 0fda8ba48a7..8db33e289de 100644 --- a/packages/pds/src/api/com/atproto/server/refreshSession.ts +++ b/packages/pds/src/api/com/atproto/server/refreshSession.ts @@ -2,12 +2,11 @@ import { AuthRequiredError, InvalidRequestError } from '@atproto/xrpc-server' import AppContext from '../../../../context' import { softDeleted } from '../../../../db/util' import { Server } from '../../../../lexicon' -import { AuthScope } from '../../../../auth' export default function (server: Server, ctx: AppContext) { server.com.atproto.server.refreshSession({ - auth: ctx.refreshVerifier, - handler: async ({ req, auth }) => { + auth: ctx.authVerifier.refresh, + handler: async ({ auth }) => { const did = auth.credentials.did const user = await ctx.services.account(ctx.db).getAccount(did, true) if (!user) { @@ -22,40 +21,21 @@ export default function (server: Server, ctx: AppContext) { ) } - const lastRefreshId = ctx.auth.verifyToken( - ctx.auth.getToken(req) ?? '', - [], - ).jti - if (!lastRefreshId) { - throw new Error('Unexpected missing refresh token id') - } - - const res = await ctx.db.transaction(async (dbTxn) => { - const authTxn = ctx.services.auth(dbTxn) - const rotateRes = await authTxn.rotateRefreshToken(lastRefreshId) - if (!rotateRes) return null - const refresh = ctx.auth.createRefreshToken({ - did: user.did, - jti: rotateRes.nextId, - }) - await authTxn.grantRefreshToken(refresh.payload, rotateRes.appPassName) - return { refresh, appPassName: rotateRes.appPassName } + const res = await ctx.db.transaction((dbTxn) => { + return ctx.services + .auth(dbTxn) + .rotateRefreshToken(auth.credentials.tokenId) }) if (res === null) { throw new InvalidRequestError('Token has been revoked', 'ExpiredToken') } - const access = ctx.auth.createAccessToken({ - did: user.did, - scope: res.appPassName === null ? AuthScope.Access : AuthScope.AppPass, - }) - return { encoding: 'application/json', body: { did: user.did, handle: user.handle, - accessJwt: access.jwt, + accessJwt: res.access.jwt, refreshJwt: res.refresh.jwt, }, } diff --git a/packages/pds/src/api/com/atproto/server/requestAccountDelete.ts b/packages/pds/src/api/com/atproto/server/requestAccountDelete.ts index c438c32f69f..ca895852f4f 100644 --- a/packages/pds/src/api/com/atproto/server/requestAccountDelete.ts +++ b/packages/pds/src/api/com/atproto/server/requestAccountDelete.ts @@ -4,7 +4,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.com.atproto.server.requestAccountDelete({ - auth: ctx.accessVerifierCheckTakedown, + auth: ctx.authVerifier.accessCheckTakedown, handler: async ({ auth }) => { const did = auth.credentials.did const user = await ctx.services.account(ctx.db).getAccount(did) diff --git a/packages/pds/src/api/com/atproto/server/requestEmailConfirmation.ts b/packages/pds/src/api/com/atproto/server/requestEmailConfirmation.ts index aa7b632569e..97b2e53cc7a 100644 --- a/packages/pds/src/api/com/atproto/server/requestEmailConfirmation.ts +++ b/packages/pds/src/api/com/atproto/server/requestEmailConfirmation.ts @@ -4,7 +4,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.com.atproto.server.requestEmailConfirmation({ - auth: ctx.accessVerifierCheckTakedown, + auth: ctx.authVerifier.accessCheckTakedown, handler: async ({ auth }) => { const did = auth.credentials.did const user = await ctx.services.account(ctx.db).getAccount(did) diff --git a/packages/pds/src/api/com/atproto/server/requestEmailUpdate.ts b/packages/pds/src/api/com/atproto/server/requestEmailUpdate.ts index bcc65303f41..5402fa6b887 100644 --- a/packages/pds/src/api/com/atproto/server/requestEmailUpdate.ts +++ b/packages/pds/src/api/com/atproto/server/requestEmailUpdate.ts @@ -4,7 +4,7 @@ import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { server.com.atproto.server.requestEmailUpdate({ - auth: ctx.accessVerifierCheckTakedown, + auth: ctx.authVerifier.accessCheckTakedown, handler: async ({ auth }) => { const did = auth.credentials.did const user = await ctx.services.account(ctx.db).getAccount(did) diff --git a/packages/pds/src/api/com/atproto/server/revokeAppPassword.ts b/packages/pds/src/api/com/atproto/server/revokeAppPassword.ts index 5f3ce4eb1cc..43398576d6a 100644 --- a/packages/pds/src/api/com/atproto/server/revokeAppPassword.ts +++ b/packages/pds/src/api/com/atproto/server/revokeAppPassword.ts @@ -3,7 +3,7 @@ import { Server } from '../../../../lexicon' export default function (server: Server, ctx: AppContext) { server.com.atproto.server.revokeAppPassword({ - auth: ctx.accessVerifier, + auth: ctx.authVerifier.access, handler: async ({ auth, input }) => { const requester = auth.credentials.did const { name } = input.body diff --git a/packages/pds/src/api/com/atproto/server/updateEmail.ts b/packages/pds/src/api/com/atproto/server/updateEmail.ts index 6f946a89446..c10bb1c85f6 100644 --- a/packages/pds/src/api/com/atproto/server/updateEmail.ts +++ b/packages/pds/src/api/com/atproto/server/updateEmail.ts @@ -5,7 +5,7 @@ import disposable from 'disposable-email' export default function (server: Server, ctx: AppContext) { server.com.atproto.server.updateEmail({ - auth: ctx.accessVerifierNotAppPassword, + auth: ctx.authVerifier.accessNotAppPassword, handler: async ({ auth, input }) => { const did = auth.credentials.did const { token, email } = input.body diff --git a/packages/pds/src/api/com/atproto/sync/deprecated/getCheckout.ts b/packages/pds/src/api/com/atproto/sync/deprecated/getCheckout.ts index cbde7131c66..899706986a5 100644 --- a/packages/pds/src/api/com/atproto/sync/deprecated/getCheckout.ts +++ b/packages/pds/src/api/com/atproto/sync/deprecated/getCheckout.ts @@ -5,15 +5,14 @@ import SqlRepoStorage, { RepoRootNotFoundError, } from '../../../../../sql-repo-storage' import AppContext from '../../../../../context' -import { isUserOrAdmin } from '../../../../../auth' export default function (server: Server, ctx: AppContext) { server.com.atproto.sync.getCheckout({ - auth: ctx.optionalAccessOrRoleVerifier, + auth: ctx.authVerifier.optionalAccessOrRole, handler: async ({ params, auth }) => { const { did } = params // takedown check for anyone other than an admin or the user - if (!isUserOrAdmin(auth, did)) { + if (!ctx.authVerifier.isUserOrAdmin(auth, did)) { const available = await ctx.services .account(ctx.db) .isRepoAvailable(did) diff --git a/packages/pds/src/api/com/atproto/sync/deprecated/getHead.ts b/packages/pds/src/api/com/atproto/sync/deprecated/getHead.ts index acde9cebc38..c8499f92faa 100644 --- a/packages/pds/src/api/com/atproto/sync/deprecated/getHead.ts +++ b/packages/pds/src/api/com/atproto/sync/deprecated/getHead.ts @@ -2,15 +2,14 @@ import { InvalidRequestError } from '@atproto/xrpc-server' import { Server } from '../../../../../lexicon' import SqlRepoStorage from '../../../../../sql-repo-storage' import AppContext from '../../../../../context' -import { isUserOrAdmin } from '../../../../../auth' export default function (server: Server, ctx: AppContext) { server.com.atproto.sync.getHead({ - auth: ctx.optionalAccessOrRoleVerifier, + auth: ctx.authVerifier.optionalAccessOrRole, handler: async ({ params, auth }) => { const { did } = params // takedown check for anyone other than an admin or the user - if (!isUserOrAdmin(auth, did)) { + if (!ctx.authVerifier.isUserOrAdmin(auth, did)) { const available = await ctx.services .account(ctx.db) .isRepoAvailable(did) diff --git a/packages/pds/src/api/com/atproto/sync/getBlob.ts b/packages/pds/src/api/com/atproto/sync/getBlob.ts index b92154af80f..7de146fcc5d 100644 --- a/packages/pds/src/api/com/atproto/sync/getBlob.ts +++ b/packages/pds/src/api/com/atproto/sync/getBlob.ts @@ -3,12 +3,11 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' import { InvalidRequestError } from '@atproto/xrpc-server' import { notSoftDeletedClause } from '../../../../db/util' -import { isUserOrAdmin } from '../../../../auth' import { BlobNotFoundError } from '@atproto/repo' export default function (server: Server, ctx: AppContext) { server.com.atproto.sync.getBlob({ - auth: ctx.optionalAccessOrRoleVerifier, + auth: ctx.authVerifier.optionalAccessOrRole, handler: async ({ params, res, auth }) => { const { ref } = ctx.db.db.dynamic const found = await ctx.db.db @@ -23,7 +22,7 @@ export default function (server: Server, ctx: AppContext) { .where('blob.cid', '=', params.cid) .where('blob.creator', '=', params.did) .where(notSoftDeletedClause(ref('repo_blob'))) - .if(!isUserOrAdmin(auth, params.did), (qb) => + .if(!ctx.authVerifier.isUserOrAdmin(auth, params.did), (qb) => // takedown check for anyone other than an admin or the user qb.where(notSoftDeletedClause(ref('repo_root'))), ) diff --git a/packages/pds/src/api/com/atproto/sync/getBlocks.ts b/packages/pds/src/api/com/atproto/sync/getBlocks.ts index a4a85355f13..1ee859255ab 100644 --- a/packages/pds/src/api/com/atproto/sync/getBlocks.ts +++ b/packages/pds/src/api/com/atproto/sync/getBlocks.ts @@ -5,15 +5,14 @@ import { blocksToCarStream } from '@atproto/repo' import { Server } from '../../../../lexicon' import SqlRepoStorage from '../../../../sql-repo-storage' import AppContext from '../../../../context' -import { isUserOrAdmin } from '../../../../auth' export default function (server: Server, ctx: AppContext) { server.com.atproto.sync.getBlocks({ - auth: ctx.optionalAccessOrRoleVerifier, + auth: ctx.authVerifier.optionalAccessOrRole, handler: async ({ params, auth }) => { const { did } = params // takedown check for anyone other than an admin or the user - if (!isUserOrAdmin(auth, did)) { + if (!ctx.authVerifier.isUserOrAdmin(auth, did)) { const available = await ctx.services .account(ctx.db) .isRepoAvailable(did) diff --git a/packages/pds/src/api/com/atproto/sync/getLatestCommit.ts b/packages/pds/src/api/com/atproto/sync/getLatestCommit.ts index 877db7806f4..a28c1ad0edd 100644 --- a/packages/pds/src/api/com/atproto/sync/getLatestCommit.ts +++ b/packages/pds/src/api/com/atproto/sync/getLatestCommit.ts @@ -2,15 +2,14 @@ import { InvalidRequestError } from '@atproto/xrpc-server' import { Server } from '../../../../lexicon' import SqlRepoStorage from '../../../../sql-repo-storage' import AppContext from '../../../../context' -import { isUserOrAdmin } from '../../../../auth' export default function (server: Server, ctx: AppContext) { server.com.atproto.sync.getLatestCommit({ - auth: ctx.optionalAccessOrRoleVerifier, + auth: ctx.authVerifier.optionalAccessOrRole, handler: async ({ params, auth }) => { const { did } = params // takedown check for anyone other than an admin or the user - if (!isUserOrAdmin(auth, did)) { + if (!ctx.authVerifier.isUserOrAdmin(auth, did)) { const available = await ctx.services .account(ctx.db) .isRepoAvailable(did) diff --git a/packages/pds/src/api/com/atproto/sync/getRecord.ts b/packages/pds/src/api/com/atproto/sync/getRecord.ts index 817d7850cb6..dc8c7e78f08 100644 --- a/packages/pds/src/api/com/atproto/sync/getRecord.ts +++ b/packages/pds/src/api/com/atproto/sync/getRecord.ts @@ -5,15 +5,14 @@ import { Server } from '../../../../lexicon' import SqlRepoStorage from '../../../../sql-repo-storage' import AppContext from '../../../../context' import { byteIterableToStream } from '@atproto/common' -import { isUserOrAdmin } from '../../../../auth' export default function (server: Server, ctx: AppContext) { server.com.atproto.sync.getRecord({ - auth: ctx.optionalAccessOrRoleVerifier, + auth: ctx.authVerifier.optionalAccessOrRole, handler: async ({ params, auth }) => { const { did, collection, rkey } = params // takedown check for anyone other than an admin or the user - if (!isUserOrAdmin(auth, did)) { + if (!ctx.authVerifier.isUserOrAdmin(auth, did)) { const available = await ctx.services .account(ctx.db) .isRepoAvailable(did) diff --git a/packages/pds/src/api/com/atproto/sync/getRepo.ts b/packages/pds/src/api/com/atproto/sync/getRepo.ts index 9037a2a3a9c..6dc9c8af68b 100644 --- a/packages/pds/src/api/com/atproto/sync/getRepo.ts +++ b/packages/pds/src/api/com/atproto/sync/getRepo.ts @@ -5,15 +5,14 @@ import SqlRepoStorage, { RepoRootNotFoundError, } from '../../../../sql-repo-storage' import AppContext from '../../../../context' -import { isUserOrAdmin } from '../../../../auth' export default function (server: Server, ctx: AppContext) { server.com.atproto.sync.getRepo({ - auth: ctx.optionalAccessOrRoleVerifier, + auth: ctx.authVerifier.optionalAccessOrRole, handler: async ({ params, auth }) => { const { did, since } = params // takedown check for anyone other than an admin or the user - if (!isUserOrAdmin(auth, did)) { + if (!ctx.authVerifier.isUserOrAdmin(auth, did)) { const available = await ctx.services .account(ctx.db) .isRepoAvailable(did) diff --git a/packages/pds/src/api/com/atproto/sync/listBlobs.ts b/packages/pds/src/api/com/atproto/sync/listBlobs.ts index 5beb4d5a0fd..dd05ee9b9e4 100644 --- a/packages/pds/src/api/com/atproto/sync/listBlobs.ts +++ b/packages/pds/src/api/com/atproto/sync/listBlobs.ts @@ -1,15 +1,14 @@ import { InvalidRequestError } from '@atproto/xrpc-server' import { Server } from '../../../../lexicon' import AppContext from '../../../../context' -import { isUserOrAdmin } from '../../../../auth' export default function (server: Server, ctx: AppContext) { server.com.atproto.sync.listBlobs({ - auth: ctx.optionalAccessOrRoleVerifier, + auth: ctx.authVerifier.optionalAccessOrRole, handler: async ({ params, auth }) => { const { did, since, limit, cursor } = params // takedown check for anyone other than an admin or the user - if (!isUserOrAdmin(auth, did)) { + if (!ctx.authVerifier.isUserOrAdmin(auth, did)) { const available = await ctx.services .account(ctx.db) .isRepoAvailable(did) diff --git a/packages/pds/src/auth-verifier.ts b/packages/pds/src/auth-verifier.ts new file mode 100644 index 00000000000..380f94b90b6 --- /dev/null +++ b/packages/pds/src/auth-verifier.ts @@ -0,0 +1,302 @@ +import { AuthRequiredError, InvalidRequestError } from '@atproto/xrpc-server' +import * as ui8 from 'uint8arrays' +import express from 'express' +import * as jwt from 'jsonwebtoken' +import Database from './db' + +type ReqCtx = { + req: express.Request +} + +// @TODO sync-up with current method names, consider backwards compat. +export enum AuthScope { + Access = 'com.atproto.access', + Refresh = 'com.atproto.refresh', + AppPass = 'com.atproto.appPass', +} + +export enum RoleStatus { + Valid, + Invalid, + Missing, +} + +type NullOutput = { + credentials: null +} + +type RoleOutput = { + credentials: { + type: 'role' + admin: boolean + moderator: boolean + triage: boolean + } +} + +type AccessOutput = { + credentials: { + type: 'access' + did: string + scope: AuthScope + } + artifacts: string +} + +type RefreshOutput = { + credentials: { + type: 'refresh' + did: string + scope: AuthScope + tokenId: string + } + artifacts: string +} + +type ValidatedBearer = { + did: string + scope: AuthScope + token: string + payload: jwt.JwtPayload +} + +export type AuthVerifierOpts = { + jwtSecret: string + adminPass: string + moderatorPass: string + triagePass: string +} + +export class AuthVerifier { + private _secret: string + private _adminPass: string + private _moderatorPass: string + private _triagePass: string + + constructor(public db: Database, opts: AuthVerifierOpts) { + this._secret = opts.jwtSecret + this._adminPass = opts.adminPass + this._moderatorPass = opts.moderatorPass + this._triagePass = opts.triagePass + } + + // verifiers (arrow fns to preserve scope) + + access = (ctx: ReqCtx): AccessOutput => { + return this.validateAccessToken(ctx.req, [ + AuthScope.Access, + AuthScope.AppPass, + ]) + } + + accessCheckTakedown = async (ctx: ReqCtx): Promise => { + const result = this.validateAccessToken(ctx.req, [ + AuthScope.Access, + AuthScope.AppPass, + ]) + const found = await this.db.db + .selectFrom('user_account') + .innerJoin('repo_root', 'repo_root.did', 'user_account.did') + .where('user_account.did', '=', result.credentials.did) + .where('repo_root.takedownId', 'is', null) + .select('user_account.did') + .executeTakeFirst() + if (!found) { + throw new AuthRequiredError( + 'Account has been taken down', + 'AccountTakedown', + ) + } + return result + } + + accessNotAppPassword = (ctx: ReqCtx): AccessOutput => { + return this.validateAccessToken(ctx.req, [AuthScope.Access]) + } + + refresh = (ctx: ReqCtx): RefreshOutput => { + const { did, scope, token, payload } = this.validateBearerToken(ctx.req, [ + AuthScope.Refresh, + ]) + if (!payload.jti) { + throw new AuthRequiredError( + 'Unexpected missing refresh token id', + 'MissingTokenId', + ) + } + return { + credentials: { + type: 'refresh', + did, + scope, + tokenId: payload.jti, + }, + artifacts: token, + } + } + + role = (ctx: ReqCtx): RoleOutput => { + const creds = this.parseRoleCreds(ctx.req) + if (creds.status !== RoleStatus.Valid) { + throw new AuthRequiredError() + } + return { + credentials: { + ...creds, + type: 'role', + }, + } + } + + accessOrRole = (ctx: ReqCtx): AccessOutput | RoleOutput => { + if (isBearerToken(ctx.req)) { + return this.access(ctx) + } else { + return this.role(ctx) + } + } + + optionalAccessOrRole = ( + ctx: ReqCtx, + ): AccessOutput | RoleOutput | NullOutput => { + if (isBearerToken(ctx.req)) { + return this.access(ctx) + } else { + const creds = this.parseRoleCreds(ctx.req) + if (creds.status === RoleStatus.Missing) { + return { credentials: null } + } else if (creds.admin) { + return { + credentials: { + ...creds, + type: 'role', + }, + } + } else { + throw new AuthRequiredError() + } + } + } + + validateBearerToken( + req: express.Request, + scopes: AuthScope[], + options?: jwt.VerifyOptions, + ): ValidatedBearer { + const token = bearerTokenFromReq(req) + if (!token) { + throw new AuthRequiredError(undefined, 'AuthMissing') + } + const payload = verifyJwt({ secret: this._secret, token, options }) + const sub = payload.sub + if (typeof sub !== 'string' || !sub.startsWith('did:')) { + throw new InvalidRequestError('Malformed token', 'InvalidToken') + } + if (scopes.length > 0 && !scopes.includes(payload.scope)) { + throw new InvalidRequestError('Bad token scope', 'InvalidToken') + } + + return { + did: sub, + scope: payload.scope, + token, + payload, + } + } + + validateAccessToken(req: express.Request, scopes: AuthScope[]): AccessOutput { + const { did, scope, token } = this.validateBearerToken(req, scopes) + return { + credentials: { + type: 'access', + did, + scope, + }, + artifacts: token, + } + } + + parseRoleCreds(req: express.Request) { + const parsed = parseBasicAuth(req.headers.authorization || '') + const { Missing, Valid, Invalid } = RoleStatus + if (!parsed) { + return { status: Missing, admin: false, moderator: false, triage: false } + } + const { username, password } = parsed + if (username === 'admin' && password === this._adminPass) { + return { status: Valid, admin: true, moderator: true, triage: true } + } + if (username === 'admin' && password === this._moderatorPass) { + return { status: Valid, admin: false, moderator: true, triage: true } + } + if (username === 'admin' && password === this._triagePass) { + return { status: Valid, admin: false, moderator: false, triage: true } + } + return { status: Invalid, admin: false, moderator: false, triage: false } + } + + isUserOrAdmin( + auth: AccessOutput | RoleOutput | NullOutput, + did: string, + ): boolean { + if (!auth.credentials) { + return false + } + if ('did' in auth.credentials) { + return auth.credentials.did === did + } + return auth.credentials.admin + } +} + +// HELPERS +// --------- + +const BEARER = 'Bearer ' +const BASIC = 'Basic ' + +const isBearerToken = (req: express.Request): boolean => { + return req.headers.authorization?.startsWith(BEARER) ?? false +} + +const bearerTokenFromReq = (req: express.Request) => { + const header = req.headers.authorization || '' + if (!header.startsWith(BEARER)) return null + return header.slice(BEARER.length) +} + +const verifyJwt = (params: { + secret: string + token: string + options?: jwt.VerifyOptions +}): jwt.JwtPayload => { + const { secret, token, options } = params + try { + const payload = jwt.verify(token, secret, options) + if (typeof payload === 'string' || 'signature' in payload) { + throw new InvalidRequestError('Malformed token', 'InvalidToken') + } + return payload + } catch (err) { + if (err instanceof jwt.TokenExpiredError) { + throw new InvalidRequestError('Token has expired', 'ExpiredToken') + } + throw new InvalidRequestError('Token could not be verified', 'InvalidToken') + } +} + +export const parseBasicAuth = ( + token: string, +): { username: string; password: string } | null => { + if (!token.startsWith(BASIC)) return null + const b64 = token.slice(BASIC.length) + let parsed: string[] + try { + parsed = ui8.toString(ui8.fromString(b64, 'base64pad'), 'utf8').split(':') + } catch (err) { + return null + } + const [username, password] = parsed + if (!username || !password) return null + return { username, password } +} diff --git a/packages/pds/src/auth.ts b/packages/pds/src/auth.ts deleted file mode 100644 index 6d75f1fd920..00000000000 --- a/packages/pds/src/auth.ts +++ /dev/null @@ -1,326 +0,0 @@ -import * as crypto from '@atproto/crypto' -import { AuthRequiredError, InvalidRequestError } from '@atproto/xrpc-server' -import * as ui8 from 'uint8arrays' -import express from 'express' -import * as jwt from 'jsonwebtoken' -import AppContext from './context' -import { softDeleted } from './db/util' - -const BEARER = 'Bearer ' -const BASIC = 'Basic ' - -export type ServerAuthOpts = { - jwtSecret: string - adminPass: string - moderatorPass?: string - triagePass?: string -} - -// @TODO sync-up with current method names, consider backwards compat. -export enum AuthScope { - Access = 'com.atproto.access', - Refresh = 'com.atproto.refresh', - AppPass = 'com.atproto.appPass', -} - -export type AuthToken = { - scope: AuthScope - sub: string - exp: number -} - -export type RefreshToken = AuthToken & { jti: string } - -export class ServerAuth { - private _secret: string - private _adminPass: string - private _moderatorPass?: string - private _triagePass?: string - - constructor(opts: ServerAuthOpts) { - this._secret = opts.jwtSecret - this._adminPass = opts.adminPass - this._moderatorPass = opts.moderatorPass - this._triagePass = opts.triagePass - } - - createAccessToken(opts: { - did: string - scope?: AuthScope - expiresIn?: string | number - }) { - const { did, scope = AuthScope.Access, expiresIn = '120mins' } = opts - const payload = { - scope, - sub: did, - } - return { - payload: payload as AuthToken, // exp set by sign() - jwt: jwt.sign(payload, this._secret, { - expiresIn: expiresIn, - mutatePayload: true, - }), - } - } - - createRefreshToken(opts: { - did: string - jti?: string - expiresIn?: string | number - }) { - const { did, jti = getRefreshTokenId(), expiresIn = '90days' } = opts - const payload = { - scope: AuthScope.Refresh, - sub: did, - jti, - } - return { - payload: payload as RefreshToken, // exp set by sign() - jwt: jwt.sign(payload, this._secret, { - expiresIn: expiresIn, - mutatePayload: true, - }), - } - } - - getCredentials( - req: express.Request, - scopes = [AuthScope.Access], - ): { did: string; scope: AuthScope } | null { - const token = this.getToken(req) - if (!token) return null - const payload = this.verifyToken(token, scopes) - const sub = payload.sub - if (typeof sub !== 'string' || !sub.startsWith('did:')) { - throw new InvalidRequestError('Malformed token', 'InvalidToken') - } - return { did: sub, scope: payload.scope } - } - - getCredentialsOrThrow( - req: express.Request, - scopes: AuthScope[], - ): { did: string; scope: AuthScope } { - const creds = this.getCredentials(req, scopes) - if (creds === null) { - throw new AuthRequiredError(undefined, 'AuthMissing') - } - return creds - } - - verifyUser(req: express.Request, did: string, scopes: AuthScope[]): boolean { - const authorized = this.getCredentials(req, scopes) - return authorized !== null && authorized.did === did - } - - verifyRole(req: express.Request) { - const parsed = parseBasicAuth(req.headers.authorization || '') - const { Missing, Valid, Invalid } = AuthStatus - if (!parsed) { - return { status: Missing, admin: false, moderator: false, triage: false } - } - const { username, password } = parsed - if (username === 'admin' && password === this._adminPass) { - return { status: Valid, admin: true, moderator: true, triage: true } - } - if (username === 'admin' && password === this._moderatorPass) { - return { status: Valid, admin: false, moderator: true, triage: true } - } - if (username === 'admin' && password === this._triagePass) { - return { status: Valid, admin: false, moderator: false, triage: true } - } - return { status: Invalid, admin: false, moderator: false, triage: false } - } - - getToken(req: express.Request) { - const header = req.headers.authorization || '' - if (!header.startsWith(BEARER)) return null - return header.slice(BEARER.length) - } - - verifyToken( - token: string, - scopes: AuthScope[], - options?: jwt.VerifyOptions, - ): jwt.JwtPayload { - try { - const payload = jwt.verify(token, this._secret, options) - if (typeof payload === 'string' || 'signature' in payload) { - throw new InvalidRequestError('Malformed token', 'InvalidToken') - } - if (scopes.length > 0 && !scopes.includes(payload.scope)) { - throw new InvalidRequestError('Bad token scope', 'InvalidToken') - } - return payload - } catch (err) { - if (err instanceof jwt.TokenExpiredError) { - throw new InvalidRequestError('Token has expired', 'ExpiredToken') - } - throw new InvalidRequestError( - 'Token could not be verified', - 'InvalidToken', - ) - } - } - - toString(): string { - return 'Server auth: JWT' - } -} - -export const parseBasicAuth = ( - token: string, -): { username: string; password: string } | null => { - if (!token.startsWith(BASIC)) return null - const b64 = token.slice(BASIC.length) - let parsed: string[] - try { - parsed = ui8.toString(ui8.fromString(b64, 'base64pad'), 'utf8').split(':') - } catch (err) { - return null - } - const [username, password] = parsed - if (!username || !password) return null - return { username, password } -} - -export const accessVerifier = - (auth: ServerAuth) => - async (ctx: { req: express.Request; res: express.Response }) => { - const creds = auth.getCredentialsOrThrow(ctx.req, [ - AuthScope.Access, - AuthScope.AppPass, - ]) - return { - credentials: creds, - artifacts: auth.getToken(ctx.req), - } - } - -export const accessVerifierNotAppPassword = - (auth: ServerAuth) => - async (ctx: { req: express.Request; res: express.Response }) => { - const creds = auth.getCredentialsOrThrow(ctx.req, [AuthScope.Access]) - return { - credentials: creds, - artifacts: auth.getToken(ctx.req), - } - } - -export const accessVerifierCheckTakedown = - (auth: ServerAuth, { db, services }: AppContext) => - async (ctx: { req: express.Request; res: express.Response }) => { - const creds = auth.getCredentialsOrThrow(ctx.req, [ - AuthScope.Access, - AuthScope.AppPass, - ]) - const actor = await services.account(db).getAccount(creds.did, true) - if (!actor || softDeleted(actor)) { - throw new AuthRequiredError( - 'Account has been taken down', - 'AccountTakedown', - ) - } - return { - credentials: creds, - artifacts: auth.getToken(ctx.req), - } - } - -export const accessOrRoleVerifier = (auth: ServerAuth) => { - const verifyAccess = accessVerifier(auth) - const verifyRole = roleVerifier(auth) - return async (ctx: { req: express.Request; res: express.Response }) => { - // For non-admin tokens, we don't want to consider alternative verifiers and let it fail if it fails - const isRoleAuthToken = ctx.req.headers.authorization?.startsWith(BASIC) - if (isRoleAuthToken) { - const result = await verifyRole(ctx) - return { - ...result, - credentials: { - type: 'role' as const, - ...result.credentials, - }, - } - } - const result = await verifyAccess(ctx) - return { - ...result, - credentials: { - type: 'access' as const, - ...result.credentials, - }, - } - } -} - -export const optionalAccessOrRoleVerifier = (auth: ServerAuth) => { - const verifyAccess = accessVerifier(auth) - return async (ctx: { req: express.Request; res: express.Response }) => { - try { - return await verifyAccess(ctx) - } catch (err) { - if ( - err instanceof AuthRequiredError && - err.customErrorName === 'AuthMissing' - ) { - // Missing access bearer, move onto admin basic auth - const credentials = auth.verifyRole(ctx.req) - if (credentials.status === AuthStatus.Missing) { - // If both are missing, passthrough: this auth scheme is optional - return { credentials: null } - } else if (credentials.admin) { - return { credentials } - } else { - throw new AuthRequiredError() - } - } - throw err - } - } -} - -export const isUserOrAdmin = ( - auth: { - credentials: null | { admin: boolean } | { did: string } - }, - did: string, -) => { - if (!auth.credentials) { - return false - } - if ('did' in auth.credentials) { - return auth.credentials.did === did - } - return auth.credentials.admin -} - -export const refreshVerifier = - (auth: ServerAuth) => - async (ctx: { req: express.Request; res: express.Response }) => { - const creds = auth.getCredentialsOrThrow(ctx.req, [AuthScope.Refresh]) - return { - credentials: creds, - artifacts: auth.getToken(ctx.req), - } - } - -export const roleVerifier = - (auth: ServerAuth) => - async (ctx: { req: express.Request; res: express.Response }) => { - const credentials = auth.verifyRole(ctx.req) - if (credentials.status !== AuthStatus.Valid) { - throw new AuthRequiredError() - } - return { credentials } - } - -export const getRefreshTokenId = () => { - return ui8.toString(crypto.randomBytes(32), 'base64') -} - -export enum AuthStatus { - Valid, - Invalid, - Missing, -} diff --git a/packages/pds/src/context.ts b/packages/pds/src/context.ts index 328b61893a1..42277c12bbf 100644 --- a/packages/pds/src/context.ts +++ b/packages/pds/src/context.ts @@ -8,8 +8,7 @@ import { KmsKeypair, S3BlobStore } from '@atproto/aws' import { createServiceAuthHeaders } from '@atproto/xrpc-server' import { Database } from './db' import { ServerConfig, ServerSecrets } from './config' -import * as auth from './auth' -import { ServerAuth } from './auth' +import { AuthVerifier } from './auth-verifier' import { ServerMailer } from './mailer' import { ModerationMailer } from './mailer/moderation' import { BlobStore } from '@atproto/repo' @@ -38,7 +37,7 @@ export type AppContextOptions = { redisScratch?: Redis crawlers: Crawlers appViewAgent: AtpAgent - auth: auth.ServerAuth + authVerifier: AuthVerifier repoSigningKey: crypto.Keypair plcRotationKey: crypto.Keypair cfg: ServerConfig @@ -60,7 +59,7 @@ export class AppContext { public redisScratch?: Redis public crawlers: Crawlers public appViewAgent: AtpAgent - public auth: auth.ServerAuth + public authVerifier: AuthVerifier public repoSigningKey: crypto.Keypair public plcRotationKey: crypto.Keypair public cfg: ServerConfig @@ -81,7 +80,7 @@ export class AppContext { this.redisScratch = opts.redisScratch this.crawlers = opts.crawlers this.appViewAgent = opts.appViewAgent - this.auth = opts.auth + this.authVerifier = opts.authVerifier this.repoSigningKey = opts.repoSigningKey this.plcRotationKey = opts.plcRotationKey this.cfg = opts.cfg @@ -152,7 +151,7 @@ export class AppContext { const appViewAgent = new AtpAgent({ service: cfg.bskyAppView.url }) - const auth = new ServerAuth({ + const authVerifier = new AuthVerifier(db, { jwtSecret: secrets.jwtSecret, adminPass: secrets.adminPassword, moderatorPass: secrets.moderatorPassword, @@ -182,6 +181,7 @@ export class AppContext { blobstore, appViewAgent, pdsHostname: cfg.service.hostname, + jwtSecret: secrets.jwtSecret, appViewDid: cfg.bskyAppView.did, appViewCdnUrlPattern: cfg.bskyAppView.cdnUrlPattern, backgroundQueue, @@ -204,7 +204,7 @@ export class AppContext { redisScratch, crawlers, appViewAgent, - auth, + authVerifier, repoSigningKey, plcRotationKey, cfg, @@ -212,34 +212,6 @@ export class AppContext { }) } - get accessVerifier() { - return auth.accessVerifier(this.auth) - } - - get accessVerifierNotAppPassword() { - return auth.accessVerifierNotAppPassword(this.auth) - } - - get accessVerifierCheckTakedown() { - return auth.accessVerifierCheckTakedown(this.auth, this) - } - - get refreshVerifier() { - return auth.refreshVerifier(this.auth) - } - - get roleVerifier() { - return auth.roleVerifier(this.auth) - } - - get accessOrRoleVerifier() { - return auth.accessOrRoleVerifier(this.auth) - } - - get optionalAccessOrRoleVerifier() { - return auth.optionalAccessOrRoleVerifier(this.auth) - } - async serviceAuthHeaders(did: string, audience?: string) { const aud = audience ?? this.cfg.bskyAppView.did if (!aud) { diff --git a/packages/pds/src/logger.ts b/packages/pds/src/logger.ts index a4277e41669..72c44352132 100644 --- a/packages/pds/src/logger.ts +++ b/packages/pds/src/logger.ts @@ -2,7 +2,7 @@ import pino from 'pino' import pinoHttp from 'pino-http' import { subsystemLogger } from '@atproto/common' import * as jwt from 'jsonwebtoken' -import { parseBasicAuth } from './auth' +import { parseBasicAuth } from './auth-verifier' export const dbLogger = subsystemLogger('pds:db') export const readStickyLogger = subsystemLogger('pds:read-sticky') diff --git a/packages/pds/src/services/auth.ts b/packages/pds/src/services/auth.ts index 7ad45be79cf..9e21cb9a629 100644 --- a/packages/pds/src/services/auth.ts +++ b/packages/pds/src/services/auth.ts @@ -1,17 +1,77 @@ +import * as jwt from 'jsonwebtoken' +import * as ui8 from 'uint8arrays' +import * as crypto from '@atproto/crypto' import { HOUR } from '@atproto/common' import Database from '../db' -import { RefreshToken, getRefreshTokenId } from '../auth' +import { AuthScope } from '../auth-verifier' const REFRESH_GRACE_MS = 2 * HOUR +export type AuthToken = { + scope: AuthScope + sub: string + exp: number +} + +export type RefreshToken = AuthToken & { jti: string } + export class AuthService { - constructor(public db: Database) {} + constructor(public db: Database, private _secret: string) {} + + static creator(jwtSecret: string) { + return (db: Database) => new AuthService(db, jwtSecret) + } + + createAccessToken(opts: { + did: string + scope?: AuthScope + expiresIn?: string | number + }) { + const { did, scope = AuthScope.Access, expiresIn = '120mins' } = opts + const payload = { + scope, + sub: did, + } + return { + payload: payload as AuthToken, // exp set by sign() + jwt: jwt.sign(payload, this._secret, { + expiresIn: expiresIn, + mutatePayload: true, + }), + } + } - static creator() { - return (db: Database) => new AuthService(db) + createRefreshToken(opts: { + did: string + jti?: string + expiresIn?: string | number + }) { + const { did, jti = getRefreshTokenId(), expiresIn = '90days' } = opts + const payload = { + scope: AuthScope.Refresh, + sub: did, + jti, + } + return { + payload: payload as RefreshToken, // exp set by sign() + jwt: jwt.sign(payload, this._secret, { + expiresIn: expiresIn, + mutatePayload: true, + }), + } } - async grantRefreshToken( + async createSession(did: string, appPasswordName: string | null) { + const access = this.createAccessToken({ + did, + scope: appPasswordName === null ? AuthScope.Access : AuthScope.AppPass, + }) + const refresh = this.createRefreshToken({ did }) + await this.storeRefreshToken(refresh.payload, appPasswordName) + return { access, refresh } + } + + async storeRefreshToken( payload: RefreshToken, appPasswordName: string | null, ) { @@ -27,9 +87,7 @@ export class AuthService { .executeTakeFirst() } - async rotateRefreshToken( - id: string, - ): Promise<{ nextId: string; appPassName: string | null } | null> { + async rotateRefreshToken(id: string) { this.db.assertTransaction() const token = await this.db.db .selectFrom('refresh_token') @@ -39,16 +97,26 @@ export class AuthService { .executeTakeFirst() if (!token) return null + // take the chance to tidy all of a user's expired tokens + const now = new Date() + await this.db.db + .deleteFrom('refresh_token') + .where('did', '=', token.did) + .where('expiresAt', '<=', now.toISOString()) + .returningAll() + .executeTakeFirst() + // Shorten the refresh token lifespan down from its // original expiration time to its revocation grace period. - - const now = new Date() const prevExpiresAt = new Date(token.expiresAt) const graceExpiresAt = new Date(now.getTime() + REFRESH_GRACE_MS) const expiresAt = graceExpiresAt < prevExpiresAt ? graceExpiresAt : prevExpiresAt - const expired = expiresAt <= now + + if (expiresAt <= now) { + return null + } // Determine the next refresh token id: upon refresh token // reuse you always receive a refresh token with the same id. @@ -56,20 +124,24 @@ export class AuthService { // Update token w/ possibly-updated expiration time // and next id, and tidy all of user's expired tokens. - await this.db.db .updateTable('refresh_token') .where('id', '=', id) .set({ expiresAt: expiresAt.toISOString(), nextId }) .executeTakeFirst() - await this.db.db - .deleteFrom('refresh_token') - .where('did', '=', token.did) - .where('expiresAt', '<=', now.toISOString()) - .returningAll() - .executeTakeFirst() - return expired ? null : { nextId, appPassName: token.appPasswordName } + const refresh = this.createRefreshToken({ + did: token.did, + jti: nextId, + }) + const access = this.createAccessToken({ + did: token.did, + scope: + token.appPasswordName === null ? AuthScope.Access : AuthScope.AppPass, + }) + await this.storeRefreshToken(refresh.payload, token.appPasswordName) + + return { access, refresh } } async revokeRefreshToken(id: string) { @@ -97,3 +169,7 @@ export class AuthService { return numDeletedRows > 0 } } + +const getRefreshTokenId = () => { + return ui8.toString(crypto.randomBytes(32), 'base64') +} diff --git a/packages/pds/src/services/index.ts b/packages/pds/src/services/index.ts index 954a5544e6e..5289e30e7e8 100644 --- a/packages/pds/src/services/index.ts +++ b/packages/pds/src/services/index.ts @@ -15,6 +15,7 @@ export function createServices(resources: { repoSigningKey: crypto.Keypair blobstore: BlobStore pdsHostname: string + jwtSecret: string appViewAgent?: AtpAgent appViewDid?: string appViewCdnUrlPattern?: string @@ -25,6 +26,7 @@ export function createServices(resources: { repoSigningKey, blobstore, pdsHostname, + jwtSecret, appViewAgent, appViewDid, appViewCdnUrlPattern, @@ -33,7 +35,7 @@ export function createServices(resources: { } = resources return { account: AccountService.creator(), - auth: AuthService.creator(), + auth: AuthService.creator(jwtSecret), record: RecordService.creator(), repo: RepoService.creator( repoSigningKey, diff --git a/packages/pds/tests/app-passwords.test.ts b/packages/pds/tests/app-passwords.test.ts index c8e1309dda8..0feb0a53712 100644 --- a/packages/pds/tests/app-passwords.test.ts +++ b/packages/pds/tests/app-passwords.test.ts @@ -66,7 +66,7 @@ describe('app_passwords', () => { const attempt = appAgent.api.com.atproto.server.createAppPassword({ name: 'another-one', }) - await expect(attempt).rejects.toThrow('Token could not be verified') + await expect(attempt).rejects.toThrow('Bad token scope') }) it('persists scope across refreshes', async () => { @@ -101,7 +101,7 @@ describe('app_passwords', () => { headers: { authorization: `Bearer ${session.data.accessJwt}` }, }, ) - await expect(attempt).rejects.toThrow('Token could not be verified') + await expect(attempt).rejects.toThrow('Bad token scope') }) it('lists available app-specific passwords', async () => { diff --git a/packages/pds/tests/auth.test.ts b/packages/pds/tests/auth.test.ts index d94eebf17e1..542001cddce 100644 --- a/packages/pds/tests/auth.test.ts +++ b/packages/pds/tests/auth.test.ts @@ -219,19 +219,19 @@ describe('auth', () => { password: 'password', }) const refreshWithAccess = refreshSession(account.accessJwt) - await expect(refreshWithAccess).rejects.toThrow( - 'Token could not be verified', - ) + await expect(refreshWithAccess).rejects.toThrow('Bad token scope') }) it('expired refresh token cannot be used to refresh a session.', async () => { - const { auth } = network.pds.ctx + const { services, db } = network.pds.ctx const account = await createAccount({ handle: 'holga.test', email: 'holga@test.com', password: 'password', }) - const refresh = auth.createRefreshToken({ did: account.did, expiresIn: -1 }) + const refresh = services + .auth(db) + .createRefreshToken({ did: account.did, expiresIn: -1 }) const refreshExpired = refreshSession(refresh.jwt) await expect(refreshExpired).rejects.toThrow('Token has expired') await deleteSession(refresh.jwt) // No problem revoking an expired token