@atproto/bsky 0.0.250 → 0.0.253
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +49 -0
- package/dist/api/age-assurance/const.js +19 -19
- package/dist/api/age-assurance/const.js.map +1 -1
- package/dist/api/app/bsky/feed/getFeed.d.ts.map +1 -1
- package/dist/api/app/bsky/feed/getFeed.js +4 -0
- package/dist/api/app/bsky/feed/getFeed.js.map +1 -1
- package/dist/api/app/bsky/feed/searchPosts.js +5 -0
- package/dist/api/app/bsky/feed/searchPosts.js.map +1 -1
- package/dist/api/app/bsky/feed/searchPostsV2.js +5 -0
- package/dist/api/app/bsky/feed/searchPostsV2.js.map +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -0
- package/dist/config.js.map +1 -1
- package/dist/hydration/feed.d.ts +1 -2
- package/dist/hydration/feed.d.ts.map +1 -1
- package/dist/hydration/feed.js.map +1 -1
- package/dist/kws.d.ts +8 -0
- package/dist/kws.d.ts.map +1 -1
- package/dist/kws.js +53 -4
- package/dist/kws.js.map +1 -1
- package/package.json +28 -23
- package/bin/migration-create.ts +0 -46
- package/buf.gen.yaml +0 -12
- package/proto/bsky.proto +0 -1907
- package/proto/courier.proto +0 -84
- package/proto/rolodex.proto +0 -116
- package/src/api/age-assurance/const.ts +0 -203
- package/src/api/age-assurance/index.ts +0 -34
- package/src/api/age-assurance/kws/age-verified.test.ts +0 -98
- package/src/api/age-assurance/kws/age-verified.ts +0 -81
- package/src/api/age-assurance/kws/const.ts +0 -33
- package/src/api/age-assurance/kws/external-payload.test.ts +0 -72
- package/src/api/age-assurance/kws/external-payload.ts +0 -149
- package/src/api/age-assurance/redirects/kws-age-verified.ts +0 -107
- package/src/api/age-assurance/stash.ts +0 -23
- package/src/api/age-assurance/types.ts +0 -10
- package/src/api/age-assurance/util.ts +0 -68
- package/src/api/age-assurance/webhooks/kws-age-verified.ts +0 -75
- package/src/api/app/bsky/actor/getProfile.ts +0 -106
- package/src/api/app/bsky/actor/getProfiles.ts +0 -99
- package/src/api/app/bsky/actor/getSuggestions.ts +0 -163
- package/src/api/app/bsky/actor/searchActors.ts +0 -171
- package/src/api/app/bsky/actor/searchActorsTypeahead.ts +0 -164
- package/src/api/app/bsky/ageassurance/begin.ts +0 -175
- package/src/api/app/bsky/ageassurance/getConfig.ts +0 -16
- package/src/api/app/bsky/ageassurance/getState.ts +0 -58
- package/src/api/app/bsky/bookmark/createBookmark.ts +0 -39
- package/src/api/app/bsky/bookmark/deleteBookmark.ts +0 -32
- package/src/api/app/bsky/bookmark/getBookmarks.ts +0 -97
- package/src/api/app/bsky/bookmark/util.ts +0 -13
- package/src/api/app/bsky/contact/dismissMatch.ts +0 -26
- package/src/api/app/bsky/contact/getMatches.ts +0 -111
- package/src/api/app/bsky/contact/getSyncStatus.ts +0 -38
- package/src/api/app/bsky/contact/importContacts.ts +0 -119
- package/src/api/app/bsky/contact/removeData.ts +0 -25
- package/src/api/app/bsky/contact/sendNotification.ts +0 -33
- package/src/api/app/bsky/contact/startPhoneVerification.ts +0 -26
- package/src/api/app/bsky/contact/util.ts +0 -92
- package/src/api/app/bsky/contact/verifyPhone.ts +0 -29
- package/src/api/app/bsky/draft/createDraft.ts +0 -45
- package/src/api/app/bsky/draft/deleteDraft.ts +0 -20
- package/src/api/app/bsky/draft/getDrafts.ts +0 -44
- package/src/api/app/bsky/draft/updateDraft.ts +0 -26
- package/src/api/app/bsky/embed/getEmbedExternalView.ts +0 -154
- package/src/api/app/bsky/feed/getActorFeeds.ts +0 -101
- package/src/api/app/bsky/feed/getActorLikes.ts +0 -128
- package/src/api/app/bsky/feed/getAuthorFeed.ts +0 -279
- package/src/api/app/bsky/feed/getFeed.ts +0 -277
- package/src/api/app/bsky/feed/getFeedGenerator.ts +0 -68
- package/src/api/app/bsky/feed/getFeedGenerators.ts +0 -86
- package/src/api/app/bsky/feed/getLikes.ts +0 -151
- package/src/api/app/bsky/feed/getListFeed.ts +0 -147
- package/src/api/app/bsky/feed/getPostThread.ts +0 -156
- package/src/api/app/bsky/feed/getPosts.ts +0 -100
- package/src/api/app/bsky/feed/getQuotes.ts +0 -122
- package/src/api/app/bsky/feed/getRepostedBy.ts +0 -121
- package/src/api/app/bsky/feed/getSuggestedFeeds.ts +0 -39
- package/src/api/app/bsky/feed/getTimeline.ts +0 -127
- package/src/api/app/bsky/feed/searchPosts.ts +0 -267
- package/src/api/app/bsky/feed/searchPostsV2.ts +0 -236
- package/src/api/app/bsky/graph/getActorStarterPacks.ts +0 -103
- package/src/api/app/bsky/graph/getBlocks.ts +0 -94
- package/src/api/app/bsky/graph/getFollowers.ts +0 -153
- package/src/api/app/bsky/graph/getFollows.ts +0 -151
- package/src/api/app/bsky/graph/getKnownFollowers.ts +0 -123
- package/src/api/app/bsky/graph/getList.ts +0 -152
- package/src/api/app/bsky/graph/getListBlocks.ts +0 -87
- package/src/api/app/bsky/graph/getListMutes.ts +0 -87
- package/src/api/app/bsky/graph/getLists.ts +0 -125
- package/src/api/app/bsky/graph/getListsWithMembership.ts +0 -146
- package/src/api/app/bsky/graph/getMutes.ts +0 -87
- package/src/api/app/bsky/graph/getRelationships.ts +0 -58
- package/src/api/app/bsky/graph/getStarterPack.ts +0 -82
- package/src/api/app/bsky/graph/getStarterPacks.ts +0 -86
- package/src/api/app/bsky/graph/getStarterPacksWithMembership.ts +0 -136
- package/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts +0 -171
- package/src/api/app/bsky/graph/muteActor.ts +0 -24
- package/src/api/app/bsky/graph/muteActorList.ts +0 -19
- package/src/api/app/bsky/graph/muteThread.ts +0 -19
- package/src/api/app/bsky/graph/searchStarterPacks.ts +0 -169
- package/src/api/app/bsky/graph/unmuteActor.ts +0 -21
- package/src/api/app/bsky/graph/unmuteActorList.ts +0 -19
- package/src/api/app/bsky/graph/unmuteThread.ts +0 -19
- package/src/api/app/bsky/labeler/getServices.ts +0 -41
- package/src/api/app/bsky/notification/getPreferences.ts +0 -49
- package/src/api/app/bsky/notification/getUnreadCount.ts +0 -83
- package/src/api/app/bsky/notification/listActivitySubscriptions.ts +0 -116
- package/src/api/app/bsky/notification/listNotifications.ts +0 -272
- package/src/api/app/bsky/notification/putActivitySubscription.ts +0 -69
- package/src/api/app/bsky/notification/putPreferences.ts +0 -17
- package/src/api/app/bsky/notification/putPreferencesV2.ts +0 -64
- package/src/api/app/bsky/notification/registerPush.ts +0 -40
- package/src/api/app/bsky/notification/unregisterPush.ts +0 -39
- package/src/api/app/bsky/notification/updateSeen.ts +0 -52
- package/src/api/app/bsky/notification/util.ts +0 -134
- package/src/api/app/bsky/unspecced/getAgeAssuranceState.ts +0 -48
- package/src/api/app/bsky/unspecced/getConfig.ts +0 -20
- package/src/api/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.ts +0 -162
- package/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts +0 -91
- package/src/api/app/bsky/unspecced/getPostThreadOtherV2.ts +0 -126
- package/src/api/app/bsky/unspecced/getPostThreadV2.ts +0 -148
- package/src/api/app/bsky/unspecced/getSuggestedFeeds.ts +0 -100
- package/src/api/app/bsky/unspecced/getSuggestedOnboardingUsers.ts +0 -143
- package/src/api/app/bsky/unspecced/getSuggestedStarterPacks.ts +0 -165
- package/src/api/app/bsky/unspecced/getSuggestedUsers.ts +0 -183
- package/src/api/app/bsky/unspecced/getSuggestedUsersForDiscover.ts +0 -175
- package/src/api/app/bsky/unspecced/getSuggestedUsersForExplore.ts +0 -178
- package/src/api/app/bsky/unspecced/getSuggestedUsersForSeeMore.ts +0 -178
- package/src/api/app/bsky/unspecced/getTaggedSuggestions.ts +0 -27
- package/src/api/app/bsky/unspecced/getTrendingTopics.ts +0 -96
- package/src/api/app/bsky/unspecced/getTrends.ts +0 -162
- package/src/api/app/bsky/unspecced/initAgeAssurance.ts +0 -150
- package/src/api/blob-dispatcher.ts +0 -41
- package/src/api/blob-resolver.ts +0 -401
- package/src/api/com/atproto/admin/getAccountInfos.ts +0 -49
- package/src/api/com/atproto/admin/getSubjectStatus.ts +0 -79
- package/src/api/com/atproto/admin/updateSubjectStatus.ts +0 -80
- package/src/api/com/atproto/identity/resolveHandle.ts +0 -19
- package/src/api/com/atproto/label/queryLabels.ts +0 -42
- package/src/api/com/atproto/repo/getRecord.ts +0 -44
- package/src/api/com/atproto/temp/fetchLabels.ts +0 -9
- package/src/api/external.ts +0 -15
- package/src/api/health.ts +0 -47
- package/src/api/index.ts +0 -216
- package/src/api/internal/bsky/actor/getProfiles.ts +0 -87
- package/src/api/kws/api.ts +0 -113
- package/src/api/kws/index.ts +0 -29
- package/src/api/kws/types.ts +0 -78
- package/src/api/kws/util.test.ts +0 -50
- package/src/api/kws/util.ts +0 -109
- package/src/api/kws/webhook.ts +0 -134
- package/src/api/sitemap.ts +0 -76
- package/src/api/util.ts +0 -45
- package/src/api/well-known.ts +0 -44
- package/src/auth-verifier.ts +0 -522
- package/src/bsync.ts +0 -41
- package/src/cache/read-through.ts +0 -157
- package/src/config.ts +0 -710
- package/src/context.ts +0 -143
- package/src/courier.ts +0 -41
- package/src/data-plane/client/hosts.ts +0 -103
- package/src/data-plane/client/index.ts +0 -125
- package/src/data-plane/client/util.test.ts +0 -29
- package/src/data-plane/client/util.ts +0 -74
- package/src/data-plane/index.ts +0 -2
- package/src/data-plane/server/background.ts +0 -66
- package/src/data-plane/server/bsync-subscription.ts +0 -590
- package/src/data-plane/server/db/database-schema.ts +0 -90
- package/src/data-plane/server/db/db.ts +0 -204
- package/src/data-plane/server/db/index.ts +0 -2
- package/src/data-plane/server/db/migrations/20230309T045948368Z-init.ts +0 -305
- package/src/data-plane/server/db/migrations/20230408T152211201Z-notification-init.ts +0 -25
- package/src/data-plane/server/db/migrations/20230417T210628672Z-moderation-init.ts +0 -127
- package/src/data-plane/server/db/migrations/20230420T211446071Z-did-cache.ts +0 -14
- package/src/data-plane/server/db/migrations/20230427T194702079Z-notif-record-index.ts +0 -14
- package/src/data-plane/server/db/migrations/20230605T144730094Z-post-profile-aggs.ts +0 -23
- package/src/data-plane/server/db/migrations/20230607T211442112Z-feed-generator-init.ts +0 -34
- package/src/data-plane/server/db/migrations/20230608T155101190Z-algo-whats-hot-view.ts +0 -85
- package/src/data-plane/server/db/migrations/20230608T201813132Z-mute-lists.ts +0 -78
- package/src/data-plane/server/db/migrations/20230608T205147239Z-mutes.ts +0 -15
- package/src/data-plane/server/db/migrations/20230609T153623961Z-blocks.ts +0 -33
- package/src/data-plane/server/db/migrations/20230609T232122649Z-actor-deletion-indexes.ts +0 -27
- package/src/data-plane/server/db/migrations/20230610T203555962Z-suggested-follows.ts +0 -13
- package/src/data-plane/server/db/migrations/20230611T215300060Z-actor-state.ts +0 -13
- package/src/data-plane/server/db/migrations/20230620T161134972Z-post-langs.ts +0 -9
- package/src/data-plane/server/db/migrations/20230627T212437895Z-optional-handle.ts +0 -15
- package/src/data-plane/server/db/migrations/20230629T220835893Z-remove-post-hierarchy.ts +0 -32
- package/src/data-plane/server/db/migrations/20230703T045536691Z-feed-and-label-indices.ts +0 -31
- package/src/data-plane/server/db/migrations/20230720T164800037Z-posts-cursor-idx.ts +0 -19
- package/src/data-plane/server/db/migrations/20230807T035309811Z-feed-item-delete-invite-for-user-idx.ts +0 -14
- package/src/data-plane/server/db/migrations/20230808T172902639Z-repo-rev.ts +0 -12
- package/src/data-plane/server/db/migrations/20230810T203349843Z-action-duration.ts +0 -23
- package/src/data-plane/server/db/migrations/20230817T195936007Z-native-notifications.ts +0 -16
- package/src/data-plane/server/db/migrations/20230830T205507322Z-suggested-feeds.ts +0 -13
- package/src/data-plane/server/db/migrations/20230904T211011773Z-block-lists.ts +0 -24
- package/src/data-plane/server/db/migrations/20230906T222220386Z-thread-gating.ts +0 -27
- package/src/data-plane/server/db/migrations/20230920T213858047Z-add-tags-to-post.ts +0 -9
- package/src/data-plane/server/db/migrations/20230929T192920807Z-record-cursor-indexes.ts +0 -40
- package/src/data-plane/server/db/migrations/20231003T202833377Z-create-moderation-subject-status.ts +0 -123
- package/src/data-plane/server/db/migrations/20231220T225126090Z-blob-takedowns.ts +0 -66
- package/src/data-plane/server/db/migrations/20240124T023719200Z-tagged-suggestions.ts +0 -15
- package/src/data-plane/server/db/migrations/20240226T225725627Z-labelers.ts +0 -27
- package/src/data-plane/server/db/migrations/20240530T170337073Z-account-deactivation.ts +0 -12
- package/src/data-plane/server/db/migrations/20240606T171229898Z-thread-mutes.ts +0 -15
- package/src/data-plane/server/db/migrations/20240606T222548219Z-starter-packs.ts +0 -45
- package/src/data-plane/server/db/migrations/20240719T203853939Z-priority-notifs.ts +0 -25
- package/src/data-plane/server/db/migrations/20240723T220700077Z-quotes-post-aggs.ts +0 -12
- package/src/data-plane/server/db/migrations/20240723T220703655Z-quotes.ts +0 -28
- package/src/data-plane/server/db/migrations/20240801T193939827Z-post-gate.ts +0 -17
- package/src/data-plane/server/db/migrations/20240808T224251220Z-post-gate-flags.ts +0 -25
- package/src/data-plane/server/db/migrations/20240829T211238293Z-simplify-actor-sync.ts +0 -23
- package/src/data-plane/server/db/migrations/20240831T134810923Z-pinned-posts.ts +0 -17
- package/src/data-plane/server/db/migrations/20241114T153108102Z-add-starter-packs-name.ts +0 -19
- package/src/data-plane/server/db/migrations/20250116T222618297Z-post-embed-video.ts +0 -17
- package/src/data-plane/server/db/migrations/20250207T174822012Z-add-label-exp.ts +0 -9
- package/src/data-plane/server/db/migrations/20250404T163421487Z-verifications.ts +0 -39
- package/src/data-plane/server/db/migrations/20250526T023712742Z-like-repost-via.ts +0 -17
- package/src/data-plane/server/db/migrations/20250528T221913281Z-add-record-tags.ts +0 -9
- package/src/data-plane/server/db/migrations/20250602T190357447Z-add-private-data.ts +0 -22
- package/src/data-plane/server/db/migrations/20250611T140649895Z-add-activity-subscription.ts +0 -22
- package/src/data-plane/server/db/migrations/20250627T025331240Z-add-actor-age-assurance-columns.ts +0 -22
- package/src/data-plane/server/db/migrations/20250812T183735692Z-add-bookmarks.ts +0 -23
- package/src/data-plane/server/db/migrations/20250813T174955711Z-add-post-agg-bookmarks.ts +0 -12
- package/src/data-plane/server/db/migrations/20251120T004738098Z-update-actor-age-assurance-v2.ts +0 -28
- package/src/data-plane/server/db/migrations/20260112T133951271Z-add-drafts.ts +0 -24
- package/src/data-plane/server/db/migrations/20260604T224952774Z-post-embed-gallery-image.ts +0 -19
- package/src/data-plane/server/db/migrations/index.ts +0 -60
- package/src/data-plane/server/db/migrations/provider.ts +0 -26
- package/src/data-plane/server/db/pagination.ts +0 -341
- package/src/data-plane/server/db/tables/activity-subscription.ts +0 -12
- package/src/data-plane/server/db/tables/actor-block.ts +0 -14
- package/src/data-plane/server/db/tables/actor-state.ts +0 -10
- package/src/data-plane/server/db/tables/actor-sync.ts +0 -9
- package/src/data-plane/server/db/tables/actor.ts +0 -19
- package/src/data-plane/server/db/tables/algo.ts +0 -11
- package/src/data-plane/server/db/tables/blob-takedown.ts +0 -9
- package/src/data-plane/server/db/tables/bookmark.ts +0 -11
- package/src/data-plane/server/db/tables/did-cache.ts +0 -13
- package/src/data-plane/server/db/tables/draft.ts +0 -11
- package/src/data-plane/server/db/tables/duplicate-record.ts +0 -12
- package/src/data-plane/server/db/tables/feed-generator.ts +0 -21
- package/src/data-plane/server/db/tables/feed-item.ts +0 -12
- package/src/data-plane/server/db/tables/follow.ts +0 -15
- package/src/data-plane/server/db/tables/label.ts +0 -13
- package/src/data-plane/server/db/tables/labeler.ts +0 -16
- package/src/data-plane/server/db/tables/like.ts +0 -18
- package/src/data-plane/server/db/tables/list-block.ts +0 -15
- package/src/data-plane/server/db/tables/list-item.ts +0 -16
- package/src/data-plane/server/db/tables/list-mute.ts +0 -9
- package/src/data-plane/server/db/tables/list.ts +0 -19
- package/src/data-plane/server/db/tables/mute.ts +0 -9
- package/src/data-plane/server/db/tables/notification-push-token.ts +0 -10
- package/src/data-plane/server/db/tables/notification.ts +0 -16
- package/src/data-plane/server/db/tables/post-agg.ts +0 -16
- package/src/data-plane/server/db/tables/post-embed.ts +0 -47
- package/src/data-plane/server/db/tables/post-gate.ts +0 -12
- package/src/data-plane/server/db/tables/post.ts +0 -28
- package/src/data-plane/server/db/tables/private-data.ts +0 -13
- package/src/data-plane/server/db/tables/profile-agg.ts +0 -14
- package/src/data-plane/server/db/tables/profile.ts +0 -17
- package/src/data-plane/server/db/tables/quote.ts +0 -15
- package/src/data-plane/server/db/tables/record.ts +0 -15
- package/src/data-plane/server/db/tables/repost.ts +0 -18
- package/src/data-plane/server/db/tables/starter-pack.ts +0 -17
- package/src/data-plane/server/db/tables/subscription.ts +0 -9
- package/src/data-plane/server/db/tables/suggested-feed.ts +0 -10
- package/src/data-plane/server/db/tables/suggested-follow.ts +0 -10
- package/src/data-plane/server/db/tables/tagged-suggestion.ts +0 -11
- package/src/data-plane/server/db/tables/thread-gate.ts +0 -12
- package/src/data-plane/server/db/tables/thread-mute.ts +0 -9
- package/src/data-plane/server/db/tables/verification.ts +0 -20
- package/src/data-plane/server/db/tables/view-param.ts +0 -12
- package/src/data-plane/server/db/types.ts +0 -12
- package/src/data-plane/server/db/util.ts +0 -67
- package/src/data-plane/server/index.ts +0 -44
- package/src/data-plane/server/indexing/index.ts +0 -458
- package/src/data-plane/server/indexing/plugins/block.ts +0 -84
- package/src/data-plane/server/indexing/plugins/chat-declaration.ts +0 -60
- package/src/data-plane/server/indexing/plugins/feed-generator.ts +0 -80
- package/src/data-plane/server/indexing/plugins/follow.ts +0 -132
- package/src/data-plane/server/indexing/plugins/germ-declaration.ts +0 -57
- package/src/data-plane/server/indexing/plugins/labeler.ts +0 -74
- package/src/data-plane/server/indexing/plugins/like.ts +0 -151
- package/src/data-plane/server/indexing/plugins/list-block.ts +0 -84
- package/src/data-plane/server/indexing/plugins/list-item.ts +0 -92
- package/src/data-plane/server/indexing/plugins/list.ts +0 -80
- package/src/data-plane/server/indexing/plugins/notif-declaration.ts +0 -57
- package/src/data-plane/server/indexing/plugins/post-gate.ts +0 -101
- package/src/data-plane/server/indexing/plugins/post.ts +0 -675
- package/src/data-plane/server/indexing/plugins/profile.ts +0 -90
- package/src/data-plane/server/indexing/plugins/repost.ts +0 -176
- package/src/data-plane/server/indexing/plugins/starter-pack.ts +0 -74
- package/src/data-plane/server/indexing/plugins/status.ts +0 -57
- package/src/data-plane/server/indexing/plugins/thread-gate.ts +0 -101
- package/src/data-plane/server/indexing/plugins/verification.ts +0 -113
- package/src/data-plane/server/indexing/processor.ts +0 -292
- package/src/data-plane/server/routes/activity-subscription.ts +0 -84
- package/src/data-plane/server/routes/blocks.ts +0 -127
- package/src/data-plane/server/routes/bookmarks.ts +0 -83
- package/src/data-plane/server/routes/drafts.ts +0 -37
- package/src/data-plane/server/routes/feed-gens.ts +0 -89
- package/src/data-plane/server/routes/feeds.ts +0 -176
- package/src/data-plane/server/routes/follows.ts +0 -141
- package/src/data-plane/server/routes/identity.ts +0 -59
- package/src/data-plane/server/routes/index.ts +0 -67
- package/src/data-plane/server/routes/interactions.ts +0 -120
- package/src/data-plane/server/routes/labels.ts +0 -55
- package/src/data-plane/server/routes/likes.ts +0 -92
- package/src/data-plane/server/routes/lists.ts +0 -88
- package/src/data-plane/server/routes/moderation.ts +0 -102
- package/src/data-plane/server/routes/mutes.ts +0 -195
- package/src/data-plane/server/routes/notifs.ts +0 -239
- package/src/data-plane/server/routes/profile.ts +0 -220
- package/src/data-plane/server/routes/quotes.ts +0 -32
- package/src/data-plane/server/routes/records.ts +0 -119
- package/src/data-plane/server/routes/relationships.ts +0 -174
- package/src/data-plane/server/routes/reposts.ts +0 -76
- package/src/data-plane/server/routes/search.ts +0 -181
- package/src/data-plane/server/routes/site-standard.ts +0 -12
- package/src/data-plane/server/routes/sitemap.ts +0 -43
- package/src/data-plane/server/routes/starter-packs.ts +0 -32
- package/src/data-plane/server/routes/suggestions.ts +0 -175
- package/src/data-plane/server/routes/sync.ts +0 -16
- package/src/data-plane/server/routes/threads.ts +0 -33
- package/src/data-plane/server/subscription.ts +0 -152
- package/src/data-plane/server/util.ts +0 -202
- package/src/error.ts +0 -12
- package/src/etcd.ts +0 -90
- package/src/feature-gates/README.md +0 -83
- package/src/feature-gates/gates.ts +0 -25
- package/src/feature-gates/index.ts +0 -235
- package/src/feature-gates/metrics.test.ts +0 -196
- package/src/feature-gates/metrics.ts +0 -107
- package/src/feature-gates/types.ts +0 -62
- package/src/feature-gates/utils.test.ts +0 -66
- package/src/feature-gates/utils.ts +0 -135
- package/src/hydration/actor.ts +0 -578
- package/src/hydration/external.test.ts +0 -281
- package/src/hydration/external.ts +0 -268
- package/src/hydration/feed.ts +0 -456
- package/src/hydration/graph.ts +0 -354
- package/src/hydration/hydrator.ts +0 -1835
- package/src/hydration/label.ts +0 -207
- package/src/hydration/util.ts +0 -199
- package/src/image/index.ts +0 -2
- package/src/image/invalidator.ts +0 -33
- package/src/image/logger.ts +0 -6
- package/src/image/server.ts +0 -228
- package/src/image/sharp.ts +0 -89
- package/src/image/uri.ts +0 -114
- package/src/image/util.ts +0 -41
- package/src/index.ts +0 -312
- package/src/kws.ts +0 -197
- package/src/logger.ts +0 -40
- package/src/pipeline.ts +0 -60
- package/src/redis.ts +0 -205
- package/src/rolodex.ts +0 -42
- package/src/stash.ts +0 -76
- package/src/util/debug.ts +0 -10
- package/src/util/http.ts +0 -42
- package/src/util/retry.ts +0 -10
- package/src/util/standard-site.test.ts +0 -423
- package/src/util/standard-site.ts +0 -196
- package/src/util/uris.ts +0 -38
- package/src/util.ts +0 -48
- package/src/views/index.ts +0 -2783
- package/src/views/threads-v2.ts +0 -510
- package/src/views/types.ts +0 -193
- package/src/views/util.ts +0 -114
- package/test.env +0 -2
- package/tests/__snapshots__/feed-generation.test.ts.snap +0 -2463
- package/tests/_util.ts +0 -292
- package/tests/admin/admin-auth.test.ts +0 -190
- package/tests/admin/moderation.test.ts +0 -222
- package/tests/auth.test.ts +0 -90
- package/tests/blob-resolver.test.ts +0 -125
- package/tests/data-plane/__snapshots__/indexing.test.ts.snap +0 -887
- package/tests/data-plane/db.test.ts +0 -189
- package/tests/data-plane/duplicate-records.test.ts +0 -156
- package/tests/data-plane/handle-invalidation.test.ts +0 -153
- package/tests/data-plane/indexing.test.ts +0 -827
- package/tests/data-plane/subscription.test.ts +0 -128
- package/tests/data-plane/thread-mutes.test.ts +0 -175
- package/tests/entryway-auth.test.ts +0 -177
- package/tests/etcd.test.ts +0 -302
- package/tests/feed-generation.test.ts +0 -919
- package/tests/hydration/util.test.ts +0 -119
- package/tests/image/server.test.ts +0 -97
- package/tests/image/sharp.test.ts +0 -199
- package/tests/image/uri.test.ts +0 -106
- package/tests/label-hydration.test.ts +0 -245
- package/tests/postgates.test.ts +0 -182
- package/tests/query-labels.test.ts +0 -85
- package/tests/redis-cache.test.ts +0 -230
- package/tests/seed/feed-hidden-replies.ts +0 -63
- package/tests/seed/get-suggested-starter-packs.ts +0 -64
- package/tests/seed/get-trends.ts +0 -71
- package/tests/seed/known-followers.ts +0 -111
- package/tests/seed/postgates.ts +0 -57
- package/tests/server.test.ts +0 -115
- package/tests/sitemap.test.ts +0 -75
- package/tests/stash.test.ts +0 -180
- package/tests/utils.test.ts +0 -36
- package/tests/views/__snapshots__/actor-search.test.ts.snap +0 -155
- package/tests/views/__snapshots__/author-feed.test.ts.snap +0 -6301
- package/tests/views/__snapshots__/block-lists.test.ts.snap +0 -690
- package/tests/views/__snapshots__/blocks.test.ts.snap +0 -462
- package/tests/views/__snapshots__/bookmarks.test.ts.snap +0 -379
- package/tests/views/__snapshots__/follows.test.ts.snap +0 -798
- package/tests/views/__snapshots__/labeler-service.test.ts.snap +0 -233
- package/tests/views/__snapshots__/likes.test.ts.snap +0 -124
- package/tests/views/__snapshots__/list-feed.test.ts.snap +0 -883
- package/tests/views/__snapshots__/lists.test.ts.snap +0 -650
- package/tests/views/__snapshots__/mute-lists.test.ts.snap +0 -705
- package/tests/views/__snapshots__/mutes.test.ts.snap +0 -353
- package/tests/views/__snapshots__/notifications.test.ts.snap +0 -3074
- package/tests/views/__snapshots__/posts.test.ts.snap +0 -1019
- package/tests/views/__snapshots__/profile.test.ts.snap +0 -811
- package/tests/views/__snapshots__/quotes.test.ts.snap +0 -445
- package/tests/views/__snapshots__/reposts.test.ts.snap +0 -112
- package/tests/views/__snapshots__/starter-packs.test.ts.snap +0 -836
- package/tests/views/__snapshots__/thread-v2.test.ts.snap +0 -1298
- package/tests/views/__snapshots__/thread.test.ts.snap +0 -2051
- package/tests/views/__snapshots__/threadgating.test.ts.snap +0 -189
- package/tests/views/__snapshots__/timeline.test.ts.snap +0 -7252
- package/tests/views/account-deactivation.test.ts +0 -81
- package/tests/views/actor-likes.test.ts +0 -138
- package/tests/views/actor-search.test.ts +0 -261
- package/tests/views/age-assurance-v2.test.ts +0 -823
- package/tests/views/age-assurance.test.ts +0 -479
- package/tests/views/author-feed.test.ts +0 -694
- package/tests/views/block-lists.test.ts +0 -661
- package/tests/views/blocks.test.ts +0 -889
- package/tests/views/bookmarks.test.ts +0 -345
- package/tests/views/drafts.test.ts +0 -430
- package/tests/views/feed-hidden-replies.test.ts +0 -243
- package/tests/views/feed-view-post.test.ts +0 -501
- package/tests/views/follows.test.ts +0 -372
- package/tests/views/get-config.test.ts +0 -64
- package/tests/views/get-suggested-onboarding-users.test.ts +0 -193
- package/tests/views/get-suggested-starter-packs.test.ts +0 -137
- package/tests/views/get-trends.test.ts +0 -141
- package/tests/views/internal-actor.test.ts +0 -127
- package/tests/views/known-followers.test.ts +0 -193
- package/tests/views/labeler-service.test.ts +0 -242
- package/tests/views/labels-needs-review.test.ts +0 -316
- package/tests/views/labels-takedown.test.ts +0 -247
- package/tests/views/likes.test.ts +0 -192
- package/tests/views/list-feed.test.ts +0 -195
- package/tests/views/lists.test.ts +0 -412
- package/tests/views/mute-lists.test.ts +0 -509
- package/tests/views/mutes.test.ts +0 -308
- package/tests/views/notifications.test.ts +0 -1581
- package/tests/views/post-search.test.ts +0 -200
- package/tests/views/posts-debug.test.ts +0 -79
- package/tests/views/posts.test.ts +0 -427
- package/tests/views/profile-debug.test.ts +0 -75
- package/tests/views/profile.test.ts +0 -795
- package/tests/views/quotes.test.ts +0 -133
- package/tests/views/reposts.test.ts +0 -112
- package/tests/views/starter-packs.test.ts +0 -395
- package/tests/views/suggestions.test.ts +0 -145
- package/tests/views/thread-v2.test.ts +0 -2005
- package/tests/views/thread.test.ts +0 -637
- package/tests/views/threadgating.test.ts +0 -843
- package/tests/views/timeline.test.ts +0 -328
- package/tests/views/verification.test.ts +0 -296
- package/tsconfig.build.json +0 -10
- package/tsconfig.build.tsbuildinfo +0 -1
- package/tsconfig.json +0 -7
- package/tsconfig.tests.json +0 -8
- package/vitest.config.ts +0 -10
package/src/auth-verifier.ts
DELETED
|
@@ -1,522 +0,0 @@
|
|
|
1
|
-
import crypto, { KeyObject } from 'node:crypto'
|
|
2
|
-
import express from 'express'
|
|
3
|
-
import * as jose from 'jose'
|
|
4
|
-
import KeyEncoderModule from 'key-encoder'
|
|
5
|
-
import * as ui8 from 'uint8arrays'
|
|
6
|
-
import { SECP256K1_JWT_ALG, parseDidKey } from '@atproto/crypto'
|
|
7
|
-
import { DidString, isDidString } from '@atproto/lex'
|
|
8
|
-
import {
|
|
9
|
-
AuthRequiredError,
|
|
10
|
-
VerifySignatureWithKeyFn,
|
|
11
|
-
cryptoVerifySignatureWithKey,
|
|
12
|
-
parseReqNsid,
|
|
13
|
-
verifyJwt as verifyServiceJwt,
|
|
14
|
-
} from '@atproto/xrpc-server'
|
|
15
|
-
import {
|
|
16
|
-
Code,
|
|
17
|
-
DataPlaneClient,
|
|
18
|
-
getKeyAsDidKey,
|
|
19
|
-
isDataplaneError,
|
|
20
|
-
unpackIdentityKeys,
|
|
21
|
-
} from './data-plane/index.js'
|
|
22
|
-
import { GetIdentityByDidResponse } from './proto/bsky_pb.js'
|
|
23
|
-
|
|
24
|
-
// key-encoder is CJS with exports.default; Node ESM interop wraps it as { default: Class }
|
|
25
|
-
const KeyEncoder = ((m) => m.default ?? m)(KeyEncoderModule)
|
|
26
|
-
|
|
27
|
-
type ReqCtx = {
|
|
28
|
-
req: express.Request
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
type StandardAuthOpts = {
|
|
32
|
-
skipAudCheck?: boolean
|
|
33
|
-
lxmCheck?: (method?: string) => boolean
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export enum RoleStatus {
|
|
37
|
-
Valid,
|
|
38
|
-
Invalid,
|
|
39
|
-
Missing,
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
type NullOutput = {
|
|
43
|
-
credentials: {
|
|
44
|
-
type: 'none'
|
|
45
|
-
iss: null
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
type StandardOutput = {
|
|
50
|
-
credentials: {
|
|
51
|
-
type: 'standard'
|
|
52
|
-
/** @note we don't validate this to be a {@link DidString} (we might want to in the future) */
|
|
53
|
-
aud: string
|
|
54
|
-
iss: DidString | `${DidString}#${string}`
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
type RoleOutput = {
|
|
59
|
-
credentials: {
|
|
60
|
-
type: 'role'
|
|
61
|
-
admin: boolean
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
type ModServiceOutput = {
|
|
66
|
-
credentials: {
|
|
67
|
-
type: 'mod_service'
|
|
68
|
-
aud: DidString
|
|
69
|
-
iss: DidString | `${DidString}#${string}`
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const ALLOWED_AUTH_SCOPES = new Set([
|
|
74
|
-
'com.atproto.access',
|
|
75
|
-
'com.atproto.appPass',
|
|
76
|
-
'com.atproto.appPassPrivileged',
|
|
77
|
-
])
|
|
78
|
-
|
|
79
|
-
export type AuthVerifierOpts = {
|
|
80
|
-
ownDid: DidString
|
|
81
|
-
alternateAudienceDids: DidString[]
|
|
82
|
-
modServiceDid: DidString
|
|
83
|
-
adminPasses: string[]
|
|
84
|
-
entrywayJwtPublicKey?: KeyObject
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export class AuthVerifier {
|
|
88
|
-
public ownDid: DidString
|
|
89
|
-
public standardAudienceDids: Set<DidString>
|
|
90
|
-
public modServiceDid: DidString
|
|
91
|
-
private adminPasses: Set<string>
|
|
92
|
-
private entrywayJwtPublicKey?: KeyObject
|
|
93
|
-
|
|
94
|
-
constructor(
|
|
95
|
-
public dataplane: DataPlaneClient,
|
|
96
|
-
opts: AuthVerifierOpts,
|
|
97
|
-
) {
|
|
98
|
-
this.ownDid = opts.ownDid
|
|
99
|
-
this.standardAudienceDids = new Set([
|
|
100
|
-
opts.ownDid,
|
|
101
|
-
...opts.alternateAudienceDids,
|
|
102
|
-
])
|
|
103
|
-
this.modServiceDid = opts.modServiceDid
|
|
104
|
-
this.adminPasses = new Set(opts.adminPasses)
|
|
105
|
-
this.entrywayJwtPublicKey = opts.entrywayJwtPublicKey
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// verifiers (arrow fns to preserve scope)
|
|
109
|
-
standardOptionalParameterized =
|
|
110
|
-
(opts: StandardAuthOpts) =>
|
|
111
|
-
async (ctx: ReqCtx): Promise<StandardOutput | NullOutput> => {
|
|
112
|
-
// @TODO remove! basic auth + did supported just for testing.
|
|
113
|
-
if (isBasicToken(ctx.req)) {
|
|
114
|
-
const aud = this.ownDid
|
|
115
|
-
const iss = ctx.req.headers['appview-as-did']
|
|
116
|
-
if (typeof iss !== 'string' || !isDidString(iss)) {
|
|
117
|
-
throw new AuthRequiredError('bad issuer')
|
|
118
|
-
}
|
|
119
|
-
if (!this.parseRoleCreds(ctx.req).admin) {
|
|
120
|
-
throw new AuthRequiredError('bad credentials')
|
|
121
|
-
}
|
|
122
|
-
return {
|
|
123
|
-
credentials: { type: 'standard', iss, aud },
|
|
124
|
-
}
|
|
125
|
-
} else if (isBearerToken(ctx.req)) {
|
|
126
|
-
// @NOTE temporarily accept entryway session tokens to shed load from PDS instances
|
|
127
|
-
const token = bearerTokenFromReq(ctx.req)
|
|
128
|
-
const header = token ? jose.decodeProtectedHeader(token) : undefined
|
|
129
|
-
if (header?.typ === 'at+jwt') {
|
|
130
|
-
// we should never use entryway session tokens in the case of flexible auth audiences (namely in the case of getFeed)
|
|
131
|
-
if (opts.skipAudCheck) {
|
|
132
|
-
throw new AuthRequiredError('Malformed token', 'InvalidToken')
|
|
133
|
-
}
|
|
134
|
-
return this.entrywaySession(ctx)
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const { iss, aud } = await this.verifyServiceJwt(ctx, {
|
|
138
|
-
lxmCheck: opts.lxmCheck,
|
|
139
|
-
iss: null,
|
|
140
|
-
aud: null,
|
|
141
|
-
})
|
|
142
|
-
if (
|
|
143
|
-
!opts.skipAudCheck &&
|
|
144
|
-
!(this.standardAudienceDids as Set<string>).has(aud)
|
|
145
|
-
) {
|
|
146
|
-
throw new AuthRequiredError(
|
|
147
|
-
'jwt audience does not match service did',
|
|
148
|
-
'BadJwtAudience',
|
|
149
|
-
)
|
|
150
|
-
}
|
|
151
|
-
return {
|
|
152
|
-
credentials: {
|
|
153
|
-
type: 'standard',
|
|
154
|
-
iss,
|
|
155
|
-
aud,
|
|
156
|
-
},
|
|
157
|
-
}
|
|
158
|
-
} else {
|
|
159
|
-
return this.nullCreds()
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
standardOptional: (ctx: ReqCtx) => Promise<StandardOutput | NullOutput> =
|
|
164
|
-
this.standardOptionalParameterized({})
|
|
165
|
-
|
|
166
|
-
standard = async (ctx: ReqCtx): Promise<StandardOutput> => {
|
|
167
|
-
const output = await this.standardOptional(ctx)
|
|
168
|
-
if (output.credentials.type === 'none') {
|
|
169
|
-
throw new AuthRequiredError(undefined, 'AuthMissing')
|
|
170
|
-
}
|
|
171
|
-
return output as StandardOutput
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
role = (ctx: ReqCtx): RoleOutput => {
|
|
175
|
-
const creds = this.parseRoleCreds(ctx.req)
|
|
176
|
-
if (creds.status !== RoleStatus.Valid) {
|
|
177
|
-
throw new AuthRequiredError()
|
|
178
|
-
}
|
|
179
|
-
return {
|
|
180
|
-
credentials: {
|
|
181
|
-
...creds,
|
|
182
|
-
type: 'role',
|
|
183
|
-
},
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
standardOrRole = async (
|
|
188
|
-
ctx: ReqCtx,
|
|
189
|
-
): Promise<StandardOutput | RoleOutput> => {
|
|
190
|
-
if (isBearerToken(ctx.req)) {
|
|
191
|
-
return this.standard(ctx)
|
|
192
|
-
} else {
|
|
193
|
-
return this.role(ctx)
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
optionalStandardOrRole = async (
|
|
198
|
-
ctx: ReqCtx,
|
|
199
|
-
): Promise<StandardOutput | RoleOutput | NullOutput> => {
|
|
200
|
-
if (isBearerToken(ctx.req)) {
|
|
201
|
-
return await this.standard(ctx)
|
|
202
|
-
} else {
|
|
203
|
-
const creds = this.parseRoleCreds(ctx.req)
|
|
204
|
-
if (creds.status === RoleStatus.Valid) {
|
|
205
|
-
return {
|
|
206
|
-
credentials: {
|
|
207
|
-
...creds,
|
|
208
|
-
type: 'role',
|
|
209
|
-
},
|
|
210
|
-
}
|
|
211
|
-
} else if (creds.status === RoleStatus.Missing) {
|
|
212
|
-
return this.nullCreds()
|
|
213
|
-
} else {
|
|
214
|
-
throw new AuthRequiredError()
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// @NOTE this auth verifier method is not recommended to be implemented by most appviews
|
|
220
|
-
// this is a short term fix to remove proxy load from Bluesky's PDS and in line with possible
|
|
221
|
-
// future plans to have the client talk directly with the appview
|
|
222
|
-
entrywaySession = async (reqCtx: ReqCtx): Promise<StandardOutput> => {
|
|
223
|
-
const token = bearerTokenFromReq(reqCtx.req)
|
|
224
|
-
if (!token) {
|
|
225
|
-
throw new AuthRequiredError(undefined, 'AuthMissing')
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// if entryway jwt key not configured then do not parsed these tokens
|
|
229
|
-
if (!this.entrywayJwtPublicKey) {
|
|
230
|
-
throw new AuthRequiredError('Malformed token', 'InvalidToken')
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const res = await jose
|
|
234
|
-
.jwtVerify(token, this.entrywayJwtPublicKey)
|
|
235
|
-
.catch((err) => {
|
|
236
|
-
if (err?.['code'] === 'ERR_JWT_EXPIRED') {
|
|
237
|
-
throw new AuthRequiredError('Token has expired', 'ExpiredToken')
|
|
238
|
-
}
|
|
239
|
-
throw new AuthRequiredError(
|
|
240
|
-
'Token could not be verified',
|
|
241
|
-
'InvalidToken',
|
|
242
|
-
)
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
const { sub, aud, scope, cnf } = res.payload
|
|
246
|
-
if (typeof cnf !== 'undefined') {
|
|
247
|
-
// Proof-of-Possession (PoP) tokens are not allowed here
|
|
248
|
-
// https://www.rfc-editor.org/rfc/rfc7800.html
|
|
249
|
-
throw new AuthRequiredError(
|
|
250
|
-
'Malformed token: DPoP not supported',
|
|
251
|
-
'InvalidToken',
|
|
252
|
-
)
|
|
253
|
-
}
|
|
254
|
-
if (typeof sub !== 'string' || !sub.startsWith('did:')) {
|
|
255
|
-
throw new AuthRequiredError('Malformed token', 'InvalidToken')
|
|
256
|
-
} else if (
|
|
257
|
-
typeof aud !== 'string' ||
|
|
258
|
-
!aud.startsWith('did:web:') ||
|
|
259
|
-
!aud.endsWith('.bsky.network')
|
|
260
|
-
) {
|
|
261
|
-
throw new AuthRequiredError('Bad token aud', 'InvalidToken')
|
|
262
|
-
} else if (typeof scope !== 'string' || !ALLOWED_AUTH_SCOPES.has(scope)) {
|
|
263
|
-
throw new AuthRequiredError('Bad token scope', 'InvalidToken')
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
return {
|
|
267
|
-
credentials: {
|
|
268
|
-
type: 'standard',
|
|
269
|
-
aud: this.ownDid,
|
|
270
|
-
iss: sub as DidString | `${DidString}#${string}`,
|
|
271
|
-
},
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
modService = async (reqCtx: ReqCtx): Promise<ModServiceOutput> => {
|
|
276
|
-
const { iss, aud } = await this.verifyServiceJwt(reqCtx, {
|
|
277
|
-
aud: this.ownDid,
|
|
278
|
-
iss: [this.modServiceDid, `${this.modServiceDid}#atproto_labeler`],
|
|
279
|
-
})
|
|
280
|
-
return { credentials: { type: 'mod_service', aud, iss } }
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
roleOrModService = async (
|
|
284
|
-
reqCtx: ReqCtx,
|
|
285
|
-
): Promise<RoleOutput | ModServiceOutput> => {
|
|
286
|
-
if (isBearerToken(reqCtx.req)) {
|
|
287
|
-
return this.modService(reqCtx)
|
|
288
|
-
} else {
|
|
289
|
-
return this.role(reqCtx)
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
parseRoleCreds(req: express.Request) {
|
|
294
|
-
const parsed = parseBasicAuth(req.headers.authorization || '')
|
|
295
|
-
const { Missing, Valid, Invalid } = RoleStatus
|
|
296
|
-
if (!parsed) {
|
|
297
|
-
return { status: Missing, admin: false, moderator: false, triage: false }
|
|
298
|
-
}
|
|
299
|
-
const { username, password } = parsed
|
|
300
|
-
if (username === 'admin' && this.adminPasses.has(password)) {
|
|
301
|
-
return { status: Valid, admin: true }
|
|
302
|
-
}
|
|
303
|
-
return { status: Invalid, admin: false }
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
async verifyServiceJwt<
|
|
307
|
-
TOptions extends {
|
|
308
|
-
iss: string[] | null
|
|
309
|
-
aud: string | null
|
|
310
|
-
lxmCheck?: (method?: string) => boolean
|
|
311
|
-
},
|
|
312
|
-
>(reqCtx: ReqCtx, opts: TOptions) {
|
|
313
|
-
const getSigningKey = async (
|
|
314
|
-
iss: string,
|
|
315
|
-
_forceRefresh: boolean, // @TODO consider propagating to dataplane
|
|
316
|
-
): Promise<string> => {
|
|
317
|
-
if (opts.iss !== null && !opts.iss.includes(iss)) {
|
|
318
|
-
throw new AuthRequiredError('Untrusted issuer', 'UntrustedIss')
|
|
319
|
-
}
|
|
320
|
-
const [did, serviceId] = iss.split('#')
|
|
321
|
-
if (!isDidString(did)) {
|
|
322
|
-
throw new AuthRequiredError('identity unknown')
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
const keyId =
|
|
326
|
-
serviceId === 'atproto_labeler' ? 'atproto_label' : 'atproto'
|
|
327
|
-
let identity: GetIdentityByDidResponse
|
|
328
|
-
try {
|
|
329
|
-
identity = await this.dataplane.getIdentityByDid({ did })
|
|
330
|
-
} catch (err) {
|
|
331
|
-
if (isDataplaneError(err, Code.NotFound)) {
|
|
332
|
-
throw new AuthRequiredError('identity unknown')
|
|
333
|
-
}
|
|
334
|
-
throw err
|
|
335
|
-
}
|
|
336
|
-
const keys = unpackIdentityKeys(identity.keys)
|
|
337
|
-
const didKey = getKeyAsDidKey(keys, { id: keyId })
|
|
338
|
-
if (!didKey) {
|
|
339
|
-
throw new AuthRequiredError('missing or bad key')
|
|
340
|
-
}
|
|
341
|
-
return didKey
|
|
342
|
-
}
|
|
343
|
-
const assertLxmCheck = () => {
|
|
344
|
-
const lxm = parseReqNsid(reqCtx.req)
|
|
345
|
-
if (
|
|
346
|
-
(opts.lxmCheck && !opts.lxmCheck(payload.lxm)) ||
|
|
347
|
-
(!opts.lxmCheck && payload.lxm !== lxm)
|
|
348
|
-
) {
|
|
349
|
-
throw new AuthRequiredError(
|
|
350
|
-
payload.lxm !== undefined
|
|
351
|
-
? `bad jwt lexicon method ("lxm"). must match: ${lxm}`
|
|
352
|
-
: `missing jwt lexicon method ("lxm"). must match: ${lxm}`,
|
|
353
|
-
'BadJwtLexiconMethod',
|
|
354
|
-
)
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
const jwtStr = bearerTokenFromReq(reqCtx.req)
|
|
359
|
-
if (!jwtStr) {
|
|
360
|
-
throw new AuthRequiredError('missing jwt', 'MissingJwt')
|
|
361
|
-
}
|
|
362
|
-
// if validating additional scopes, skip scope check in initial validation & follow up afterwards
|
|
363
|
-
const payload = await verifyServiceJwt(
|
|
364
|
-
jwtStr,
|
|
365
|
-
opts.aud,
|
|
366
|
-
null,
|
|
367
|
-
getSigningKey,
|
|
368
|
-
verifySignatureWithKey,
|
|
369
|
-
)
|
|
370
|
-
if (
|
|
371
|
-
!payload.iss.endsWith('#atproto_labeler') ||
|
|
372
|
-
payload.lxm !== undefined
|
|
373
|
-
) {
|
|
374
|
-
// @TODO currently permissive of labelers who dont set lxm yet.
|
|
375
|
-
// we'll allow ozone self-hosters to upgrade before removing this condition.
|
|
376
|
-
assertLxmCheck()
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
return {
|
|
380
|
-
iss: payload.iss as (DidString | `${DidString}#${string}`) &
|
|
381
|
-
(TOptions extends { iss: ReadonlyArray<infer I> } ? I : unknown),
|
|
382
|
-
aud: payload.aud as string &
|
|
383
|
-
(TOptions extends { aud: infer A extends string } ? A : unknown),
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
isModService(iss: string): iss is DidString | `${DidString}#atproto_labeler` {
|
|
388
|
-
return [
|
|
389
|
-
this.modServiceDid,
|
|
390
|
-
`${this.modServiceDid}#atproto_labeler`,
|
|
391
|
-
].includes(iss)
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
nullCreds(): NullOutput {
|
|
395
|
-
return {
|
|
396
|
-
credentials: {
|
|
397
|
-
type: 'none',
|
|
398
|
-
iss: null,
|
|
399
|
-
},
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
parseCreds(
|
|
404
|
-
creds: StandardOutput | RoleOutput | ModServiceOutput | NullOutput,
|
|
405
|
-
) {
|
|
406
|
-
const viewer =
|
|
407
|
-
creds.credentials.type === 'standard' ? creds.credentials.iss : null
|
|
408
|
-
const includeTakedownsAnd3pBlocks =
|
|
409
|
-
(creds.credentials.type === 'role' && creds.credentials.admin) ||
|
|
410
|
-
creds.credentials.type === 'mod_service' ||
|
|
411
|
-
(creds.credentials.type === 'standard' &&
|
|
412
|
-
this.isModService(creds.credentials.iss))
|
|
413
|
-
const canPerformTakedown =
|
|
414
|
-
(creds.credentials.type === 'role' && creds.credentials.admin) ||
|
|
415
|
-
creds.credentials.type === 'mod_service'
|
|
416
|
-
const isModService =
|
|
417
|
-
creds.credentials.type === 'mod_service' ||
|
|
418
|
-
(creds.credentials.type === 'standard' &&
|
|
419
|
-
this.isModService(creds.credentials.iss))
|
|
420
|
-
|
|
421
|
-
return {
|
|
422
|
-
viewer,
|
|
423
|
-
includeTakedowns: includeTakedownsAnd3pBlocks,
|
|
424
|
-
include3pBlocks: includeTakedownsAnd3pBlocks,
|
|
425
|
-
canPerformTakedown,
|
|
426
|
-
isModService,
|
|
427
|
-
skipViewerBlocks: isModService && viewer !== null,
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// HELPERS
|
|
433
|
-
// ---------
|
|
434
|
-
|
|
435
|
-
const BEARER = 'Bearer '
|
|
436
|
-
const BASIC = 'Basic '
|
|
437
|
-
|
|
438
|
-
const isBearerToken = (req: express.Request): boolean => {
|
|
439
|
-
return req.headers.authorization?.startsWith(BEARER) ?? false
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
const isBasicToken = (req: express.Request): boolean => {
|
|
443
|
-
return req.headers.authorization?.startsWith(BASIC) ?? false
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
const bearerTokenFromReq = (req: express.Request) => {
|
|
447
|
-
const header = req.headers.authorization || ''
|
|
448
|
-
if (!header.startsWith(BEARER)) return null
|
|
449
|
-
return header.slice(BEARER.length).trim()
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
export const parseBasicAuth = (
|
|
453
|
-
token: string,
|
|
454
|
-
): { username: string; password: string } | null => {
|
|
455
|
-
if (!token.startsWith(BASIC)) return null
|
|
456
|
-
const b64 = token.slice(BASIC.length)
|
|
457
|
-
let parsed: string[]
|
|
458
|
-
try {
|
|
459
|
-
parsed = ui8.toString(ui8.fromString(b64, 'base64pad'), 'utf8').split(':')
|
|
460
|
-
} catch (err) {
|
|
461
|
-
return null
|
|
462
|
-
}
|
|
463
|
-
const [username, password] = parsed
|
|
464
|
-
if (!username || !password) return null
|
|
465
|
-
return { username, password }
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
export const buildBasicAuth = (username: string, password: string): string => {
|
|
469
|
-
return (
|
|
470
|
-
BASIC +
|
|
471
|
-
ui8.toString(ui8.fromString(`${username}:${password}`, 'utf8'), 'base64pad')
|
|
472
|
-
)
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
const keyEncoder = new KeyEncoder('secp256k1')
|
|
476
|
-
export const createPublicKeyObject = (publicKeyHex: string): KeyObject => {
|
|
477
|
-
const key = keyEncoder.encodePublic(publicKeyHex, 'raw', 'pem')
|
|
478
|
-
return crypto.createPublicKey({ format: 'pem', key })
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
const verifySig = (
|
|
482
|
-
publicKey: Uint8Array,
|
|
483
|
-
data: Uint8Array,
|
|
484
|
-
sig: Uint8Array,
|
|
485
|
-
) => {
|
|
486
|
-
const keyEncoder = new KeyEncoder('secp256k1')
|
|
487
|
-
|
|
488
|
-
const pemKey = keyEncoder.encodePublic(
|
|
489
|
-
ui8.toString(publicKey, 'hex'),
|
|
490
|
-
'raw',
|
|
491
|
-
'pem',
|
|
492
|
-
)
|
|
493
|
-
const key = crypto.createPublicKey({ format: 'pem', key: pemKey })
|
|
494
|
-
|
|
495
|
-
return crypto.verify(
|
|
496
|
-
'sha256',
|
|
497
|
-
data,
|
|
498
|
-
{
|
|
499
|
-
key,
|
|
500
|
-
dsaEncoding: 'ieee-p1363',
|
|
501
|
-
},
|
|
502
|
-
sig,
|
|
503
|
-
)
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
export const verifySignatureWithKey: VerifySignatureWithKeyFn = async (
|
|
507
|
-
didKey: string,
|
|
508
|
-
msgBytes: Uint8Array,
|
|
509
|
-
sigBytes: Uint8Array,
|
|
510
|
-
alg: string,
|
|
511
|
-
) => {
|
|
512
|
-
if (alg === SECP256K1_JWT_ALG) {
|
|
513
|
-
const parsed = parseDidKey(didKey)
|
|
514
|
-
if (alg !== parsed.jwtAlg) {
|
|
515
|
-
throw new Error(`Expected key alg ${alg}, got ${parsed.jwtAlg}`)
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
return verifySig(parsed.keyBytes, msgBytes, sigBytes)
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
return cryptoVerifySignatureWithKey(didKey, msgBytes, sigBytes, alg)
|
|
522
|
-
}
|
package/src/bsync.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Code,
|
|
3
|
-
ConnectError,
|
|
4
|
-
Interceptor,
|
|
5
|
-
PromiseClient,
|
|
6
|
-
createPromiseClient,
|
|
7
|
-
} from '@connectrpc/connect'
|
|
8
|
-
import {
|
|
9
|
-
ConnectTransportOptions,
|
|
10
|
-
createConnectTransport,
|
|
11
|
-
} from '@connectrpc/connect-node'
|
|
12
|
-
import { Service } from './proto/bsync_connect.js'
|
|
13
|
-
|
|
14
|
-
export type BsyncClient = PromiseClient<typeof Service>
|
|
15
|
-
|
|
16
|
-
export const createBsyncClient = (
|
|
17
|
-
opts: ConnectTransportOptions,
|
|
18
|
-
): BsyncClient => {
|
|
19
|
-
const transport = createConnectTransport(opts)
|
|
20
|
-
return createPromiseClient(Service, transport)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export { Code }
|
|
24
|
-
|
|
25
|
-
export const isBsyncError = (
|
|
26
|
-
err: unknown,
|
|
27
|
-
code?: Code,
|
|
28
|
-
): err is ConnectError => {
|
|
29
|
-
if (err instanceof ConnectError) {
|
|
30
|
-
return !code || err.code === code
|
|
31
|
-
}
|
|
32
|
-
return false
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export const authWithApiKey =
|
|
36
|
-
(apiKey: string): Interceptor =>
|
|
37
|
-
(next) =>
|
|
38
|
-
(req) => {
|
|
39
|
-
req.header.set('authorization', `Bearer ${apiKey}`)
|
|
40
|
-
return next(req)
|
|
41
|
-
}
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { cacheLogger as log } from '../logger.js'
|
|
2
|
-
import { Redis } from '../redis.js'
|
|
3
|
-
|
|
4
|
-
export type CacheItem<T> = {
|
|
5
|
-
val: T | null // null here is for negative caching
|
|
6
|
-
updatedAt: number
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export type CacheOptions<T> = {
|
|
10
|
-
staleTTL: number
|
|
11
|
-
maxTTL: number
|
|
12
|
-
fetchMethod: (key: string) => Promise<T | null>
|
|
13
|
-
fetchManyMethod?: (keys: string[]) => Promise<Record<string, T | null>>
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export class ReadThroughCache<T> {
|
|
17
|
-
constructor(
|
|
18
|
-
public redis: Redis,
|
|
19
|
-
public opts: CacheOptions<T>,
|
|
20
|
-
) {}
|
|
21
|
-
|
|
22
|
-
private async _fetchMany(keys: string[]): Promise<Record<string, T | null>> {
|
|
23
|
-
let result: Record<string, T | null> = {}
|
|
24
|
-
if (this.opts.fetchManyMethod) {
|
|
25
|
-
result = await this.opts.fetchManyMethod(keys)
|
|
26
|
-
} else {
|
|
27
|
-
const got = await Promise.all(keys.map((k) => this.opts.fetchMethod(k)))
|
|
28
|
-
for (let i = 0; i < keys.length; i++) {
|
|
29
|
-
result[keys[i]] = got[i] ?? null
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
// ensure caching negatives
|
|
33
|
-
for (const key of keys) {
|
|
34
|
-
result[key] ??= null
|
|
35
|
-
}
|
|
36
|
-
return result
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
private async fetchAndCache(key: string): Promise<T | null> {
|
|
40
|
-
const fetched = await this.opts.fetchMethod(key)
|
|
41
|
-
this.set(key, fetched).catch((err) =>
|
|
42
|
-
log.error({ err, key }, 'failed to set cache value'),
|
|
43
|
-
)
|
|
44
|
-
return fetched
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
private async fetchAndCacheMany(keys: string[]): Promise<Record<string, T>> {
|
|
48
|
-
const fetched = await this._fetchMany(keys)
|
|
49
|
-
this.setMany(fetched).catch((err) =>
|
|
50
|
-
log.error({ err, keys }, 'failed to set cache values'),
|
|
51
|
-
)
|
|
52
|
-
return removeNulls(fetched)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async get(key: string, opts?: { revalidate?: boolean }): Promise<T | null> {
|
|
56
|
-
if (opts?.revalidate) {
|
|
57
|
-
return this.fetchAndCache(key)
|
|
58
|
-
}
|
|
59
|
-
let cached: CacheItem<T> | null
|
|
60
|
-
try {
|
|
61
|
-
const got = await this.redis.get(key)
|
|
62
|
-
cached = got ? JSON.parse(got) : null
|
|
63
|
-
} catch (err) {
|
|
64
|
-
cached = null
|
|
65
|
-
log.warn({ key, err }, 'failed to fetch value from cache')
|
|
66
|
-
}
|
|
67
|
-
if (!cached || this.isExpired(cached)) {
|
|
68
|
-
return this.fetchAndCache(key)
|
|
69
|
-
}
|
|
70
|
-
if (this.isStale(cached)) {
|
|
71
|
-
this.fetchAndCache(key).catch((err) =>
|
|
72
|
-
log.warn({ key, err }, 'failed to refresh stale cache value'),
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
return cached.val
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async getMany(
|
|
79
|
-
keys: string[],
|
|
80
|
-
opts?: { revalidate?: boolean },
|
|
81
|
-
): Promise<Record<string, T>> {
|
|
82
|
-
if (opts?.revalidate) {
|
|
83
|
-
return this.fetchAndCacheMany(keys)
|
|
84
|
-
}
|
|
85
|
-
let cached: Record<string, string>
|
|
86
|
-
try {
|
|
87
|
-
cached = await this.redis.getMulti(keys)
|
|
88
|
-
} catch (err) {
|
|
89
|
-
cached = {}
|
|
90
|
-
log.warn({ keys, err }, 'failed to fetch values from cache')
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const stale: string[] = []
|
|
94
|
-
const toFetch: string[] = []
|
|
95
|
-
const results: Record<string, T> = {}
|
|
96
|
-
for (const key of keys) {
|
|
97
|
-
const val = cached[key] ? (JSON.parse(cached[key]) as CacheItem<T>) : null
|
|
98
|
-
if (!val || this.isExpired(val)) {
|
|
99
|
-
toFetch.push(key)
|
|
100
|
-
continue
|
|
101
|
-
}
|
|
102
|
-
if (this.isStale(val)) {
|
|
103
|
-
stale.push(key)
|
|
104
|
-
}
|
|
105
|
-
if (val.val) {
|
|
106
|
-
results[key] = val.val
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
const fetched = await this.fetchAndCacheMany(toFetch)
|
|
110
|
-
this.fetchAndCacheMany(stale).catch((err) =>
|
|
111
|
-
log.warn({ keys, err }, 'failed to refresh stale cache values'),
|
|
112
|
-
)
|
|
113
|
-
return {
|
|
114
|
-
...results,
|
|
115
|
-
...fetched,
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async set(key: string, val: T | null) {
|
|
120
|
-
await this.setMany({ [key]: val })
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
async setMany(vals: Record<string, T | null>) {
|
|
124
|
-
const items: Record<string, string> = {}
|
|
125
|
-
for (const key of Object.keys(vals)) {
|
|
126
|
-
items[key] = JSON.stringify({
|
|
127
|
-
val: vals[key],
|
|
128
|
-
updatedAt: Date.now(),
|
|
129
|
-
})
|
|
130
|
-
}
|
|
131
|
-
await this.redis.setMulti(items, this.opts.maxTTL)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async clearEntry(key: string) {
|
|
135
|
-
await this.redis.del(key)
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
isExpired(result: CacheItem<T>) {
|
|
139
|
-
return Date.now() > result.updatedAt + this.opts.maxTTL
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
isStale(result: CacheItem<T>) {
|
|
143
|
-
return Date.now() > result.updatedAt + this.opts.staleTTL
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const removeNulls = <T>(obj: Record<string, T | null>): Record<string, T> => {
|
|
148
|
-
return Object.entries(obj).reduce(
|
|
149
|
-
(acc, [key, val]) => {
|
|
150
|
-
if (val !== null) {
|
|
151
|
-
acc[key] = val
|
|
152
|
-
}
|
|
153
|
-
return acc
|
|
154
|
-
},
|
|
155
|
-
{} as Record<string, T>,
|
|
156
|
-
)
|
|
157
|
-
}
|