@atproto/pds 0.4.25 → 0.4.26
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 +6 -0
- package/dist/account-manager/db/migrations/003-privileged-app-passwords.d.ts +4 -0
- package/dist/account-manager/db/migrations/003-privileged-app-passwords.d.ts.map +1 -0
- package/dist/account-manager/db/migrations/003-privileged-app-passwords.js +15 -0
- package/dist/account-manager/db/migrations/003-privileged-app-passwords.js.map +1 -0
- package/dist/account-manager/db/migrations/index.d.ts +2 -0
- package/dist/account-manager/db/migrations/index.d.ts.map +1 -1
- package/dist/account-manager/db/migrations/index.js +2 -0
- package/dist/account-manager/db/migrations/index.js.map +1 -1
- package/dist/account-manager/db/schema/app-password.d.ts +1 -0
- package/dist/account-manager/db/schema/app-password.d.ts.map +1 -1
- package/dist/account-manager/db/schema/app-password.js.map +1 -1
- package/dist/account-manager/helpers/auth.d.ts +9 -4
- package/dist/account-manager/helpers/auth.d.ts.map +1 -1
- package/dist/account-manager/helpers/auth.js +30 -5
- package/dist/account-manager/helpers/auth.js.map +1 -1
- package/dist/account-manager/helpers/password.d.ts +7 -2
- package/dist/account-manager/helpers/password.d.ts.map +1 -1
- package/dist/account-manager/helpers/password.js +17 -4
- package/dist/account-manager/helpers/password.js.map +1 -1
- package/dist/account-manager/index.d.ts +5 -3
- package/dist/account-manager/index.d.ts.map +1 -1
- package/dist/account-manager/index.js +7 -7
- package/dist/account-manager/index.js.map +1 -1
- package/dist/api/chat/index.js +14 -14
- package/dist/api/chat/index.js.map +1 -1
- package/dist/api/com/atproto/identity/requestPlcOperationSignature.js +1 -1
- package/dist/api/com/atproto/identity/requestPlcOperationSignature.js.map +1 -1
- package/dist/api/com/atproto/identity/signPlcOperation.js +1 -1
- package/dist/api/com/atproto/identity/signPlcOperation.js.map +1 -1
- package/dist/api/com/atproto/repo/importRepo.js +1 -1
- package/dist/api/com/atproto/repo/importRepo.js.map +1 -1
- package/dist/api/com/atproto/server/activateAccount.js +1 -1
- package/dist/api/com/atproto/server/activateAccount.js.map +1 -1
- package/dist/api/com/atproto/server/createAppPassword.d.ts.map +1 -1
- package/dist/api/com/atproto/server/createAppPassword.js +2 -2
- package/dist/api/com/atproto/server/createAppPassword.js.map +1 -1
- package/dist/api/com/atproto/server/createSession.d.ts.map +1 -1
- package/dist/api/com/atproto/server/createSession.js +4 -4
- package/dist/api/com/atproto/server/createSession.js.map +1 -1
- package/dist/api/com/atproto/server/deactivateAccount.js +1 -1
- package/dist/api/com/atproto/server/deactivateAccount.js.map +1 -1
- package/dist/api/com/atproto/server/getAccountInviteCodes.js +1 -1
- package/dist/api/com/atproto/server/getAccountInviteCodes.js.map +1 -1
- package/dist/api/com/atproto/server/getServiceAuth.js +1 -1
- package/dist/api/com/atproto/server/getServiceAuth.js.map +1 -1
- package/dist/api/com/atproto/server/updateEmail.js +1 -1
- package/dist/api/com/atproto/server/updateEmail.js.map +1 -1
- package/dist/auth-verifier.d.ts +3 -1
- package/dist/auth-verifier.d.ts.map +1 -1
- package/dist/auth-verifier.js +16 -1
- package/dist/auth-verifier.js.map +1 -1
- package/dist/lexicon/lexicons.d.ts +10 -0
- package/dist/lexicon/lexicons.d.ts.map +1 -1
- package/dist/lexicon/lexicons.js +10 -0
- package/dist/lexicon/lexicons.js.map +1 -1
- package/dist/lexicon/types/com/atproto/server/createAppPassword.d.ts +3 -0
- package/dist/lexicon/types/com/atproto/server/createAppPassword.d.ts.map +1 -1
- package/dist/lexicon/types/com/atproto/server/createAppPassword.js.map +1 -1
- package/dist/lexicon/types/com/atproto/server/listAppPasswords.d.ts +1 -0
- package/dist/lexicon/types/com/atproto/server/listAppPasswords.d.ts.map +1 -1
- package/dist/lexicon/types/com/atproto/server/listAppPasswords.js.map +1 -1
- package/package.json +3 -3
- package/src/account-manager/db/migrations/003-privileged-app-passwords.ts +12 -0
- package/src/account-manager/db/migrations/index.ts +2 -0
- package/src/account-manager/db/schema/app-password.ts +1 -0
- package/src/account-manager/helpers/auth.ts +32 -4
- package/src/account-manager/helpers/password.ts +23 -5
- package/src/account-manager/index.ts +11 -9
- package/src/api/chat/index.ts +14 -14
- package/src/api/com/atproto/identity/requestPlcOperationSignature.ts +1 -1
- package/src/api/com/atproto/identity/signPlcOperation.ts +1 -1
- package/src/api/com/atproto/repo/importRepo.ts +1 -1
- package/src/api/com/atproto/server/activateAccount.ts +1 -1
- package/src/api/com/atproto/server/createAppPassword.ts +3 -1
- package/src/api/com/atproto/server/createSession.ts +5 -4
- package/src/api/com/atproto/server/deactivateAccount.ts +1 -1
- package/src/api/com/atproto/server/getAccountInviteCodes.ts +1 -1
- package/src/api/com/atproto/server/getServiceAuth.ts +1 -1
- package/src/api/com/atproto/server/updateEmail.ts +1 -1
- package/src/auth-verifier.ts +12 -1
- package/src/lexicon/lexicons.ts +11 -0
- package/src/lexicon/types/com/atproto/server/createAppPassword.ts +3 -0
- package/src/lexicon/types/com/atproto/server/listAppPasswords.ts +1 -0
- package/tests/app-passwords.test.ts +108 -7
@@ -13,6 +13,8 @@ export interface QueryParams {}
|
|
13
13
|
export interface InputSchema {
|
14
14
|
/** A short name for the App Password, to help distinguish them. */
|
15
15
|
name: string
|
16
|
+
/** If an app password has 'privileged' access to possibly sensitive account state. Meant for use with trusted clients. */
|
17
|
+
privileged?: boolean
|
16
18
|
[k: string]: unknown
|
17
19
|
}
|
18
20
|
|
@@ -51,6 +53,7 @@ export interface AppPassword {
|
|
51
53
|
name: string
|
52
54
|
password: string
|
53
55
|
createdAt: string
|
56
|
+
privileged?: boolean
|
54
57
|
[k: string]: unknown
|
55
58
|
}
|
56
59
|
|
@@ -6,6 +6,7 @@ describe('app_passwords', () => {
|
|
6
6
|
let network: TestNetworkNoAppView
|
7
7
|
let accntAgent: AtpAgent
|
8
8
|
let appAgent: AtpAgent
|
9
|
+
let priviAgent: AtpAgent
|
9
10
|
|
10
11
|
beforeAll(async () => {
|
11
12
|
network = await TestNetworkNoAppView.create({
|
@@ -13,6 +14,7 @@ describe('app_passwords', () => {
|
|
13
14
|
})
|
14
15
|
accntAgent = network.pds.getClient()
|
15
16
|
appAgent = network.pds.getClient()
|
17
|
+
priviAgent = network.pds.getClient()
|
16
18
|
|
17
19
|
await accntAgent.createAccount({
|
18
20
|
handle: 'alice.test',
|
@@ -26,26 +28,46 @@ describe('app_passwords', () => {
|
|
26
28
|
})
|
27
29
|
|
28
30
|
let appPass: string
|
31
|
+
let privilegedAppPass: string
|
29
32
|
|
30
33
|
it('creates an app-specific password', async () => {
|
31
34
|
const res = await accntAgent.api.com.atproto.server.createAppPassword({
|
32
35
|
name: 'test-pass',
|
33
36
|
})
|
34
37
|
expect(res.data.name).toBe('test-pass')
|
38
|
+
expect(res.data.privileged).toBe(false)
|
35
39
|
appPass = res.data.password
|
36
40
|
})
|
37
41
|
|
42
|
+
it('creates a privileged app-specific password', async () => {
|
43
|
+
const res = await accntAgent.api.com.atproto.server.createAppPassword({
|
44
|
+
name: 'privi-pass',
|
45
|
+
privileged: true,
|
46
|
+
})
|
47
|
+
expect(res.data.name).toBe('privi-pass')
|
48
|
+
expect(res.data.privileged).toBe(true)
|
49
|
+
privilegedAppPass = res.data.password
|
50
|
+
})
|
51
|
+
|
38
52
|
it('creates a session with an app-specific password', async () => {
|
39
|
-
const
|
53
|
+
const res1 = await appAgent.login({
|
40
54
|
identifier: 'alice.test',
|
41
55
|
password: appPass,
|
42
56
|
})
|
43
|
-
expect(
|
57
|
+
expect(res1.data.did).toEqual(accntAgent.session?.did)
|
58
|
+
const res2 = await priviAgent.login({
|
59
|
+
identifier: 'alice.test',
|
60
|
+
password: privilegedAppPass,
|
61
|
+
})
|
62
|
+
expect(res2.data.did).toEqual(accntAgent.session?.did)
|
44
63
|
})
|
45
64
|
|
46
65
|
it('creates an access token for an app with a restricted scope', () => {
|
47
66
|
const decoded = jose.decodeJwt(appAgent.session?.accessJwt ?? '')
|
48
67
|
expect(decoded?.scope).toEqual('com.atproto.appPass')
|
68
|
+
|
69
|
+
const decodedPrivi = jose.decodeJwt(priviAgent.session?.accessJwt ?? '')
|
70
|
+
expect(decodedPrivi?.scope).toEqual('com.atproto.appPassPrivileged')
|
49
71
|
})
|
50
72
|
|
51
73
|
it('allows actions to be performed from app', async () => {
|
@@ -58,15 +80,41 @@ describe('app_passwords', () => {
|
|
58
80
|
createdAt: new Date().toISOString(),
|
59
81
|
},
|
60
82
|
)
|
83
|
+
await priviAgent.api.app.bsky.feed.post.create(
|
84
|
+
{
|
85
|
+
repo: priviAgent.session?.did,
|
86
|
+
},
|
87
|
+
{
|
88
|
+
text: 'testing again',
|
89
|
+
createdAt: new Date().toISOString(),
|
90
|
+
},
|
91
|
+
)
|
61
92
|
})
|
62
93
|
|
63
|
-
it('restricts
|
64
|
-
const
|
94
|
+
it('restricts full access actions', async () => {
|
95
|
+
const attempt1 = appAgent.api.com.atproto.server.createAppPassword({
|
65
96
|
name: 'another-one',
|
66
97
|
})
|
98
|
+
await expect(attempt1).rejects.toThrow('Bad token scope')
|
99
|
+
const attempt2 = priviAgent.api.com.atproto.server.createAppPassword({
|
100
|
+
name: 'another-one',
|
101
|
+
})
|
102
|
+
await expect(attempt2).rejects.toThrow('Bad token scope')
|
103
|
+
})
|
104
|
+
|
105
|
+
it('restricts privileged app password actions', async () => {
|
106
|
+
const attempt = appAgent.api.com.atproto.server.getServiceAuth({
|
107
|
+
aud: 'did:example:test',
|
108
|
+
})
|
67
109
|
await expect(attempt).rejects.toThrow('Bad token scope')
|
68
110
|
})
|
69
111
|
|
112
|
+
it('allows privileged actions with a privileged app password', async () => {
|
113
|
+
await priviAgent.api.com.atproto.server.getServiceAuth({
|
114
|
+
aud: 'did:example:test',
|
115
|
+
})
|
116
|
+
})
|
117
|
+
|
70
118
|
it('persists scope across refreshes', async () => {
|
71
119
|
const session = await appAgent.api.com.atproto.server.refreshSession(
|
72
120
|
undefined,
|
@@ -77,6 +125,7 @@ describe('app_passwords', () => {
|
|
77
125
|
},
|
78
126
|
)
|
79
127
|
|
128
|
+
// allows any access auth
|
80
129
|
await appAgent.api.app.bsky.feed.post.create(
|
81
130
|
{
|
82
131
|
repo: appAgent.session?.did,
|
@@ -90,7 +139,56 @@ describe('app_passwords', () => {
|
|
90
139
|
},
|
91
140
|
)
|
92
141
|
|
93
|
-
|
142
|
+
// allows privileged app passwords or higher
|
143
|
+
const priviAttempt = appAgent.api.com.atproto.server.getServiceAuth({
|
144
|
+
aud: 'did:example:test',
|
145
|
+
})
|
146
|
+
await expect(priviAttempt).rejects.toThrow('Bad token scope')
|
147
|
+
|
148
|
+
// allows only full access auth
|
149
|
+
const fullAttempt = appAgent.api.com.atproto.server.createAppPassword(
|
150
|
+
{
|
151
|
+
name: 'another-one',
|
152
|
+
},
|
153
|
+
{
|
154
|
+
encoding: 'application/json',
|
155
|
+
headers: { authorization: `Bearer ${session.data.accessJwt}` },
|
156
|
+
},
|
157
|
+
)
|
158
|
+
await expect(fullAttempt).rejects.toThrow('Bad token scope')
|
159
|
+
})
|
160
|
+
|
161
|
+
it('persists privileged scope across refreshes', async () => {
|
162
|
+
const session = await priviAgent.api.com.atproto.server.refreshSession(
|
163
|
+
undefined,
|
164
|
+
{
|
165
|
+
headers: {
|
166
|
+
authorization: `Bearer ${priviAgent.session?.refreshJwt}`,
|
167
|
+
},
|
168
|
+
},
|
169
|
+
)
|
170
|
+
|
171
|
+
// allows any access auth
|
172
|
+
await priviAgent.api.app.bsky.feed.post.create(
|
173
|
+
{
|
174
|
+
repo: priviAgent.session?.did,
|
175
|
+
},
|
176
|
+
{
|
177
|
+
text: 'Testing testing',
|
178
|
+
createdAt: new Date().toISOString(),
|
179
|
+
},
|
180
|
+
{
|
181
|
+
authorization: `Bearer ${session.data.accessJwt}`,
|
182
|
+
},
|
183
|
+
)
|
184
|
+
|
185
|
+
// allows privileged app passwords or higher
|
186
|
+
await priviAgent.api.com.atproto.server.getServiceAuth({
|
187
|
+
aud: 'did:example:test',
|
188
|
+
})
|
189
|
+
|
190
|
+
// allows only full access auth
|
191
|
+
const attempt = priviAgent.api.com.atproto.server.createAppPassword(
|
94
192
|
{
|
95
193
|
name: 'another-one',
|
96
194
|
},
|
@@ -104,8 +202,11 @@ describe('app_passwords', () => {
|
|
104
202
|
|
105
203
|
it('lists available app-specific passwords', async () => {
|
106
204
|
const res = await appAgent.api.com.atproto.server.listAppPasswords()
|
107
|
-
expect(res.data.passwords.length).toBe(
|
108
|
-
expect(res.data.passwords[0].name).toEqual('
|
205
|
+
expect(res.data.passwords.length).toBe(2)
|
206
|
+
expect(res.data.passwords[0].name).toEqual('privi-pass')
|
207
|
+
expect(res.data.passwords[0].privileged).toEqual(true)
|
208
|
+
expect(res.data.passwords[1].name).toEqual('test-pass')
|
209
|
+
expect(res.data.passwords[1].privileged).toEqual(false)
|
109
210
|
})
|
110
211
|
|
111
212
|
it('revokes an app-specific password', async () => {
|