@atproto/pds 0.4.34 → 0.4.36

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/account-manager/db/migrations/004-oauth.d.ts +4 -0
  3. package/dist/account-manager/db/migrations/004-oauth.d.ts.map +1 -0
  4. package/dist/account-manager/db/migrations/004-oauth.js +106 -0
  5. package/dist/account-manager/db/migrations/004-oauth.js.map +1 -0
  6. package/dist/account-manager/db/migrations/index.d.ts +2 -0
  7. package/dist/account-manager/db/migrations/index.d.ts.map +1 -1
  8. package/dist/account-manager/db/migrations/index.js +2 -0
  9. package/dist/account-manager/db/migrations/index.js.map +1 -1
  10. package/dist/account-manager/db/schema/authorization-request.d.ts +19 -0
  11. package/dist/account-manager/db/schema/authorization-request.d.ts.map +1 -0
  12. package/dist/account-manager/db/schema/authorization-request.js +5 -0
  13. package/dist/account-manager/db/schema/authorization-request.js.map +1 -0
  14. package/dist/account-manager/db/schema/device-account.d.ts +14 -0
  15. package/dist/account-manager/db/schema/device-account.d.ts.map +1 -0
  16. package/dist/account-manager/db/schema/device-account.js +5 -0
  17. package/dist/account-manager/db/schema/device-account.js.map +1 -0
  18. package/dist/account-manager/db/schema/device.d.ts +16 -0
  19. package/dist/account-manager/db/schema/device.d.ts.map +1 -0
  20. package/dist/account-manager/db/schema/device.js +5 -0
  21. package/dist/account-manager/db/schema/device.js.map +1 -0
  22. package/dist/account-manager/db/schema/index.d.ts +11 -1
  23. package/dist/account-manager/db/schema/index.d.ts.map +1 -1
  24. package/dist/account-manager/db/schema/token.d.ts +24 -0
  25. package/dist/account-manager/db/schema/token.d.ts.map +1 -0
  26. package/dist/account-manager/db/schema/token.js +5 -0
  27. package/dist/account-manager/db/schema/token.js.map +1 -0
  28. package/dist/account-manager/db/schema/used-refresh-token.d.ts +12 -0
  29. package/dist/account-manager/db/schema/used-refresh-token.d.ts.map +1 -0
  30. package/dist/account-manager/db/schema/used-refresh-token.js +5 -0
  31. package/dist/account-manager/db/schema/used-refresh-token.js.map +1 -0
  32. package/dist/account-manager/helpers/account.d.ts +27 -5
  33. package/dist/account-manager/helpers/account.d.ts.map +1 -1
  34. package/dist/account-manager/helpers/account.js +15 -14
  35. package/dist/account-manager/helpers/account.js.map +1 -1
  36. package/dist/account-manager/helpers/authorization-request.d.ts +12 -0
  37. package/dist/account-manager/helpers/authorization-request.d.ts.map +1 -0
  38. package/dist/account-manager/helpers/authorization-request.js +59 -0
  39. package/dist/account-manager/helpers/authorization-request.js.map +1 -0
  40. package/dist/account-manager/helpers/device-account.d.ts +108 -0
  41. package/dist/account-manager/helpers/device-account.d.ts.map +1 -0
  42. package/dist/account-manager/helpers/device-account.js +82 -0
  43. package/dist/account-manager/helpers/device-account.js.map +1 -0
  44. package/dist/account-manager/helpers/device.d.ts +9 -0
  45. package/dist/account-manager/helpers/device.d.ts.map +1 -0
  46. package/dist/account-manager/helpers/device.js +32 -0
  47. package/dist/account-manager/helpers/device.js.map +1 -0
  48. package/dist/account-manager/helpers/token.d.ts +485 -0
  49. package/dist/account-manager/helpers/token.d.ts.map +1 -0
  50. package/dist/account-manager/helpers/token.js +123 -0
  51. package/dist/account-manager/helpers/token.js.map +1 -0
  52. package/dist/account-manager/helpers/used-refresh-token.d.ts +10 -0
  53. package/dist/account-manager/helpers/used-refresh-token.d.ts.map +1 -0
  54. package/dist/account-manager/helpers/used-refresh-token.js +25 -0
  55. package/dist/account-manager/helpers/used-refresh-token.js.map +1 -0
  56. package/dist/account-manager/index.d.ts +36 -6
  57. package/dist/account-manager/index.d.ts.map +1 -1
  58. package/dist/account-manager/index.js +223 -22
  59. package/dist/account-manager/index.js.map +1 -1
  60. package/dist/actor-store/preference/reader.js.map +1 -1
  61. package/dist/actor-store/record/reader.d.ts +1 -1
  62. package/dist/api/app/bsky/util/resolver.d.ts +1 -1
  63. package/dist/api/com/atproto/server/createSession.d.ts.map +1 -1
  64. package/dist/api/com/atproto/server/createSession.js +7 -31
  65. package/dist/api/com/atproto/server/createSession.js.map +1 -1
  66. package/dist/api/com/atproto/server/deleteSession.d.ts.map +1 -1
  67. package/dist/api/com/atproto/server/deleteSession.js +14 -13
  68. package/dist/api/com/atproto/server/deleteSession.js.map +1 -1
  69. package/dist/api/com/atproto/server/getSession.d.ts.map +1 -1
  70. package/dist/api/com/atproto/server/getSession.js +4 -2
  71. package/dist/api/com/atproto/server/getSession.js.map +1 -1
  72. package/dist/api/com/atproto/server/refreshSession.d.ts.map +1 -1
  73. package/dist/api/com/atproto/server/refreshSession.js +4 -2
  74. package/dist/api/com/atproto/server/refreshSession.js.map +1 -1
  75. package/dist/api/com/atproto/sync/getRepoStatus.d.ts.map +1 -1
  76. package/dist/api/com/atproto/sync/getRepoStatus.js +2 -1
  77. package/dist/api/com/atproto/sync/getRepoStatus.js.map +1 -1
  78. package/dist/api/com/atproto/sync/listRepos.js +2 -2
  79. package/dist/api/com/atproto/sync/listRepos.js.map +1 -1
  80. package/dist/api/proxy.d.ts.map +1 -1
  81. package/dist/api/proxy.js +15 -2
  82. package/dist/api/proxy.js.map +1 -1
  83. package/dist/auth-routes.d.ts +4 -0
  84. package/dist/auth-routes.d.ts.map +1 -0
  85. package/dist/auth-routes.js +24 -0
  86. package/dist/auth-routes.js.map +1 -0
  87. package/dist/auth-verifier.d.ts +32 -11
  88. package/dist/auth-verifier.d.ts.map +1 -1
  89. package/dist/auth-verifier.js +238 -79
  90. package/dist/auth-verifier.js.map +1 -1
  91. package/dist/config/config.d.ts +12 -0
  92. package/dist/config/config.d.ts.map +1 -1
  93. package/dist/config/config.js +45 -0
  94. package/dist/config/config.js.map +1 -1
  95. package/dist/config/env.d.ts +8 -0
  96. package/dist/config/env.d.ts.map +1 -1
  97. package/dist/config/env.js +10 -0
  98. package/dist/config/env.js.map +1 -1
  99. package/dist/config/secrets.d.ts +1 -0
  100. package/dist/config/secrets.d.ts.map +1 -1
  101. package/dist/config/secrets.js +1 -0
  102. package/dist/config/secrets.js.map +1 -1
  103. package/dist/context.d.ts +6 -0
  104. package/dist/context.d.ts.map +1 -1
  105. package/dist/context.js +71 -13
  106. package/dist/context.js.map +1 -1
  107. package/dist/db/cast.d.ts +15 -0
  108. package/dist/db/cast.d.ts.map +1 -0
  109. package/dist/db/cast.js +66 -0
  110. package/dist/db/cast.js.map +1 -0
  111. package/dist/db/db.d.ts +2 -2
  112. package/dist/db/db.d.ts.map +1 -1
  113. package/dist/db/db.js +9 -7
  114. package/dist/db/db.js.map +1 -1
  115. package/dist/db/index.d.ts +1 -0
  116. package/dist/db/index.d.ts.map +1 -1
  117. package/dist/db/index.js +1 -0
  118. package/dist/db/index.js.map +1 -1
  119. package/dist/error.d.ts.map +1 -1
  120. package/dist/error.js +5 -0
  121. package/dist/error.js.map +1 -1
  122. package/dist/index.d.ts.map +1 -1
  123. package/dist/index.js +2 -0
  124. package/dist/index.js.map +1 -1
  125. package/dist/logger.d.ts +13 -11
  126. package/dist/logger.d.ts.map +1 -1
  127. package/dist/logger.js +80 -64
  128. package/dist/logger.js.map +1 -1
  129. package/dist/oauth/detailed-account-store.d.ts +27 -0
  130. package/dist/oauth/detailed-account-store.d.ts.map +1 -0
  131. package/dist/oauth/detailed-account-store.js +76 -0
  132. package/dist/oauth/detailed-account-store.js.map +1 -0
  133. package/dist/oauth/provider.d.ts +16 -0
  134. package/dist/oauth/provider.d.ts.map +1 -0
  135. package/dist/oauth/provider.js +45 -0
  136. package/dist/oauth/provider.js.map +1 -0
  137. package/dist/pipethrough.d.ts.map +1 -1
  138. package/dist/pipethrough.js.map +1 -1
  139. package/dist/sequencer/events.d.ts +2 -2
  140. package/example.env +21 -3
  141. package/package.json +9 -7
  142. package/src/account-manager/db/migrations/004-oauth.ts +122 -0
  143. package/src/account-manager/db/migrations/index.ts +2 -0
  144. package/src/account-manager/db/schema/authorization-request.ts +26 -0
  145. package/src/account-manager/db/schema/device-account.ts +15 -0
  146. package/src/account-manager/db/schema/device.ts +18 -0
  147. package/src/account-manager/db/schema/index.ts +15 -0
  148. package/src/account-manager/db/schema/token.ts +34 -0
  149. package/src/account-manager/db/schema/used-refresh-token.ts +13 -0
  150. package/src/account-manager/helpers/account.ts +16 -21
  151. package/src/account-manager/helpers/authorization-request.ts +82 -0
  152. package/src/account-manager/helpers/device-account.ts +135 -0
  153. package/src/account-manager/helpers/device.ts +45 -0
  154. package/src/account-manager/helpers/token.ts +185 -0
  155. package/src/account-manager/helpers/used-refresh-token.ts +30 -0
  156. package/src/account-manager/index.ts +325 -20
  157. package/src/actor-store/preference/reader.ts +1 -1
  158. package/src/api/com/atproto/server/createSession.ts +8 -44
  159. package/src/api/com/atproto/server/deleteSession.ts +14 -20
  160. package/src/api/com/atproto/server/getSession.ts +7 -2
  161. package/src/api/com/atproto/server/refreshSession.ts +6 -2
  162. package/src/api/com/atproto/sync/getRepoStatus.ts +3 -1
  163. package/src/api/com/atproto/sync/listRepos.ts +1 -1
  164. package/src/api/proxy.ts +18 -2
  165. package/src/auth-routes.ts +27 -0
  166. package/src/auth-verifier.ts +312 -92
  167. package/src/config/config.ts +66 -0
  168. package/src/config/env.ts +24 -0
  169. package/src/config/secrets.ts +2 -0
  170. package/src/context.ts +80 -14
  171. package/src/db/cast.ts +59 -0
  172. package/src/db/db.ts +15 -12
  173. package/src/db/index.ts +1 -0
  174. package/src/error.ts +7 -0
  175. package/src/index.ts +2 -0
  176. package/src/logger.ts +83 -38
  177. package/src/oauth/detailed-account-store.ts +96 -0
  178. package/src/oauth/provider.ts +77 -0
  179. package/src/pipethrough.ts +3 -2
