add auth
This commit is contained in:
parent
2a13e9e97c
commit
84420cc7aa
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,2 @@
|
|||||||
node_modules
|
node_modules
|
||||||
.env
|
.env
|
||||||
test.sqlite
|
|
||||||
|
@ -10,9 +10,10 @@
|
|||||||
"start": "ts-node src/index.ts"
|
"start": "ts-node src/index.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@atproto/did-resolver": "^0.1.0",
|
||||||
"@atproto/repo": "^0.1.0",
|
"@atproto/repo": "^0.1.0",
|
||||||
"@atproto/uri": "^0.0.2",
|
"@atproto/uri": "^0.0.2",
|
||||||
"@atproto/xrpc-server": "^0.1.0",
|
"@atproto/xrpc-server": "^0.2.0",
|
||||||
"better-sqlite3": "^8.3.0",
|
"better-sqlite3": "^8.3.0",
|
||||||
"dotenv": "^16.0.3",
|
"dotenv": "^16.0.3",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
|
18
src/auth.ts
Normal file
18
src/auth.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import express from 'express'
|
||||||
|
import { verifyJwt, AuthRequiredError } from '@atproto/xrpc-server'
|
||||||
|
import { DidResolver } from '@atproto/did-resolver'
|
||||||
|
|
||||||
|
export const validateAuth = async (
|
||||||
|
req: express.Request,
|
||||||
|
serviceDid: string,
|
||||||
|
didResolver: DidResolver,
|
||||||
|
): Promise<string> => {
|
||||||
|
const { authorization = '' } = req.headers
|
||||||
|
if (!authorization.startsWith('Bearer ')) {
|
||||||
|
throw new AuthRequiredError()
|
||||||
|
}
|
||||||
|
const jwt = authorization.replace('Bearer ', '').trim()
|
||||||
|
return verifyJwt(jwt, serviceDid, async (did: string) => {
|
||||||
|
return didResolver.resolveAtprotoKey(did)
|
||||||
|
})
|
||||||
|
}
|
15
src/config.ts
Normal file
15
src/config.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { Database } from './db'
|
||||||
|
import { DidResolver } from '@atproto/did-resolver'
|
||||||
|
|
||||||
|
export type AppContext = {
|
||||||
|
db: Database
|
||||||
|
didResolver: DidResolver
|
||||||
|
cfg: Config
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Config = {
|
||||||
|
port: number
|
||||||
|
sqliteLocation: string
|
||||||
|
subscriptionEndpoint: string
|
||||||
|
serviceDid: string
|
||||||
|
}
|
@ -1,13 +1,22 @@
|
|||||||
import { InvalidRequestError } from '@atproto/xrpc-server'
|
import { InvalidRequestError } from '@atproto/xrpc-server'
|
||||||
import { Database } from './db'
|
|
||||||
import { Server } from './lexicon'
|
import { Server } from './lexicon'
|
||||||
|
import { AppContext } from './config'
|
||||||
|
import { validateAuth } from './auth'
|
||||||
|
|
||||||
export default function (server: Server, db: Database) {
|
export default function (server: Server, ctx: AppContext) {
|
||||||
server.app.bsky.feed.getFeedSkeleton(async ({ params, auth }) => {
|
server.app.bsky.feed.getFeedSkeleton(async ({ params, req }) => {
|
||||||
if (params.feed !== 'alf.bsky.social') {
|
if (params.feed !== 'did:example:alice/app.bsky.feed.generator/whats-alf') {
|
||||||
throw new InvalidRequestError('algorithm unsupported')
|
throw new InvalidRequestError('algorithm unsupported')
|
||||||
}
|
}
|
||||||
let builder = db
|
// example of how to check auth
|
||||||
|
// feel free to remove if requesterDid is not used
|
||||||
|
const requesterDid = await validateAuth(
|
||||||
|
req,
|
||||||
|
ctx.cfg.serviceDid,
|
||||||
|
ctx.didResolver,
|
||||||
|
)
|
||||||
|
|
||||||
|
let builder = ctx.db
|
||||||
.selectFrom('post')
|
.selectFrom('post')
|
||||||
.selectAll()
|
.selectAll()
|
||||||
.orderBy('indexedAt', 'desc')
|
.orderBy('indexedAt', 'desc')
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
import http from 'http'
|
import http from 'http'
|
||||||
import events from 'events'
|
import events from 'events'
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
|
import { DidResolver, MemoryCache } from '@atproto/did-resolver'
|
||||||
import { createServer } from './lexicon'
|
import { createServer } from './lexicon'
|
||||||
import feedGeneration from './feed-generation'
|
import feedGeneration from './feed-generation'
|
||||||
import { createDb, Database, migrateToLatest } from './db'
|
import { createDb, Database, migrateToLatest } from './db'
|
||||||
import { FirehoseSubscription } from './subscription'
|
import { FirehoseSubscription } from './subscription'
|
||||||
|
import { AppContext, Config } from './config'
|
||||||
export type Config = {
|
|
||||||
port: number
|
|
||||||
sqliteLocation: string
|
|
||||||
subscriptionEndpoint: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export class FeedGenerator {
|
export class FeedGenerator {
|
||||||
public app: express.Application
|
public app: express.Application
|
||||||
@ -36,11 +32,18 @@ export class FeedGenerator {
|
|||||||
port: config?.port ?? 3000,
|
port: config?.port ?? 3000,
|
||||||
sqliteLocation: config?.sqliteLocation ?? 'test.sqlite',
|
sqliteLocation: config?.sqliteLocation ?? 'test.sqlite',
|
||||||
subscriptionEndpoint: config?.subscriptionEndpoint ?? 'wss://bsky.social',
|
subscriptionEndpoint: config?.subscriptionEndpoint ?? 'wss://bsky.social',
|
||||||
|
serviceDid: config?.serviceDid ?? 'did:example:test',
|
||||||
}
|
}
|
||||||
const app = express()
|
const app = express()
|
||||||
const db = createDb(cfg.sqliteLocation)
|
const db = createDb(cfg.sqliteLocation)
|
||||||
const firehose = new FirehoseSubscription(db, cfg.subscriptionEndpoint)
|
const firehose = new FirehoseSubscription(db, cfg.subscriptionEndpoint)
|
||||||
|
|
||||||
|
const didCache = new MemoryCache()
|
||||||
|
const didResolver = new DidResolver(
|
||||||
|
{ plcUrl: 'https://plc.directory' },
|
||||||
|
didCache,
|
||||||
|
)
|
||||||
|
|
||||||
const server = createServer({
|
const server = createServer({
|
||||||
validateResponse: true,
|
validateResponse: true,
|
||||||
payload: {
|
payload: {
|
||||||
@ -49,7 +52,12 @@ export class FeedGenerator {
|
|||||||
blobLimit: 5 * 1024 * 1024, // 5mb
|
blobLimit: 5 * 1024 * 1024, // 5mb
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
feedGeneration(server, db)
|
const ctx: AppContext = {
|
||||||
|
db,
|
||||||
|
didResolver,
|
||||||
|
cfg,
|
||||||
|
}
|
||||||
|
feedGeneration(server, ctx)
|
||||||
app.use(server.xrpc.router)
|
app.use(server.xrpc.router)
|
||||||
|
|
||||||
return new FeedGenerator(app, db, firehose, cfg)
|
return new FeedGenerator(app, db, firehose, cfg)
|
||||||
|
57
yarn.lock
57
yarn.lock
@ -43,6 +43,16 @@
|
|||||||
axios "^0.24.0"
|
axios "^0.24.0"
|
||||||
did-resolver "^4.0.0"
|
did-resolver "^4.0.0"
|
||||||
|
|
||||||
|
"@atproto/did-resolver@^0.1.0":
|
||||||
|
version "0.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@atproto/did-resolver/-/did-resolver-0.1.0.tgz#58f42447700aaad61bad2f0d70b721966268aa02"
|
||||||
|
integrity sha512-ztljyMMCqXvJSi/Qqa2zEQFvOm1AUUR7Bybr3cM1BCddbhW46gk6/g8BgdZeDt2sMBdye37qTctR9O/FjhigvQ==
|
||||||
|
dependencies:
|
||||||
|
"@atproto/common-web" "*"
|
||||||
|
"@atproto/crypto" "*"
|
||||||
|
axios "^0.27.2"
|
||||||
|
zod "^3.14.2"
|
||||||
|
|
||||||
"@atproto/identifier@*":
|
"@atproto/identifier@*":
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@atproto/identifier/-/identifier-0.1.0.tgz#6b600c8a3da08d9a7d5eab076f8b7064457dde75"
|
resolved "https://registry.yarnpkg.com/@atproto/identifier/-/identifier-0.1.0.tgz#6b600c8a3da08d9a7d5eab076f8b7064457dde75"
|
||||||
@ -92,12 +102,13 @@
|
|||||||
"@atproto/identifier" "*"
|
"@atproto/identifier" "*"
|
||||||
"@atproto/nsid" "*"
|
"@atproto/nsid" "*"
|
||||||
|
|
||||||
"@atproto/xrpc-server@^0.1.0":
|
"@atproto/xrpc-server@^0.2.0":
|
||||||
version "0.1.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@atproto/xrpc-server/-/xrpc-server-0.1.0.tgz#2dd3172bb35fbfefb98c3d727d29be8eca5c3d9b"
|
resolved "https://registry.yarnpkg.com/@atproto/xrpc-server/-/xrpc-server-0.2.0.tgz#a36616c2ac70339cd79cda83ede0a0b305c74f9b"
|
||||||
integrity sha512-I7EjhnLUrlqQKTe2jDEnyAaOTvj26pg9NRjTXflbIOqCOkh+K9+5ztGSI0djF7TSQ7pegXroj3qRnmpVVCBr7Q==
|
integrity sha512-sCJuVUIb1tDIlKCFwHPRHbAgEy0HYGlQ7XhpNqMRKXECh8Z+DRICEne3gLDVaXhyNaC/N7OjHcsyuofDDbuGFQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@atproto/common" "*"
|
"@atproto/common" "*"
|
||||||
|
"@atproto/crypto" "*"
|
||||||
"@atproto/lexicon" "*"
|
"@atproto/lexicon" "*"
|
||||||
cbor-x "^1.5.1"
|
cbor-x "^1.5.1"
|
||||||
express "^4.17.2"
|
express "^4.17.2"
|
||||||
@ -322,6 +333,11 @@ array-flatten@1.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
|
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
|
||||||
integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==
|
integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==
|
||||||
|
|
||||||
|
asynckit@^0.4.0:
|
||||||
|
version "0.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||||
|
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
||||||
|
|
||||||
atomic-sleep@^1.0.0:
|
atomic-sleep@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b"
|
resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b"
|
||||||
@ -334,6 +350,14 @@ axios@^0.24.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects "^1.14.4"
|
follow-redirects "^1.14.4"
|
||||||
|
|
||||||
|
axios@^0.27.2:
|
||||||
|
version "0.27.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
|
||||||
|
integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
|
||||||
|
dependencies:
|
||||||
|
follow-redirects "^1.14.9"
|
||||||
|
form-data "^4.0.0"
|
||||||
|
|
||||||
base64-js@^1.3.1:
|
base64-js@^1.3.1:
|
||||||
version "1.5.1"
|
version "1.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||||
@ -446,6 +470,13 @@ chownr@^1.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
|
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
|
||||||
integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
|
integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
|
||||||
|
|
||||||
|
combined-stream@^1.0.8:
|
||||||
|
version "1.0.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||||
|
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||||
|
dependencies:
|
||||||
|
delayed-stream "~1.0.0"
|
||||||
|
|
||||||
content-disposition@0.5.4:
|
content-disposition@0.5.4:
|
||||||
version "0.5.4"
|
version "0.5.4"
|
||||||
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
|
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
|
||||||
@ -492,6 +523,11 @@ deep-extend@^0.6.0:
|
|||||||
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
||||||
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
|
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
|
||||||
|
|
||||||
|
delayed-stream@~1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||||
|
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
|
||||||
|
|
||||||
depd@2.0.0:
|
depd@2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
|
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
|
||||||
@ -624,11 +660,20 @@ finalhandler@1.2.0:
|
|||||||
statuses "2.0.1"
|
statuses "2.0.1"
|
||||||
unpipe "~1.0.0"
|
unpipe "~1.0.0"
|
||||||
|
|
||||||
follow-redirects@^1.14.4:
|
follow-redirects@^1.14.4, follow-redirects@^1.14.9:
|
||||||
version "1.15.2"
|
version "1.15.2"
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
|
||||||
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
|
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
|
||||||
|
|
||||||
|
form-data@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
|
||||||
|
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
|
||||||
|
dependencies:
|
||||||
|
asynckit "^0.4.0"
|
||||||
|
combined-stream "^1.0.8"
|
||||||
|
mime-types "^2.1.12"
|
||||||
|
|
||||||
forwarded@0.2.0:
|
forwarded@0.2.0:
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
|
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
|
||||||
@ -755,7 +800,7 @@ mime-db@1.52.0:
|
|||||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
|
||||||
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
||||||
|
|
||||||
mime-types@^2.1.35, mime-types@~2.1.24, mime-types@~2.1.34:
|
mime-types@^2.1.12, mime-types@^2.1.35, mime-types@~2.1.24, mime-types@~2.1.34:
|
||||||
version "2.1.35"
|
version "2.1.35"
|
||||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
|
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
|
||||||
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
||||||
|
Loading…
Reference in New Issue
Block a user