@atproto/pds 0.5.5 → 0.5.7
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 +31 -0
- package/dist/account-manager/account-manager.d.ts +51 -13
- package/dist/account-manager/account-manager.d.ts.map +1 -1
- package/dist/account-manager/account-manager.js +86 -26
- package/dist/account-manager/account-manager.js.map +1 -1
- package/dist/account-manager/db/migrations/005-oauth-account-management.d.ts.map +1 -1
- package/dist/account-manager/db/migrations/005-oauth-account-management.js +3 -4
- package/dist/account-manager/db/migrations/005-oauth-account-management.js.map +1 -1
- package/dist/account-manager/db/schema/authorization-request.d.ts +2 -2
- package/dist/account-manager/db/schema/authorization-request.d.ts.map +1 -1
- package/dist/account-manager/db/schema/authorization-request.js.map +1 -1
- package/dist/account-manager/db/schema/authorized-client.d.ts +2 -2
- package/dist/account-manager/db/schema/authorized-client.d.ts.map +1 -1
- package/dist/account-manager/db/schema/authorized-client.js.map +1 -1
- package/dist/account-manager/db/schema/token.d.ts +2 -2
- package/dist/account-manager/db/schema/token.d.ts.map +1 -1
- package/dist/account-manager/db/schema/token.js.map +1 -1
- package/dist/account-manager/helpers/account-device.d.ts +23 -196
- package/dist/account-manager/helpers/account-device.d.ts.map +1 -1
- package/dist/account-manager/helpers/account-device.js +3 -3
- package/dist/account-manager/helpers/account-device.js.map +1 -1
- package/dist/account-manager/helpers/account.d.ts +14 -4
- package/dist/account-manager/helpers/account.d.ts.map +1 -1
- package/dist/account-manager/helpers/account.js +17 -11
- package/dist/account-manager/helpers/account.js.map +1 -1
- package/dist/account-manager/helpers/auth.js +1 -1
- package/dist/account-manager/helpers/auth.js.map +1 -1
- package/dist/account-manager/helpers/authorization-request.d.ts +83 -5
- package/dist/account-manager/helpers/authorization-request.d.ts.map +1 -1
- package/dist/account-manager/helpers/authorization-request.js +8 -8
- package/dist/account-manager/helpers/authorization-request.js.map +1 -1
- package/dist/account-manager/helpers/authorized-client.d.ts +5 -4
- package/dist/account-manager/helpers/authorized-client.d.ts.map +1 -1
- package/dist/account-manager/helpers/authorized-client.js +3 -0
- package/dist/account-manager/helpers/authorized-client.js.map +1 -1
- package/dist/account-manager/helpers/device.d.ts +9 -3
- package/dist/account-manager/helpers/device.d.ts.map +1 -1
- package/dist/account-manager/helpers/device.js +4 -4
- package/dist/account-manager/helpers/device.js.map +1 -1
- package/dist/account-manager/helpers/invite.d.ts +35 -2
- package/dist/account-manager/helpers/invite.d.ts.map +1 -1
- package/dist/account-manager/helpers/lexicon.d.ts.map +1 -1
- package/dist/account-manager/helpers/lexicon.js +6 -0
- package/dist/account-manager/helpers/lexicon.js.map +1 -1
- package/dist/account-manager/helpers/password.d.ts +1 -0
- package/dist/account-manager/helpers/password.d.ts.map +1 -1
- package/dist/account-manager/helpers/password.js +3 -0
- package/dist/account-manager/helpers/password.js.map +1 -1
- package/dist/account-manager/helpers/token.d.ts +72 -1031
- package/dist/account-manager/helpers/token.d.ts.map +1 -1
- package/dist/account-manager/helpers/token.js +13 -10
- package/dist/account-manager/helpers/token.js.map +1 -1
- package/dist/account-manager/helpers/used-refresh-token.d.ts +6 -2
- package/dist/account-manager/helpers/used-refresh-token.d.ts.map +1 -1
- package/dist/account-manager/oauth-store.d.ts +17 -13
- package/dist/account-manager/oauth-store.d.ts.map +1 -1
- package/dist/account-manager/oauth-store.js +89 -39
- package/dist/account-manager/oauth-store.js.map +1 -1
- package/dist/actor-store/blob/reader.d.ts.map +1 -1
- package/dist/actor-store/blob/reader.js +2 -3
- package/dist/actor-store/blob/reader.js.map +1 -1
- package/dist/actor-store/record/reader.js +3 -3
- package/dist/actor-store/record/reader.js.map +1 -1
- package/dist/actor-store/repo/sql-repo-reader.d.ts +5 -1
- package/dist/actor-store/repo/sql-repo-reader.d.ts.map +1 -1
- package/dist/actor-store/repo/sql-repo-reader.js.map +1 -1
- package/dist/api/com/atproto/admin/updateSubjectStatus.d.ts.map +1 -1
- package/dist/api/com/atproto/admin/updateSubjectStatus.js +12 -4
- package/dist/api/com/atproto/admin/updateSubjectStatus.js.map +1 -1
- package/dist/api/com/atproto/server/activateAccount.d.ts.map +1 -1
- package/dist/api/com/atproto/server/activateAccount.js +25 -31
- package/dist/api/com/atproto/server/activateAccount.js.map +1 -1
- package/dist/api/com/atproto/server/deactivateAccount.d.ts.map +1 -1
- package/dist/api/com/atproto/server/deactivateAccount.js +3 -4
- package/dist/api/com/atproto/server/deactivateAccount.js.map +1 -1
- package/dist/api/com/atproto/server/deleteAccount.d.ts.map +1 -1
- package/dist/api/com/atproto/server/deleteAccount.js +51 -37
- package/dist/api/com/atproto/server/deleteAccount.js.map +1 -1
- package/dist/api/com/atproto/server/util.d.ts +25 -6
- package/dist/api/com/atproto/server/util.d.ts.map +1 -1
- package/dist/api/com/atproto/server/util.js.map +1 -1
- package/dist/background.d.ts +12 -6
- package/dist/background.d.ts.map +1 -1
- package/dist/background.js +32 -13
- package/dist/background.js.map +1 -1
- package/dist/config/config.d.ts +2 -1
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +4 -1
- package/dist/config/config.js.map +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +5 -32
- package/dist/context.js.map +1 -1
- package/dist/db/migrator.d.ts +4 -3
- package/dist/db/migrator.d.ts.map +1 -1
- package/dist/db/migrator.js +1 -1
- package/dist/db/migrator.js.map +1 -1
- package/dist/db/pagination.d.ts +2 -1
- package/dist/db/pagination.d.ts.map +1 -1
- package/dist/db/pagination.js +2 -2
- package/dist/db/pagination.js.map +1 -1
- package/dist/db/util.d.ts +3 -3
- package/dist/db/util.d.ts.map +1 -1
- package/dist/db/util.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -11
- package/dist/index.js.map +1 -1
- package/dist/lexicons/app/bsky/notification/defs.defs.d.ts +5 -0
- package/dist/lexicons/app/bsky/notification/defs.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/notification/defs.defs.js +1 -0
- package/dist/lexicons/app/bsky/notification/defs.defs.js.map +1 -1
- package/dist/lexicons/chat/bsky/notification/defs.d.ts +2 -0
- package/dist/lexicons/chat/bsky/notification/defs.d.ts.map +1 -0
- package/dist/lexicons/chat/bsky/notification/defs.defs.d.ts +20 -0
- package/dist/lexicons/chat/bsky/notification/defs.defs.d.ts.map +1 -0
- package/dist/lexicons/chat/bsky/notification/defs.defs.js +19 -0
- package/dist/lexicons/chat/bsky/notification/defs.defs.js.map +1 -0
- package/dist/lexicons/chat/bsky/notification/defs.js +5 -0
- package/dist/lexicons/chat/bsky/notification/defs.js.map +1 -0
- package/dist/lexicons/chat/bsky/notification/getPreferences.d.ts +3 -0
- package/dist/lexicons/chat/bsky/notification/getPreferences.d.ts.map +1 -0
- package/dist/lexicons/chat/bsky/notification/getPreferences.defs.d.ts +18 -0
- package/dist/lexicons/chat/bsky/notification/getPreferences.defs.d.ts.map +1 -0
- package/dist/lexicons/chat/bsky/notification/getPreferences.defs.js +16 -0
- package/dist/lexicons/chat/bsky/notification/getPreferences.defs.js.map +1 -0
- package/dist/lexicons/chat/bsky/notification/getPreferences.js +6 -0
- package/dist/lexicons/chat/bsky/notification/getPreferences.js.map +1 -0
- package/dist/lexicons/chat/bsky/notification/putPreferences.d.ts +3 -0
- package/dist/lexicons/chat/bsky/notification/putPreferences.d.ts.map +1 -0
- package/dist/lexicons/chat/bsky/notification/putPreferences.defs.d.ts +27 -0
- package/dist/lexicons/chat/bsky/notification/putPreferences.defs.d.ts.map +1 -0
- package/dist/lexicons/chat/bsky/notification/putPreferences.defs.js +22 -0
- package/dist/lexicons/chat/bsky/notification/putPreferences.defs.js.map +1 -0
- package/dist/lexicons/chat/bsky/notification/putPreferences.js +6 -0
- package/dist/lexicons/chat/bsky/notification/putPreferences.js.map +1 -0
- package/dist/lexicons/chat/bsky/notification.d.ts +4 -0
- package/dist/lexicons/chat/bsky/notification.d.ts.map +1 -0
- package/dist/lexicons/chat/bsky/notification.js +7 -0
- package/dist/lexicons/chat/bsky/notification.js.map +1 -0
- package/dist/lexicons/chat/bsky.d.ts +1 -0
- package/dist/lexicons/chat/bsky.d.ts.map +1 -1
- package/dist/lexicons/chat/bsky.js +1 -0
- package/dist/lexicons/chat/bsky.js.map +1 -1
- package/dist/lexicons/tools/ozone/report/defs.defs.d.ts +4 -0
- package/dist/lexicons/tools/ozone/report/defs.defs.d.ts.map +1 -1
- package/dist/lexicons/tools/ozone/report/defs.defs.js +2 -0
- package/dist/lexicons/tools/ozone/report/defs.defs.js.map +1 -1
- package/dist/lexicons/tools/ozone/report/queryActivities.d.ts +3 -0
- package/dist/lexicons/tools/ozone/report/queryActivities.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/report/queryActivities.defs.d.ts +42 -0
- package/dist/lexicons/tools/ozone/report/queryActivities.defs.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/report/queryActivities.defs.js +31 -0
- package/dist/lexicons/tools/ozone/report/queryActivities.defs.js.map +1 -0
- package/dist/lexicons/tools/ozone/report/queryActivities.js +6 -0
- package/dist/lexicons/tools/ozone/report/queryActivities.js.map +1 -0
- package/dist/lexicons/tools/ozone/report.d.ts +1 -0
- package/dist/lexicons/tools/ozone/report.d.ts.map +1 -1
- package/dist/lexicons/tools/ozone/report.js +1 -0
- package/dist/lexicons/tools/ozone/report.js.map +1 -1
- package/dist/mailer/index.d.ts +2 -0
- package/dist/mailer/index.d.ts.map +1 -1
- package/dist/mailer/index.js +2 -0
- package/dist/mailer/index.js.map +1 -1
- package/dist/pipethrough.d.ts +3 -0
- package/dist/pipethrough.d.ts.map +1 -1
- package/dist/pipethrough.js +32 -0
- package/dist/pipethrough.js.map +1 -1
- package/dist/scripts/sequencer-recovery/recovery-db.js.map +1 -1
- package/dist/sequencer/events.d.ts.map +1 -1
- package/dist/sequencer/events.js +6 -13
- package/dist/sequencer/events.js.map +1 -1
- package/dist/sequencer/sequencer.d.ts +1 -1
- package/dist/sequencer/sequencer.d.ts.map +1 -1
- package/dist/sequencer/sequencer.js.map +1 -1
- package/package.json +14 -14
- package/src/account-manager/account-manager.ts +135 -36
- package/src/account-manager/db/migrations/005-oauth-account-management.ts +6 -5
- package/src/account-manager/db/schema/authorization-request.ts +2 -1
- package/src/account-manager/db/schema/authorized-client.ts +6 -2
- package/src/account-manager/db/schema/token.ts +2 -2
- package/src/account-manager/helpers/account-device.ts +5 -11
- package/src/account-manager/helpers/account.ts +39 -16
- package/src/account-manager/helpers/auth.ts +2 -2
- package/src/account-manager/helpers/authorization-request.ts +12 -8
- package/src/account-manager/helpers/authorized-client.ts +12 -6
- package/src/account-manager/helpers/device.ts +4 -4
- package/src/account-manager/helpers/lexicon.ts +8 -3
- package/src/account-manager/helpers/password.ts +6 -0
- package/src/account-manager/helpers/token.ts +17 -11
- package/src/account-manager/oauth-store.ts +129 -61
- package/src/actor-store/blob/reader.ts +8 -5
- package/src/actor-store/record/reader.ts +3 -3
- package/src/actor-store/repo/sql-repo-reader.ts +1 -1
- package/src/api/com/atproto/admin/updateSubjectStatus.ts +16 -4
- package/src/api/com/atproto/server/activateAccount.ts +27 -49
- package/src/api/com/atproto/server/deactivateAccount.ts +3 -7
- package/src/api/com/atproto/server/deleteAccount.ts +60 -43
- package/src/api/com/atproto/server/util.ts +24 -7
- package/src/background.ts +49 -18
- package/src/config/config.ts +7 -2
- package/src/context.ts +6 -40
- package/src/db/migrator.ts +2 -1
- package/src/db/pagination.ts +7 -7
- package/src/db/util.ts +5 -2
- package/src/index.ts +31 -13
- package/src/mailer/index.ts +4 -2
- package/src/pipethrough.ts +38 -1
- package/src/scripts/sequencer-recovery/recovery-db.ts +1 -1
- package/src/sequencer/events.ts +8 -13
- package/src/sequencer/sequencer.ts +1 -3
- package/tests/_util.ts +8 -25
- package/tests/account-deactivation.test.ts +1 -1
- package/tests/account-deletion.test.ts +1 -1
- package/tests/account-manager.test.ts +79 -0
- package/tests/account-migration.test.ts +2 -2
- package/tests/account-status.test.ts +206 -0
- package/tests/account.test.ts +1 -1
- package/tests/app-passwords.test.ts +1 -1
- package/tests/auth.test.ts +1 -1
- package/tests/blob-deletes.test.ts +1 -1
- package/tests/create-post.test.ts +1 -1
- package/tests/crud.test.ts +1 -1
- package/tests/db.test.ts +4 -4
- package/tests/email-confirmation.test.ts +1 -1
- package/tests/file-uploads.test.ts +2 -2
- package/tests/get-service-auth.test.ts +1 -1
- package/tests/handles.test.ts +1 -1
- package/tests/invite-codes.test.ts +1 -1
- package/tests/invites-admin.test.ts +1 -1
- package/tests/moderation.test.ts +1 -1
- package/tests/moderator-auth.test.ts +1 -1
- package/tests/oauth.test.ts +91 -0
- package/tests/plc-operations.test.ts +1 -1
- package/tests/preferences.test.ts +1 -1
- package/tests/proxied/admin.test.ts +1 -1
- package/tests/proxied/feedgen.test.ts +1 -1
- package/tests/proxied/notif.test.ts +6 -13
- package/tests/proxied/procedures.test.ts +1 -1
- package/tests/proxied/proxy-catchall.test.ts +9 -8
- package/tests/proxied/proxy-header.test.ts +12 -8
- package/tests/proxied/proxy-oauth-aud.test.ts +17 -10
- package/tests/proxied/read-after-write.test.ts +4 -5
- package/tests/proxied/views.test.ts +1 -1
- package/tests/races.test.ts +1 -1
- package/tests/rate-limits.test.ts +1 -1
- package/tests/recovery.test.ts +1 -1
- package/tests/seeds/basic.ts +2 -2
- package/tests/seeds/users.ts +4 -1
- package/tests/sequencer.test.ts +1 -1
- package/tests/server.test.ts +9 -12
- package/tests/sync/invertible-ops.test.ts +1 -1
- package/tests/sync/list.test.ts +1 -1
- package/tests/sync/subscribe-repos.test.ts +1 -1
- package/tests/sync/sync.test.ts +1 -1
- package/tests/takedown-appeal.test.ts +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -162,9 +162,7 @@ export class Sequencer extends (EventEmitter as new () => SequencerEmitter) {
|
|
|
162
162
|
await wait(waitTime)
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
|
|
166
|
-
events: readonly RepoSeqInsert[],
|
|
167
|
-
): Promise<number[]> {
|
|
165
|
+
async sequenceEvts(events: readonly RepoSeqInsert[]): Promise<number[]> {
|
|
168
166
|
if (!events.length) return []
|
|
169
167
|
const rows = await this.db.executeWithRetry(
|
|
170
168
|
this.db.db.insertInto('repo_seq').values(events).returning('seq'),
|
package/tests/_util.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RequestListener, createServer } from 'node:http'
|
|
2
2
|
import { AddressInfo } from 'node:net'
|
|
3
|
-
|
|
3
|
+
// eslint-disable-next-line import/default
|
|
4
|
+
import httpTerminator from 'http-terminator'
|
|
4
5
|
import { ToolsOzoneModerationDefs, lexToJson } from '@atproto/api'
|
|
5
6
|
import { isCidString } from '@atproto/lex'
|
|
6
7
|
import { isCid, isPlainObject } from '@atproto/lex-data'
|
|
@@ -146,19 +147,11 @@ export const paginateAll = async <T extends { cursor?: string }>(
|
|
|
146
147
|
return results
|
|
147
148
|
}
|
|
148
149
|
|
|
149
|
-
export async function startServer(
|
|
150
|
-
return new Promise<{
|
|
151
|
-
origin: string
|
|
152
|
-
server: Server
|
|
153
|
-
stop: () => Promise<void>
|
|
154
|
-
}>((resolve, reject) => {
|
|
150
|
+
export async function startServer(listener: RequestListener) {
|
|
151
|
+
return new Promise<AsyncDisposable & { port: number }>((resolve, reject) => {
|
|
155
152
|
const onListen = () => {
|
|
156
153
|
const port = (server.address() as AddressInfo).port
|
|
157
|
-
resolve({
|
|
158
|
-
server,
|
|
159
|
-
origin: `http://localhost:${port}`,
|
|
160
|
-
stop: () => stopServer(server),
|
|
161
|
-
})
|
|
154
|
+
resolve({ port, [Symbol.asyncDispose]: () => terminator.terminate() })
|
|
162
155
|
cleanup()
|
|
163
156
|
}
|
|
164
157
|
const onError = (err: Error) => {
|
|
@@ -170,22 +163,12 @@ export async function startServer(app: Express) {
|
|
|
170
163
|
server.removeListener('error', onError)
|
|
171
164
|
}
|
|
172
165
|
|
|
173
|
-
const server =
|
|
166
|
+
const server = createServer(listener)
|
|
174
167
|
.listen(0)
|
|
175
168
|
.once('listening', onListen)
|
|
176
169
|
.once('error', onError)
|
|
177
|
-
})
|
|
178
|
-
}
|
|
179
170
|
|
|
180
|
-
|
|
181
|
-
return new Promise<void>((resolve, reject) => {
|
|
182
|
-
server.close((err) => {
|
|
183
|
-
if (err) {
|
|
184
|
-
reject(err)
|
|
185
|
-
} else {
|
|
186
|
-
resolve()
|
|
187
|
-
}
|
|
188
|
-
})
|
|
171
|
+
const terminator = httpTerminator.createHttpTerminator({ server })
|
|
189
172
|
})
|
|
190
173
|
}
|
|
191
174
|
|
|
@@ -134,6 +134,7 @@ describe('account manager', () => {
|
|
|
134
134
|
const [params] = sendResetPasswordMock.mock.lastCall!
|
|
135
135
|
expect(params).toEqual({
|
|
136
136
|
handle: 'bob.test',
|
|
137
|
+
locale: 'fr',
|
|
137
138
|
token: expect.any(String),
|
|
138
139
|
})
|
|
139
140
|
|
|
@@ -380,4 +381,82 @@ describe('account manager', () => {
|
|
|
380
381
|
await page.clickOnText('Retour')
|
|
381
382
|
await page.ensureTextVisibility('bob-renamed.test', 'span')
|
|
382
383
|
})
|
|
384
|
+
|
|
385
|
+
it('allows deactivating & reactivating the account', async () => {
|
|
386
|
+
await using page = await PageHelper.from(browser, { languages })
|
|
387
|
+
|
|
388
|
+
await page.goto(new URL('/account', network.pds.url))
|
|
389
|
+
|
|
390
|
+
await page.assertTitle('Mon compte Atmosphère')
|
|
391
|
+
|
|
392
|
+
await page.clickOnText('Compte utilisateur', 'a')
|
|
393
|
+
|
|
394
|
+
await page.clickOnText('Désactiver le compte')
|
|
395
|
+
|
|
396
|
+
await page.ensureTextVisibility(
|
|
397
|
+
'limite de temps pour la désactivation du compte',
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
await page.clickOnText('Oui, désactiver')
|
|
401
|
+
|
|
402
|
+
await page.waitForNetworkIdle()
|
|
403
|
+
|
|
404
|
+
// The row should now offer re-activation
|
|
405
|
+
await page.ensureTextVisibility('Réactiver le compte', 'span')
|
|
406
|
+
|
|
407
|
+
await page.clickOnText('Réactiver le compte')
|
|
408
|
+
|
|
409
|
+
// @NOTE The dialog's submit label ("Réactiver") is a substring of the
|
|
410
|
+
// trigger row ("Réactiver le compte"), which comes first in DOM order, so
|
|
411
|
+
// we target the dialog's submit button instead of using its text.
|
|
412
|
+
await page.clickOn('[role="dialog"] button[type="submit"]')
|
|
413
|
+
|
|
414
|
+
await page.waitForNetworkIdle()
|
|
415
|
+
|
|
416
|
+
await page.ensureTextVisibility('Désactiver le compte', 'span')
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
it('allows deleting the account', async () => {
|
|
420
|
+
await using page = await PageHelper.from(browser, { languages })
|
|
421
|
+
|
|
422
|
+
await page.goto(new URL('/account', network.pds.url))
|
|
423
|
+
|
|
424
|
+
await page.assertTitle('Mon compte Atmosphère')
|
|
425
|
+
|
|
426
|
+
await page.clickOnText('Compte utilisateur', 'a')
|
|
427
|
+
|
|
428
|
+
await page.clickOnText('Supprimer le compte')
|
|
429
|
+
|
|
430
|
+
using sendAccountDeleteMock = jest
|
|
431
|
+
.spyOn(network.pds.ctx.mailer, 'sendAccountDelete')
|
|
432
|
+
.mockImplementation(async () => {
|
|
433
|
+
// noop
|
|
434
|
+
})
|
|
435
|
+
|
|
436
|
+
await page.clickOnText("Envoyer l'email")
|
|
437
|
+
|
|
438
|
+
await page.waitForNetworkIdle()
|
|
439
|
+
|
|
440
|
+
expect(sendAccountDeleteMock).toHaveBeenCalledTimes(1)
|
|
441
|
+
|
|
442
|
+
const [params] = sendAccountDeleteMock.mock.lastCall!
|
|
443
|
+
expect(params).toEqual({
|
|
444
|
+
locale: 'fr',
|
|
445
|
+
token: expect.any(String),
|
|
446
|
+
})
|
|
447
|
+
|
|
448
|
+
await page.typeInInput('code', params.token)
|
|
449
|
+
await page.typeInInput('password', 'bob-new-pass')
|
|
450
|
+
|
|
451
|
+
await page.clickOnText('Supprimer mon compte')
|
|
452
|
+
|
|
453
|
+
// A final confirmation step is displayed
|
|
454
|
+
await page.ensureTextVisibility('Êtes-vous vraiment, vraiment sûr ?', 'h2')
|
|
455
|
+
|
|
456
|
+
await page.clickOnText('Oui, supprimer mon compte')
|
|
457
|
+
|
|
458
|
+
// Once the account is deleted, the session is gone and the user is
|
|
459
|
+
// brought back to the sign-in page.
|
|
460
|
+
await page.assertTitle('Se connecter')
|
|
461
|
+
})
|
|
383
462
|
})
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { jest } from '@jest/globals'
|
|
2
|
+
import { TestNetworkNoAppView } from '@atproto/dev-env'
|
|
3
|
+
import { Client } from '@atproto/lex'
|
|
4
|
+
import { com } from '../src/lexicons/index.js'
|
|
5
|
+
|
|
6
|
+
describe('account-status', () => {
|
|
7
|
+
let network: TestNetworkNoAppView
|
|
8
|
+
let client: Client
|
|
9
|
+
|
|
10
|
+
beforeAll(async () => {
|
|
11
|
+
network = await TestNetworkNoAppView.create({
|
|
12
|
+
dbPostgresSchema: 'account_status',
|
|
13
|
+
})
|
|
14
|
+
client = network.pds.getClient()
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
afterEach(async () => {
|
|
18
|
+
await network.processAll()
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
afterAll(async () => {
|
|
22
|
+
await network?.close()
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('takedown + activation triggers an error', async () => {
|
|
26
|
+
const { did } = await client.call(com.atproto.server.createAccount, {
|
|
27
|
+
handle: 'iris.test',
|
|
28
|
+
email: 'iris@test.com',
|
|
29
|
+
password: 'password',
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
await expect(
|
|
33
|
+
client.call(
|
|
34
|
+
com.atproto.admin.updateSubjectStatus,
|
|
35
|
+
{
|
|
36
|
+
subject: com.atproto.admin.defs.repoRef.$build({ did }),
|
|
37
|
+
takedown: { applied: true },
|
|
38
|
+
deactivated: { applied: false },
|
|
39
|
+
},
|
|
40
|
+
{ headers: { authorization: network.pds.adminAuth() } },
|
|
41
|
+
),
|
|
42
|
+
).rejects.toMatchObject({
|
|
43
|
+
error: 'InvalidRequest',
|
|
44
|
+
message: 'Cannot activate and takedown an account at the same time',
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('activating a taken down account causes an error', async () => {
|
|
49
|
+
const { did } = await client.call(com.atproto.server.createAccount, {
|
|
50
|
+
handle: 'iris2.test',
|
|
51
|
+
email: 'iris2@test.com',
|
|
52
|
+
password: 'password',
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const mock = jest.spyOn(network.pds.ctx.sequencer, 'sequenceEvts')
|
|
56
|
+
|
|
57
|
+
// First deactivate
|
|
58
|
+
await client.call(
|
|
59
|
+
com.atproto.admin.updateSubjectStatus,
|
|
60
|
+
{
|
|
61
|
+
subject: com.atproto.admin.defs.repoRef.$build({ did }),
|
|
62
|
+
deactivated: { applied: true },
|
|
63
|
+
},
|
|
64
|
+
{ headers: { authorization: network.pds.adminAuth() } },
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
expect(mock).toHaveBeenCalledTimes(1)
|
|
68
|
+
|
|
69
|
+
// Then takedown
|
|
70
|
+
await client.call(
|
|
71
|
+
com.atproto.admin.updateSubjectStatus,
|
|
72
|
+
{
|
|
73
|
+
subject: com.atproto.admin.defs.repoRef.$build({ did }),
|
|
74
|
+
takedown: { applied: true },
|
|
75
|
+
},
|
|
76
|
+
{ headers: { authorization: network.pds.adminAuth() } },
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
expect(mock).toHaveBeenCalledTimes(2)
|
|
80
|
+
|
|
81
|
+
// Then remove the takedown
|
|
82
|
+
await client.call(
|
|
83
|
+
com.atproto.admin.updateSubjectStatus,
|
|
84
|
+
{
|
|
85
|
+
subject: com.atproto.admin.defs.repoRef.$build({ did }),
|
|
86
|
+
takedown: { applied: false },
|
|
87
|
+
},
|
|
88
|
+
{ headers: { authorization: network.pds.adminAuth() } },
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
expect(mock).toHaveBeenCalledTimes(3)
|
|
92
|
+
|
|
93
|
+
// Then try to activate again (should work now)
|
|
94
|
+
await client.call(
|
|
95
|
+
com.atproto.admin.updateSubjectStatus,
|
|
96
|
+
{
|
|
97
|
+
subject: com.atproto.admin.defs.repoRef.$build({ did }),
|
|
98
|
+
deactivated: { applied: false },
|
|
99
|
+
},
|
|
100
|
+
{ headers: { authorization: network.pds.adminAuth() } },
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
expect(mock).toHaveBeenCalledTimes(4)
|
|
104
|
+
|
|
105
|
+
// Attempt login to ensure account is active
|
|
106
|
+
await client.call(com.atproto.server.createSession, {
|
|
107
|
+
identifier: 'iris2.test',
|
|
108
|
+
password: 'password',
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
// @TODO use "using" (requires updating jest)
|
|
112
|
+
mock.mockRestore()
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('sequences an account status event when calling updateSubjectStatus without changing the status', async () => {
|
|
116
|
+
const { did } = await client.call(com.atproto.server.createAccount, {
|
|
117
|
+
handle: 'iris3.test',
|
|
118
|
+
email: 'iris3@test.com',
|
|
119
|
+
password: 'password',
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
const mock = jest.spyOn(network.pds.ctx.sequencer, 'sequenceEvts')
|
|
123
|
+
|
|
124
|
+
// Update the account status without changing the status (should still sequence an event)
|
|
125
|
+
await client.call(
|
|
126
|
+
com.atproto.admin.updateSubjectStatus,
|
|
127
|
+
{
|
|
128
|
+
subject: com.atproto.admin.defs.repoRef.$build({ did }),
|
|
129
|
+
},
|
|
130
|
+
{ headers: { authorization: network.pds.adminAuth() } },
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
expect(mock).toHaveBeenCalledTimes(1)
|
|
134
|
+
|
|
135
|
+
// @TODO use "using" (requires updating jest)
|
|
136
|
+
mock.mockRestore()
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
it('allows to takedown, then deactivate, an account', async () => {
|
|
140
|
+
const { did } = await client.call(com.atproto.server.createAccount, {
|
|
141
|
+
handle: 'iris4.test',
|
|
142
|
+
email: 'iris4@test.com',
|
|
143
|
+
password: 'password',
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
await client.call(
|
|
147
|
+
com.atproto.admin.updateSubjectStatus,
|
|
148
|
+
{
|
|
149
|
+
subject: com.atproto.admin.defs.repoRef.$build({ did }),
|
|
150
|
+
takedown: { applied: true },
|
|
151
|
+
},
|
|
152
|
+
{ headers: { authorization: network.pds.adminAuth() } },
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
await client.call(
|
|
156
|
+
com.atproto.admin.updateSubjectStatus,
|
|
157
|
+
{
|
|
158
|
+
subject: com.atproto.admin.defs.repoRef.$build({ did }),
|
|
159
|
+
deactivated: { applied: true },
|
|
160
|
+
},
|
|
161
|
+
{ headers: { authorization: network.pds.adminAuth() } },
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
const status = await client.call(
|
|
165
|
+
com.atproto.admin.getSubjectStatus,
|
|
166
|
+
{ did },
|
|
167
|
+
{ headers: { authorization: network.pds.adminAuth() } },
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
expect(status).toEqual({
|
|
171
|
+
subject: com.atproto.admin.defs.repoRef.$build({ did }),
|
|
172
|
+
takedown: { applied: true, ref: expect.any(String) },
|
|
173
|
+
deactivated: { applied: true },
|
|
174
|
+
})
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
it('throws when trying to activate a takedown account', async () => {
|
|
178
|
+
const { did } = await client.call(com.atproto.server.createAccount, {
|
|
179
|
+
handle: 'iris5.test',
|
|
180
|
+
email: 'iris5@test.com',
|
|
181
|
+
password: 'password',
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
await client.call(
|
|
185
|
+
com.atproto.admin.updateSubjectStatus,
|
|
186
|
+
{
|
|
187
|
+
subject: com.atproto.admin.defs.repoRef.$build({ did }),
|
|
188
|
+
takedown: { applied: true },
|
|
189
|
+
},
|
|
190
|
+
{ headers: { authorization: network.pds.adminAuth() } },
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
await expect(
|
|
194
|
+
client.call(
|
|
195
|
+
com.atproto.admin.updateSubjectStatus,
|
|
196
|
+
{
|
|
197
|
+
subject: com.atproto.admin.defs.repoRef.$build({ did }),
|
|
198
|
+
deactivated: { applied: false },
|
|
199
|
+
},
|
|
200
|
+
{ headers: { authorization: network.pds.adminAuth() } },
|
|
201
|
+
),
|
|
202
|
+
).rejects.toMatchObject({
|
|
203
|
+
error: 'AccountNotFound',
|
|
204
|
+
})
|
|
205
|
+
})
|
|
206
|
+
})
|
package/tests/account.test.ts
CHANGED
package/tests/auth.test.ts
CHANGED
package/tests/crud.test.ts
CHANGED
package/tests/db.test.ts
CHANGED
|
@@ -14,15 +14,15 @@ describe('db', () => {
|
|
|
14
14
|
})
|
|
15
15
|
|
|
16
16
|
afterAll(async () => {
|
|
17
|
-
await network
|
|
17
|
+
await network?.close()
|
|
18
18
|
})
|
|
19
19
|
|
|
20
20
|
it('commits changes', async () => {
|
|
21
21
|
const result = await db.transaction(async (dbTxn) => {
|
|
22
22
|
return await dbTxn.db
|
|
23
23
|
.insertInto('repo_root')
|
|
24
|
+
// @ts-expect-error invalid date is intentional for testing purposes
|
|
24
25
|
.values({
|
|
25
|
-
// @ts-expect-error invalid date is intentional for testing purposes
|
|
26
26
|
did: 'x',
|
|
27
27
|
cid: 'x',
|
|
28
28
|
rev: 'x',
|
|
@@ -56,8 +56,8 @@ describe('db', () => {
|
|
|
56
56
|
const promise = db.transaction(async (dbTxn) => {
|
|
57
57
|
await dbTxn.db
|
|
58
58
|
.insertInto('repo_root')
|
|
59
|
+
// @ts-expect-error invalid date is intentional for testing purposes
|
|
59
60
|
.values({
|
|
60
|
-
// @ts-expect-error invalid date is intentional for testing purposes
|
|
61
61
|
did: 'y',
|
|
62
62
|
cid: 'y',
|
|
63
63
|
rev: 'y',
|
|
@@ -139,8 +139,8 @@ describe('db', () => {
|
|
|
139
139
|
const name = `user${i}`
|
|
140
140
|
const query = dbTxn.db
|
|
141
141
|
.insertInto('repo_root')
|
|
142
|
+
// @ts-expect-error invalid date is intentional for testing purposes
|
|
142
143
|
.values({
|
|
143
|
-
// @ts-expect-error invalid date is intentional for testing purposes
|
|
144
144
|
cid: name,
|
|
145
145
|
did: name,
|
|
146
146
|
rev: name,
|
package/tests/handles.test.ts
CHANGED
package/tests/moderation.test.ts
CHANGED
package/tests/oauth.test.ts
CHANGED
|
@@ -160,6 +160,7 @@ describe('oauth', () => {
|
|
|
160
160
|
const [params] = sendTemplateMock.mock.lastCall!
|
|
161
161
|
expect(params).toEqual({
|
|
162
162
|
handle: 'alice.test',
|
|
163
|
+
locale: 'fr',
|
|
163
164
|
token: expect.any(String),
|
|
164
165
|
})
|
|
165
166
|
|
|
@@ -240,4 +241,94 @@ describe('oauth', () => {
|
|
|
240
241
|
|
|
241
242
|
await page.waitForNetworkIdle()
|
|
242
243
|
})
|
|
244
|
+
|
|
245
|
+
it('revokes OAuth sessions on deactivation & requires re-activation on sign-in', async () => {
|
|
246
|
+
await using page = await PageHelper.from(browser, { languages })
|
|
247
|
+
|
|
248
|
+
// Sign into the client (the device session is remembered, so the flow
|
|
249
|
+
// jumps straight to the consent screen).
|
|
250
|
+
await page.goto(appUrl)
|
|
251
|
+
|
|
252
|
+
await page.assertTitle('OAuth Client Example')
|
|
253
|
+
|
|
254
|
+
await page.navigationAction(async () => {
|
|
255
|
+
const input = await page.typeInInput('identifier', 'alice.test')
|
|
256
|
+
await input.press('Enter')
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
await page.assertTitle('Autoriser')
|
|
260
|
+
|
|
261
|
+
await page.navigationClick('Autoriser')
|
|
262
|
+
|
|
263
|
+
await page.assertTitle('OAuth Client Example')
|
|
264
|
+
|
|
265
|
+
await page.ensureTextVisibility('Token info', 'h2')
|
|
266
|
+
|
|
267
|
+
// While the client page is still open, deactivate the account through
|
|
268
|
+
// the account manager in another page.
|
|
269
|
+
{
|
|
270
|
+
await using accountPage = await PageHelper.from(browser, { languages })
|
|
271
|
+
|
|
272
|
+
await accountPage.goto(new URL('/account', network.pds.url))
|
|
273
|
+
|
|
274
|
+
await accountPage.assertTitle('Mon compte Atmosphère')
|
|
275
|
+
|
|
276
|
+
await accountPage.clickOnText('Compte utilisateur', 'a')
|
|
277
|
+
|
|
278
|
+
await accountPage.clickOnText('Désactiver le compte')
|
|
279
|
+
|
|
280
|
+
await accountPage.clickOnText('Oui, désactiver')
|
|
281
|
+
|
|
282
|
+
await accountPage.waitForNetworkIdle()
|
|
283
|
+
|
|
284
|
+
await accountPage.ensureTextVisibility('Réactiver le compte', 'span')
|
|
285
|
+
|
|
286
|
+
await network.processAll()
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Back in the client: deactivation revoked every OAuth session, so
|
|
290
|
+
// refreshing the credentials logs the user out.
|
|
291
|
+
await page.clickOnText('refresh').catch((_err) => {
|
|
292
|
+
// The OAuth app may have refreshed the session on it's own, causing the
|
|
293
|
+
// page to reset before the click is processed, which throws an error.
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
await page.waitForNetworkIdle()
|
|
297
|
+
|
|
298
|
+
await page.ensureTextVisibility('Login with the Atmosphere', 'h2')
|
|
299
|
+
|
|
300
|
+
// Signing back in with the deactivated account asks the user to
|
|
301
|
+
// re-activate it before the flow can proceed.
|
|
302
|
+
// @NOTE The PDS is used directly as issuer (rather than resolving the
|
|
303
|
+
// handle) because handle resolution does not work for deactivated
|
|
304
|
+
// accounts.
|
|
305
|
+
|
|
306
|
+
await page.navigationClick(`Login with ${new URL(network.pds.url).host}`)
|
|
307
|
+
|
|
308
|
+
await page.ensureTextVisibility('Se connecter en tant que...')
|
|
309
|
+
|
|
310
|
+
await page.clickOnText('alice.test', 'span')
|
|
311
|
+
|
|
312
|
+
await page.assertTitle('Heureux de vous revoir!')
|
|
313
|
+
|
|
314
|
+
await page.ensureTextVisibility('Vous avez précédemment désactivé')
|
|
315
|
+
|
|
316
|
+
await page.clickOnText('Oui, réactiver mon compte')
|
|
317
|
+
|
|
318
|
+
// Deactivation also cleared the authorized clients, so consent is
|
|
319
|
+
// required again.
|
|
320
|
+
await page.assertTitle('Autoriser')
|
|
321
|
+
|
|
322
|
+
await page.navigationClick('Autoriser')
|
|
323
|
+
|
|
324
|
+
await page.assertTitle('OAuth Client Example')
|
|
325
|
+
|
|
326
|
+
await page.ensureTextVisibility('Token info', 'h2')
|
|
327
|
+
|
|
328
|
+
await page.clickOnAriaLabel('User menu')
|
|
329
|
+
|
|
330
|
+
await page.clickOnText('Sign out')
|
|
331
|
+
|
|
332
|
+
await page.waitForNetworkIdle()
|
|
333
|
+
})
|
|
243
334
|
})
|