@@ -1,28 +1,22 @@
1
- import { AuthScope } from '../../../../auth-verifier'
2
1
  import AppContext from '../../../../context'
3
2
  import { Server } from '../../../../lexicon'
4
3
  import { authPassthru } from '../../../proxy'
5
4
 
6
5
  export default function (server: Server, ctx: AppContext) {
7
- server.com.atproto.server.deleteSession(async ({ req }) => {
8
- if (ctx.entrywayAgent) {
9
- await ctx.entrywayAgent.com.atproto.server.deleteSession(
6
+ const { entrywayAgent } = ctx
7
+ if (entrywayAgent) {
8
+ server.com.atproto.server.deleteSession(async (reqCtx) => {
9
+ await entrywayAgent.com.atproto.server.deleteSession(
10
10
  undefined,
11
- authPassthru(req, true),
11
+ authPassthru(reqCtx.req, true),
12
12
  )
13
- return
14
- }
15
-
16
- const result = await ctx.authVerifier.validateBearerToken(
17
- req,
18
- [AuthScope.Refresh],
19
- { clockTolerance: Infinity }, // ignore expiration
20
- )
21
- const id = result.payload.jti
22
- if (!id) {
23
- throw new Error('Unexpected missing refresh token id')
24
- }
25
-
26
- await ctx.accountManager.revokeRefreshToken(id)
27
- })
13
+ })
14
+ } else {
15
+ server.com.atproto.server.deleteSession({
16
+ auth: ctx.authVerifier.refreshExpired,
17
+ handler: async ({ auth }) => {
18
+ await ctx.accountManager.revokeRefreshToken(auth.credentials.tokenId)
19
+ },
20
+ })
21
+ }
28
22
  }
@@ -1,5 +1,7 @@
1
1
  import { InvalidRequestError } from '@atproto/xrpc-server'
2
2
  import { INVALID_HANDLE } from '@atproto/syntax'
3
+
4
+ import { formatAccountStatus } from '../../../../account-manager'
3
5
  import AppContext from '../../../../context'
4
6
  import { Server } from '../../../../lexicon'
5
7
  import { authPassthru, resultPassthru } from '../../../proxy'
@@ -31,6 +33,9 @@ export default function (server: Server, ctx: AppContext) {
31
33
  `Could not find user info for account: ${did}`,
32
34
  )
33
35
  }
