Skip to content

Commit

Permalink
Add client-set proxy headers to PDS (#2251)
Browse files Browse the repository at this point in the history
* tidy bsky auth

* hook up new auth verifier

* update auth throughout ozone

* handle mod signing keys

* add client proxy heads to pds

* hook up rest of routes

* simplify pipethrough & add some SSRF protection

* tests

* fix bad var

* fix key parsing in pds

* fix admin auth test

* rename test

* add pipethrough to write routes

* update did doc id values

* null creds string -> `none`

* fix fetchLabels auth check

* ✨ Add a couple more proxied requests that we use in ozone ui

* Add runit to the services/bsky Dockerfile (#2254)

add runit to the services/bsky Dockerfile

* Improve tag detection (#2260)

* Allow tags to lead with and contain only numbers

* Break tags on other whitespace characters

* Export regexes from rich text detection

* Add test

* Add test

* Disallow number-only tags

* Avoid combining enclosing screen chars

* Allow full-width number sign

* Clarify tests

* Fix punctuation edge case

* Reorder

* Simplify, add another test

* Another test, comment

* Version packages (#2261)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* 🐛 Increment attempt count after each attempt to push ozone event (#2239)

* Ozone delegates email sending to actor's pds (#2272)

* ozone delegates email sending to user's pds

* lexicon: add content field to mod email event

* test email sending via mod event

* fix auth verifier method

* build branch

* fix url check

* better error handling for get account infos

* fix labeler service id

* fix iss on auth headers

* fix dev-env ozone did

* fix tests & another jwt issuer

* ozone: fix ip check

* fix aud check on pds mod service auth

* tidy

* fix pipethrough of headers

---------

Co-authored-by: Foysal Ahamed <[email protected]>
Co-authored-by: Jake Gold <[email protected]>
Co-authored-by: Eric Bailey <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: devin ivy <[email protected]>
  • Loading branch information
7 people authored Mar 7, 2024
1 parent 3988543 commit 2267f1e
Show file tree
Hide file tree
Showing 63 changed files with 472 additions and 562 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-and-push-bsky-ghcr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ on:
push:
branches:
- main
- appview-v2
- pds-proxy-headers
env:
REGISTRY: ghcr.io
USERNAME: ${{ github.actor }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build-and-push-ozone-aws.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ on:
push:
branches:
- main
- ozone-cdn-invalidation
- pds-proxy-headers
env:
REGISTRY: ${{ secrets.AWS_ECR_REGISTRY_USEAST2_PACKAGES_REGISTRY }}
USERNAME: ${{ secrets.AWS_ECR_REGISTRY_USEAST2_PACKAGES_USERNAME }}
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/build-and-push-pds-ghcr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ on:
push:
branches:
- main
- pds-proxy-headers
env:
REGISTRY: ghcr.io
USERNAME: ${{ github.actor }}
Expand Down
4 changes: 2 additions & 2 deletions packages/common-web/src/did-doc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export const getNotifEndpoint = (doc: DidDocument): string | undefined => {

export const getServiceEndpoint = (
doc: DidDocument,
opts: { id: string; type: string },
opts: { id: string; type?: string },
) => {
const did = getDid(doc)
let services = doc.service
Expand All @@ -94,7 +94,7 @@ export const getServiceEndpoint = (
(service) => service.id === opts.id || service.id === `${did}${opts.id}`,
)
if (!found) return undefined
if (found.type !== opts.type) {
if (opts.type && found.type !== opts.type) {
return undefined
}
if (typeof found.serviceEndpoint !== 'string') {
Expand Down
1 change: 1 addition & 0 deletions packages/dev-env/src/pds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export class TestPds {
await fs.mkdir(dataDirectory, { recursive: true })

const env: pds.ServerEnvironment = {
devMode: true,
port,
dataDirectory: dataDirectory,
blobstoreDiskLocation: blobstoreLoc,
Expand Down
17 changes: 4 additions & 13 deletions packages/pds/src/api/app/bsky/actor/getProfile.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Server } from '../../../../lexicon'
import AppContext from '../../../../context'
import { authPassthru } from '../../../proxy'
import { OutputSchema } from '../../../../lexicon/types/app/bsky/actor/getProfile'
import {
LocalViewer,
Expand All @@ -15,18 +14,10 @@ export default function (server: Server, ctx: AppContext) {
const { bskyAppView } = ctx.cfg
if (!bskyAppView) return
server.app.bsky.actor.getProfile({
auth: ctx.authVerifier.accessOrRole,
handler: async ({ req, auth, params }) => {
const requester =
auth.credentials.type === 'access' ? auth.credentials.did : null
const res = await pipethrough(
bskyAppView.url,
METHOD_NSID,
params,
requester
? await ctx.appviewAuthHeaders(requester, req)
: authPassthru(req),
)
auth: ctx.authVerifier.access,
handler: async ({ req, auth }) => {
const requester = auth.credentials.did
const res = await pipethrough(ctx, req, requester)
if (!requester) {
return res
}
Expand Down
9 changes: 2 additions & 7 deletions packages/pds/src/api/app/bsky/actor/getProfiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,10 @@ export default function (server: Server, ctx: AppContext) {
if (!bskyAppView) return
server.app.bsky.actor.getProfiles({
auth: ctx.authVerifier.access,
handler: async ({ auth, params, req }) => {
handler: async ({ req, auth }) => {
const requester = auth.credentials.did

const res = await pipethrough(
bskyAppView.url,
METHOD_NSID,
params,
await ctx.appviewAuthHeaders(requester, req),
)
const res = await pipethrough(ctx, req, requester)
return handleReadAfterWrite(
ctx,
METHOD_NSID,
Expand Down
9 changes: 2 additions & 7 deletions packages/pds/src/api/app/bsky/actor/getSuggestions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,9 @@ export default function (server: Server, ctx: AppContext) {
if (!bskyAppView) return
server.app.bsky.actor.getSuggestions({
auth: ctx.authVerifier.access,
handler: async ({ params, auth, req }) => {
handler: async ({ req, auth }) => {
const requester = auth.credentials.did
return pipethrough(
bskyAppView.url,
'app.bsky.actor.getSuggestions',
params,
await ctx.appviewAuthHeaders(requester, req),
)
return pipethrough(ctx, req, requester)
},
})
}
9 changes: 2 additions & 7 deletions packages/pds/src/api/app/bsky/actor/searchActors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,9 @@ export default function (server: Server, ctx: AppContext) {
if (!bskyAppView) return
server.app.bsky.actor.searchActors({
auth: ctx.authVerifier.access,
handler: async ({ params, auth, req }) => {
handler: async ({ req, auth }) => {
const requester = auth.credentials.did
return pipethrough(
bskyAppView.url,
'app.bsky.actor.searchActors',
params,
await ctx.appviewAuthHeaders(requester, req),
)
return pipethrough(ctx, req, requester)
},
})
}
9 changes: 2 additions & 7 deletions packages/pds/src/api/app/bsky/actor/searchActorsTypeahead.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,9 @@ export default function (server: Server, ctx: AppContext) {
if (!bskyAppView) return
server.app.bsky.actor.searchActorsTypeahead({
auth: ctx.authVerifier.access,
handler: async ({ params, auth, req }) => {
handler: async ({ req, auth }) => {
const requester = auth.credentials.did
return pipethrough(
bskyAppView.url,
'app.bsky.actor.searchActorsTypeahead',
params,
await ctx.appviewAuthHeaders(requester, req),
)
return pipethrough(ctx, req, requester)
},
})
}
9 changes: 2 additions & 7 deletions packages/pds/src/api/app/bsky/feed/getActorFeeds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,9 @@ export default function (server: Server, ctx: AppContext) {
if (!bskyAppView) return
server.app.bsky.feed.getActorFeeds({
auth: ctx.authVerifier.access,
handler: async ({ auth, params, req }) => {
handler: async ({ req, auth }) => {
const requester = auth.credentials.did
return pipethrough(
bskyAppView.url,
'app.bsky.feed.getActorFeeds',
params,
await ctx.appviewAuthHeaders(requester, req),
)
return pipethrough(ctx, req, requester)
},
})
}
17 changes: 4 additions & 13 deletions packages/pds/src/api/app/bsky/feed/getActorLikes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Server } from '../../../../lexicon'
import AppContext from '../../../../context'
import { authPassthru } from '../../../proxy'
import { OutputSchema } from '../../../../lexicon/types/app/bsky/feed/getAuthorFeed'
import {
LocalViewer,
Expand All @@ -15,18 +14,10 @@ export default function (server: Server, ctx: AppContext) {
const { bskyAppView } = ctx.cfg
if (!bskyAppView) return
server.app.bsky.feed.getActorLikes({
auth: ctx.authVerifier.accessOrRole,
handler: async ({ req, params, auth }) => {
const requester =
auth.credentials.type === 'access' ? auth.credentials.did : null
const res = await pipethrough(
bskyAppView.url,
METHOD_NSID,
params,
requester
? await ctx.appviewAuthHeaders(requester, req)
: authPassthru(req),
)
auth: ctx.authVerifier.access,
handler: async ({ req, auth }) => {
const requester = auth.credentials.did
const res = await pipethrough(ctx, req, requester)

if (!requester) {
return res
Expand Down
17 changes: 4 additions & 13 deletions packages/pds/src/api/app/bsky/feed/getAuthorFeed.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Server } from '../../../../lexicon'
import AppContext from '../../../../context'
import { authPassthru } from '../../../proxy'
import { OutputSchema } from '../../../../lexicon/types/app/bsky/feed/getAuthorFeed'
import { isReasonRepost } from '../../../../lexicon/types/app/bsky/feed/defs'
import {
Expand All @@ -16,18 +15,10 @@ export default function (server: Server, ctx: AppContext) {
const { bskyAppView } = ctx.cfg
if (!bskyAppView) return
server.app.bsky.feed.getAuthorFeed({
auth: ctx.authVerifier.accessOrRole,
handler: async ({ req, params, auth }) => {
const requester =
auth.credentials.type === 'access' ? auth.credentials.did : null
const res = await pipethrough(
bskyAppView.url,
METHOD_NSID,
params,
requester
? await ctx.appviewAuthHeaders(requester, req)
: authPassthru(req),
)
auth: ctx.authVerifier.access,
handler: async ({ req, auth }) => {
const requester = auth.credentials.did
const res = await pipethrough(ctx, req, requester)
if (!requester) {
return res
}
Expand Down
17 changes: 2 additions & 15 deletions packages/pds/src/api/app/bsky/feed/getFeed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,9 @@ export default function (server: Server, ctx: AppContext) {
const { data: feed } =
await appViewAgent.api.app.bsky.feed.getFeedGenerator(
{ feed: params.feed },
await ctx.appviewAuthHeaders(requester, req),
await ctx.appviewAuthHeaders(requester),
)
const serviceAuthHeaders = await ctx.serviceAuthHeaders(
requester,
feed.view.did,
req,
)
// forward accept-language header to upstream services
serviceAuthHeaders.headers['accept-language'] =
req.headers['accept-language']
return pipethrough(
bskyAppView.url,
'app.bsky.feed.getFeed',
params,
serviceAuthHeaders,
)
return pipethrough(ctx, req, requester, feed.view.did)
},
})
}
9 changes: 2 additions & 7 deletions packages/pds/src/api/app/bsky/feed/getFeedGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,9 @@ export default function (server: Server, ctx: AppContext) {
if (!bskyAppView) return
server.app.bsky.feed.getFeedGenerator({
auth: ctx.authVerifier.access,
handler: async ({ params, auth, req }) => {
handler: async ({ req, auth }) => {
const requester = auth.credentials.did
return pipethrough(
bskyAppView.url,
'app.bsky.feed.getFeedGenerator',
params,
await ctx.appviewAuthHeaders(requester, req),
)
return pipethrough(ctx, req, requester)
},
})
}
9 changes: 2 additions & 7 deletions packages/pds/src/api/app/bsky/feed/getFeedGenerators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,9 @@ export default function (server: Server, ctx: AppContext) {
if (!bskyAppView) return
server.app.bsky.feed.getFeedGenerators({
auth: ctx.authVerifier.access,
handler: async ({ params, auth, req }) => {
handler: async ({ req, auth }) => {
const requester = auth.credentials.did
return pipethrough(
bskyAppView.url,
'app.bsky.feed.getFeedGenerators',
params,
await ctx.appviewAuthHeaders(requester, req),
)
return pipethrough(ctx, req, requester)
},
})
}
9 changes: 2 additions & 7 deletions packages/pds/src/api/app/bsky/feed/getLikes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,9 @@ export default function (server: Server, ctx: AppContext) {
if (!bskyAppView) return
server.app.bsky.feed.getLikes({
auth: ctx.authVerifier.access,
handler: async ({ params, auth, req }) => {
handler: async ({ req, auth }) => {
const requester = auth.credentials.did
return pipethrough(
bskyAppView.url,
'app.bsky.feed.getLikes',
params,
await ctx.appviewAuthHeaders(requester, req),
)
return pipethrough(ctx, req, requester)
},
})
}
9 changes: 2 additions & 7 deletions packages/pds/src/api/app/bsky/feed/getListFeed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,9 @@ export default function (server: Server, ctx: AppContext) {
if (!bskyAppView) return
server.app.bsky.feed.getListFeed({
auth: ctx.authVerifier.access,
handler: async ({ auth, params, req }) => {
handler: async ({ req, auth }) => {
const requester = auth.credentials.did
return pipethrough(
bskyAppView.url,
'app.bsky.feed.getListFeed',
params,
await ctx.appviewAuthHeaders(requester, req),
)
return pipethrough(ctx, req, requester)
},
})
}
26 changes: 5 additions & 21 deletions packages/pds/src/api/app/bsky/feed/getPostThread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { AtUri } from '@atproto/syntax'
import { Headers, XRPCError } from '@atproto/xrpc'
import { Server } from '../../../../lexicon'
import AppContext from '../../../../context'
import { authPassthru } from '../../../proxy'
import {
ThreadViewPost,
isThreadViewPost,
Expand All @@ -30,27 +29,12 @@ export default function (server: Server, ctx: AppContext) {
const { bskyAppView } = ctx.cfg
if (!bskyAppView) return
server.app.bsky.feed.getPostThread({
auth: ctx.authVerifier.accessOrRole,
handler: async ({ req, params, auth }) => {
const requester =
auth.credentials.type === 'access' ? auth.credentials.did : null

if (!requester) {
return pipethrough(
bskyAppView.url,
METHOD_NSID,
params,
authPassthru(req),
)
}
auth: ctx.authVerifier.access,
handler: async ({ req, auth, params }) => {
const requester = auth.credentials.did

try {
const res = await pipethrough(
bskyAppView.url,
METHOD_NSID,
params,
await ctx.appviewAuthHeaders(requester, req),
)
const res = await pipethrough(ctx, req, requester)

return await handleReadAfterWrite(
ctx,
Expand Down Expand Up @@ -206,7 +190,7 @@ const readAfterWriteNotFound = async (
assert(ctx.appViewAgent)
const parentsRes = await ctx.appViewAgent.api.app.bsky.feed.getPostThread(
{ uri: highestParent, parentHeight: params.parentHeight, depth: 0 },
await ctx.appviewAuthHeaders(requester, null),
await ctx.appviewAuthHeaders(requester),
)
thread.parent = parentsRes.data.thread
} catch (err) {
Expand Down
9 changes: 2 additions & 7 deletions packages/pds/src/api/app/bsky/feed/getPosts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,9 @@ export default function (server: Server, ctx: AppContext) {
if (!bskyAppView) return
server.app.bsky.feed.getPosts({
auth: ctx.authVerifier.access,
handler: async ({ params, auth, req }) => {
handler: async ({ req, auth }) => {
const requester = auth.credentials.did
return pipethrough(
bskyAppView.url,
'app.bsky.feed.getPosts',
params,
await ctx.appviewAuthHeaders(requester, req),
)
return pipethrough(ctx, req, requester)
},
})
}
Loading

0 comments on commit 2267f1e

Please sign in to comment.