36
+
37
+ const { status, active } = formatAccountStatus(user)
38
+
34
39
  return {
35
40
  encoding: 'application/json',
36
41
  body: {
@@ -39,8 +44,8 @@ export default function (server: Server, ctx: AppContext) {
39
44
  email: user.email ?? undefined,
40
45
  didDoc,
41
46
  emailConfirmed: !!user.emailConfirmedAt,
42
- active: user.active,
43
- status: user.status,
47
+ active,
48
+ status,
44
49
  },
45
50
  }
46
51
  },
@@ -1,5 +1,7 @@
1
1
  import { INVALID_HANDLE } from '@atproto/syntax'
2
2
  import { AuthRequiredError, InvalidRequestError } from '@atproto/xrpc-server'
3
+
4
+ import { formatAccountStatus } from '../../../../account-manager'
3
5
  import AppContext from '../../../../context'
4
6
  import { softDeleted } from '../../../../db/util'
5
7
  import { Server } from '../../../../lexicon'
@@ -44,6 +46,8 @@ export default function (server: Server, ctx: AppContext) {
44
46
  throw new InvalidRequestError('Token has been revoked', 'ExpiredToken')
45
47
  }
46
48
 
49
+ const { status, active } = formatAccountStatus(user)
50
+
47
51
  return {
48
52
  encoding: 'application/json',
49
53
  body: {
@@ -52,8 +56,8 @@ export default function (server: Server, ctx: AppContext) {
52
56
  handle: user.handle ?? INVALID_HANDLE,
53
57
  accessJwt: rotated.accessJwt,
54
58
  refreshJwt: rotated.refreshJwt,
55
- active: user.active,
56
- status: user.status,
59
+ active,
60
+ status,
57
61
  },
58
62
  }
59
63
  },
@@ -1,13 +1,15 @@
1
1
  import { Server } from '../../../../lexicon'
2
2
  import AppContext from '../../../../context'
3
3
  import { assertRepoAvailability } from './util'
4
+ import { formatAccountStatus } from '../../../../account-manager'
4
5
 
5
6
  export default function (server: Server, ctx: AppContext) {
6
7
  server.com.atproto.sync.getRepoStatus({
7
8
  handler: async ({ params }) => {
8
9
  const { did } = params
9
10
  const account = await assertRepoAvailability(ctx, did, true)
10
- const { active, status } = account
11
+
12
+ const { active, status } = formatAccountStatus(account)
11
13
 
12
14
  let rev: string | undefined = undefined
13
15
  if (active) {
@@ -2,7 +2,7 @@ import { InvalidRequestError } from '@atproto/xrpc-server'
2
2
  import { Server } from '../../../../lexicon'
3
3
  import AppContext from '../../../../context'
4
4
  import { Cursor, GenericKeyset, paginate } from '../../../../db/pagination'
5
- import { formatAccountStatus } from '../../../../account-manager/helpers/account'
5
+ import { formatAccountStatus } from '../../../../account-manager'
6
6
 
7
7
  export default function (server: Server, ctx: AppContext) {
8
8
  server.com.atproto.sync.listRepos(async ({ params }) => {
package/src/api/proxy.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Headers } from '@atproto/xrpc'
2
+ import { InvalidRequestError } from '@atproto/xrpc-server'
2
3
  import { IncomingMessage } from 'node:http'
3
4
 
4
5
  export const resultPassthru = <T>(result: { headers: Headers; data: T }) => {
@@ -24,9 +25,24 @@ export function authPassthru(
24
25
  | undefined
25
26
 
26
27
  export function authPassthru(req: IncomingMessage, withEncoding?: boolean) {
27
- if (req.headers.authorization) {
28
+ const { authorization } = req.headers
29
+
30
+ if (authorization) {
31
+ // DPoP requests are bound to the endpoint being called. Allowing them to be
32
+ // proxied would require that the receiving end allows DPoP proof not
33
+ // created for him. Since proxying is mainly there to support legacy
34
+ // clients, and DPoP is a new feature, we don't support DPoP requests
35
+ // through the proxy.
36
+
37
+ // This is fine since app views are usually called using the requester's
38
+ // credentials when "auth.credentials.type === 'access'", which is the only
39
+ // case were DPoP is used.
40
+ if (authorization.startsWith('DPoP ') || req.headers['dpop']) {
41
+ throw new InvalidRequestError('DPoP requests cannot be proxied')
42
+ }
43
+
28
44
  return {
29
- headers: { authorization: req.headers.authorization },
45
+ headers: { authorization },
30
46
  encoding: withEncoding ? 'application/json' : undefined,
31
47
  }
32
48
  }
@@ -0,0 +1,27 @@
1
+ import { oauthProtectedResourceMetadataSchema } from '@atproto/oauth-provider'
2
+ import { Router } from 'express'
3
+
4
+ import AppContext from './context'
5
+
6
+ export const createRouter = ({ authProvider, cfg }: AppContext): Router => {
7
+ const router = Router()
8
+
9
+ const oauthProtectedResourceMetadata =
10
+ oauthProtectedResourceMetadataSchema.parse({
11
+ resource: cfg.service.publicUrl,
12
+ authorization_servers: [cfg.entryway?.url ?? cfg.service.publicUrl],
13
+ bearer_methods_supported: ['header'],
14
+ scopes_supported: ['profile', 'email', 'phone'],
15
+ resource_documentation: 'https://atproto.com',
16
+ })
17
+
18
+ router.get('/.well-known/oauth-protected-resource', (req, res) => {
19
+ res.status(200).json(oauthProtectedResourceMetadata)
20
+ })
21
+
22
+ if (authProvider) {
23
+ router.use(authProvider.createRouter())
24
+ }
25
+
26
+ return router
27
+ }