@atproto/pds 0.4.0-beta.2 → 0.4.0-beta.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -20,6 +20,7 @@ import * as ComAtprotoAdminSearchRepos from './types/com/atproto/admin/searchRep
20
20
  import * as ComAtprotoAdminSendEmail from './types/com/atproto/admin/sendEmail';
21
21
  import * as ComAtprotoAdminUpdateAccountEmail from './types/com/atproto/admin/updateAccountEmail';
22
22
  import * as ComAtprotoAdminUpdateAccountHandle from './types/com/atproto/admin/updateAccountHandle';
23
+ import * as ComAtprotoAdminUpdateAccountPassword from './types/com/atproto/admin/updateAccountPassword';
23
24
  import * as ComAtprotoAdminUpdateCommunicationTemplate from './types/com/atproto/admin/updateCommunicationTemplate';
24
25
  import * as ComAtprotoAdminUpdateSubjectStatus from './types/com/atproto/admin/updateSubjectStatus';
25
26
  import * as ComAtprotoIdentityGetRecommendedDidCredentials from './types/com/atproto/identity/getRecommendedDidCredentials';
@@ -192,6 +193,7 @@ export declare class ComAtprotoAdminNS {
192
193
  sendEmail<AV extends AuthVerifier>(cfg: ConfigOf<AV, ComAtprotoAdminSendEmail.Handler<ExtractAuth<AV>>, ComAtprotoAdminSendEmail.HandlerReqCtx<ExtractAuth<AV>>>): void;
193
194
  updateAccountEmail<AV extends AuthVerifier>(cfg: ConfigOf<AV, ComAtprotoAdminUpdateAccountEmail.Handler<ExtractAuth<AV>>, ComAtprotoAdminUpdateAccountEmail.HandlerReqCtx<ExtractAuth<AV>>>): void;
194
195
  updateAccountHandle<AV extends AuthVerifier>(cfg: ConfigOf<AV, ComAtprotoAdminUpdateAccountHandle.Handler<ExtractAuth<AV>>, ComAtprotoAdminUpdateAccountHandle.HandlerReqCtx<ExtractAuth<AV>>>): void;
196
+ updateAccountPassword<AV extends AuthVerifier>(cfg: ConfigOf<AV, ComAtprotoAdminUpdateAccountPassword.Handler<ExtractAuth<AV>>, ComAtprotoAdminUpdateAccountPassword.HandlerReqCtx<ExtractAuth<AV>>>): void;
195
197
  updateCommunicationTemplate<AV extends AuthVerifier>(cfg: ConfigOf<AV, ComAtprotoAdminUpdateCommunicationTemplate.Handler<ExtractAuth<AV>>, ComAtprotoAdminUpdateCommunicationTemplate.HandlerReqCtx<ExtractAuth<AV>>>): void;
196
198
  updateSubjectStatus<AV extends AuthVerifier>(cfg: ConfigOf<AV, ComAtprotoAdminUpdateSubjectStatus.Handler<ExtractAuth<AV>>, ComAtprotoAdminUpdateSubjectStatus.HandlerReqCtx<ExtractAuth<AV>>>): void;
197
199
  }
@@ -1695,6 +1695,32 @@ export declare const schemaDict: {
1695
1695
  };
1696
1696
  };
1697
1697
  };
1698
+ ComAtprotoAdminUpdateAccountPassword: {
1699
+ lexicon: number;
1700
+ id: string;
1701
+ defs: {
1702
+ main: {
1703
+ type: string;
1704
+ description: string;
1705
+ input: {
1706
+ encoding: string;
1707
+ schema: {
1708
+ type: string;
1709
+ required: string[];
1710
+ properties: {
1711
+ did: {
1712
+ type: string;
1713
+ format: string;
1714
+ };
1715
+ password: {
1716
+ type: string;
1717
+ };
1718
+ };
1719
+ };
1720
+ };
1721
+ };
1722
+ };
1723
+ };
1698
1724
  ComAtprotoAdminUpdateCommunicationTemplate: {
1699
1725
  lexicon: number;
1700
1726
  id: string;
@@ -8205,6 +8231,7 @@ export declare const ids: {
8205
8231
  ComAtprotoAdminSendEmail: string;
8206
8232
  ComAtprotoAdminUpdateAccountEmail: string;
8207
8233
  ComAtprotoAdminUpdateAccountHandle: string;
8234
+ ComAtprotoAdminUpdateAccountPassword: string;
8208
8235
  ComAtprotoAdminUpdateCommunicationTemplate: string;
8209
8236
  ComAtprotoAdminUpdateSubjectStatus: string;
8210
8237
  ComAtprotoIdentityGetRecommendedDidCredentials: string;
@@ -0,0 +1,26 @@
1
+ import express from 'express';
2
+ import { HandlerAuth } from '@atproto/xrpc-server';
3
+ export interface QueryParams {
4
+ }
5
+ export interface InputSchema {
6
+ did: string;
7
+ password: string;
8
+ [k: string]: unknown;
9
+ }
10
+ export interface HandlerInput {
11
+ encoding: 'application/json';
12
+ body: InputSchema;
13
+ }
14
+ export interface HandlerError {
15
+ status: number;
16
+ message?: string;
17
+ }
18
+ export type HandlerOutput = HandlerError | void;
19
+ export type HandlerReqCtx<HA extends HandlerAuth = never> = {
20
+ auth: HA;
21
+ params: QueryParams;
22
+ input: HandlerInput;
23
+ req: express.Request;
24
+ res: express.Response;
25
+ };
26
+ export type Handler<HA extends HandlerAuth = never> = (ctx: HandlerReqCtx<HA>) => Promise<HandlerOutput> | HandlerOutput;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/pds",
3
- "version": "0.4.0-beta.2",
3
+ "version": "0.4.0-beta.4",
4
4
  "license": "MIT",
5
5
  "description": "Reference implementation of atproto Personal Data Server (PDS)",
6
6
  "keywords": [
@@ -14,35 +14,8 @@
14
14
  "directory": "packages/pds"
15
15
  },
16
16
  "main": "dist/index.js",
17
- "publishConfig": {
18
- "main": "dist/index.js",
19
- "types": "dist/index.d.ts"
20
- },
21
17
  "bin": "dist/bin.js",
22
- "scripts": {
23
- "codegen": "lex gen-server ./src/lexicon ../../lexicons/com/atproto/*/* ../../lexicons/app/bsky/*/*",
24
- "build": "node ./build.js",
25
- "postbuild": "tsc --build tsconfig.build.json",
26
- "test": "../dev-infra/with-test-redis-and-db.sh jest",
27
- "test:sqlite": "jest",
28
- "test:sqlite-only": "jest --testPathIgnorePatterns /tests/proxied/*",
29
- "test:log": "tail -50 test.log | pino-pretty",
30
- "update-main-to-dist": "node ../../update-main-to-dist.js packages/pds",
31
- "bench": "../dev-infra/with-test-redis-and-db.sh jest --config jest.bench.config.js",
32
- "test:updateSnapshot": "jest --updateSnapshot",
33
- "migration:create": "ts-node ./bin/migration-create.ts"
34
- },
35
18
  "dependencies": {
36
- "@atproto/api": "workspace:^",
37
- "@atproto/aws": "workspace:^",
38
- "@atproto/common": "workspace:^",
39
- "@atproto/crypto": "workspace:^",
40
- "@atproto/identity": "workspace:^",
41
- "@atproto/lexicon": "workspace:^",
42
- "@atproto/repo": "workspace:^",
43
- "@atproto/syntax": "workspace:^",
44
- "@atproto/xrpc": "workspace:^",
45
- "@atproto/xrpc-server": "workspace:^",
46
19
  "@did-plc/lib": "^0.0.4",
47
20
  "better-sqlite3": "^9.4.0",
48
21
  "bytes": "^3.1.2",
@@ -70,13 +43,19 @@
70
43
  "sharp": "^0.32.6",
71
44
  "typed-emitter": "^2.1.0",
72
45
  "uint8arrays": "3.0.0",
73
- "zod": "^3.21.4"
46
+ "zod": "^3.21.4",
47
+ "@atproto/aws": "^0.1.7",
48
+ "@atproto/common": "^0.3.3",
49
+ "@atproto/api": "^0.10.0",
50
+ "@atproto/crypto": "^0.3.0",
51
+ "@atproto/identity": "^0.3.2",
52
+ "@atproto/lexicon": "^0.3.1",
53
+ "@atproto/repo": "^0.3.7",
54
+ "@atproto/syntax": "^0.1.5",
55
+ "@atproto/xrpc": "^0.4.1",
56
+ "@atproto/xrpc-server": "^0.4.2"
74
57
  },
75
58
  "devDependencies": {
76
- "@atproto/api": "workspace:^",
77
- "@atproto/bsky": "workspace:^",
78
- "@atproto/dev-env": "workspace:^",
79
- "@atproto/lex-cli": "workspace:^",
80
59
  "@atproto/pds-entryway": "npm:@atproto/pds@0.3.0-entryway.3",
81
60
  "@did-plc/server": "^0.0.1",
82
61
  "@types/cors": "^2.8.12",
@@ -88,6 +67,24 @@
88
67
  "@types/qs": "^6.9.7",
89
68
  "axios": "^0.27.2",
90
69
  "get-port": "^6.1.2",
91
- "ws": "^8.12.0"
92
- }
93
- }
70
+ "ws": "^8.12.0",
71
+ "@atproto/api": "^0.10.0",
72
+ "@atproto/bsky": "^0.0.32",
73
+ "@atproto/dev-env": "^0.2.32",
74
+ "@atproto/lex-cli": "^0.3.0"
75
+ },
76
+ "scripts": {
77
+ "codegen": "lex gen-server ./src/lexicon ../../lexicons/com/atproto/*/* ../../lexicons/app/bsky/*/*",
78
+ "build": "node ./build.js",
79
+ "postbuild": "tsc --build tsconfig.build.json",
80
+ "test": "../dev-infra/with-test-redis-and-db.sh jest",
81
+ "test:sqlite": "jest",
82
+ "test:sqlite-only": "jest --testPathIgnorePatterns /tests/proxied/*",
83
+ "test:log": "tail -50 test.log | pino-pretty",
84
+ "update-main-to-dist": "node ../../update-main-to-dist.js packages/pds",
85
+ "bench": "../dev-infra/with-test-redis-and-db.sh jest --config jest.bench.config.js",
86
+ "test:updateSnapshot": "jest --updateSnapshot",
87
+ "migration:create": "ts-node ./bin/migration-create.ts"
88
+ },
89
+ "types": "dist/index.d.ts"
90
+ }
@@ -370,6 +370,11 @@ export class AccountManager {
370
370
  'reset_password',
371
371
  opts.token,
372
372
  )
373
+ await this.updateAccountPassword({ did, password: opts.password })
374
+ }
375
+
376
+ async updateAccountPassword(opts: { did: string; password: string }) {
377
+ const { did } = opts
373
378
  const passwordScrypt = await scrypt.genSaltAndHash(opts.password)
374
379
  await this.db.transaction(async (dbTxn) =>
375
380
  Promise.all([
@@ -15,6 +15,7 @@ import disableInviteCodes from './disableInviteCodes'
15
15
  import getInviteCodes from './getInviteCodes'
16
16
  import updateAccountHandle from './updateAccountHandle'
17
17
  import updateAccountEmail from './updateAccountEmail'
18
+ import updateAccountPassword from './updateAccountPassword'
18
19
  import sendEmail from './sendEmail'
19
20
  import deleteAccount from './deleteAccount'
20
21
  import queryModerationStatuses from './queryModerationStatuses'
@@ -40,6 +41,7 @@ export default function (server: Server, ctx: AppContext) {
40
41
  getInviteCodes(server, ctx)
41
42
  updateAccountHandle(server, ctx)
42
43
  updateAccountEmail(server, ctx)
44
+ updateAccountPassword(server, ctx)
43
45
  sendEmail(server, ctx)
44
46
  deleteAccount(server, ctx)
45
47
  listCommunicationTemplates(server, ctx)
@@ -0,0 +1,28 @@
1
+ import { AuthRequiredError } from '@atproto/xrpc-server'
2
+ import { Server } from '../../../../lexicon'
3
+ import AppContext from '../../../../context'
4
+ import { authPassthru } from '../../../proxy'
5
+
6
+ export default function (server: Server, ctx: AppContext) {
7
+ server.com.atproto.admin.updateAccountPassword({
8
+ auth: ctx.authVerifier.role,
9
+ handler: async ({ input, auth, req }) => {
10
+ if (!auth.credentials.admin) {
11
+ throw new AuthRequiredError(
12
+ 'Must be an admin to update an account password',
13
+ )
14
+ }
15
+
16
+ if (ctx.entrywayAgent) {
17
+ await ctx.entrywayAgent.com.atproto.admin.updateAccountPassword(
18
+ input.body,
19
+ authPassthru(req, true),
20
+ )
21
+ return
22
+ }
23
+
24
+ const { did, password } = input.body
25
+ await ctx.accountManager.updateAccountPassword({ did, password })
26
+ },
27
+ })
28
+ }
@@ -30,6 +30,7 @@ import * as ComAtprotoAdminSearchRepos from './types/com/atproto/admin/searchRep
30
30
  import * as ComAtprotoAdminSendEmail from './types/com/atproto/admin/sendEmail'
31
31
  import * as ComAtprotoAdminUpdateAccountEmail from './types/com/atproto/admin/updateAccountEmail'
32
32
  import * as ComAtprotoAdminUpdateAccountHandle from './types/com/atproto/admin/updateAccountHandle'
33
+ import * as ComAtprotoAdminUpdateAccountPassword from './types/com/atproto/admin/updateAccountPassword'
33
34
  import * as ComAtprotoAdminUpdateCommunicationTemplate from './types/com/atproto/admin/updateCommunicationTemplate'
34
35
  import * as ComAtprotoAdminUpdateSubjectStatus from './types/com/atproto/admin/updateSubjectStatus'
35
36
  import * as ComAtprotoIdentityGetRecommendedDidCredentials from './types/com/atproto/identity/getRecommendedDidCredentials'
@@ -444,6 +445,17 @@ export class ComAtprotoAdminNS {
444
445
  return this._server.xrpc.method(nsid, cfg)
445
446
  }
446
447
 
448
+ updateAccountPassword<AV extends AuthVerifier>(
449
+ cfg: ConfigOf<
450
+ AV,
451
+ ComAtprotoAdminUpdateAccountPassword.Handler<ExtractAuth<AV>>,
452
+ ComAtprotoAdminUpdateAccountPassword.HandlerReqCtx<ExtractAuth<AV>>
453
+ >,
454
+ ) {
455
+ const nsid = 'com.atproto.admin.updateAccountPassword' // @ts-ignore
456
+ return this._server.xrpc.method(nsid, cfg)
457
+ }
458
+
447
459
  updateCommunicationTemplate<AV extends AuthVerifier>(
448
460
  cfg: ConfigOf<
449
461
  AV,
@@ -1863,6 +1863,33 @@ export const schemaDict = {
1863
1863
  },
1864
1864
  },
1865
1865
  },
1866
+ ComAtprotoAdminUpdateAccountPassword: {
1867
+ lexicon: 1,
1868
+ id: 'com.atproto.admin.updateAccountPassword',
1869
+ defs: {
1870
+ main: {
1871
+ type: 'procedure',
1872
+ description:
1873
+ 'Update the password for a user account as an administrator.',
1874
+ input: {
1875
+ encoding: 'application/json',
1876
+ schema: {
1877
+ type: 'object',
1878
+ required: ['did', 'password'],
1879
+ properties: {
1880
+ did: {
1881
+ type: 'string',
1882
+ format: 'did',
1883
+ },
1884
+ password: {
1885
+ type: 'string',
1886
+ },
1887
+ },
1888
+ },
1889
+ },
1890
+ },
1891
+ },
1892
+ },
1866
1893
  ComAtprotoAdminUpdateCommunicationTemplate: {
1867
1894
  lexicon: 1,
1868
1895
  id: 'com.atproto.admin.updateCommunicationTemplate',
@@ -8860,6 +8887,8 @@ export const ids = {
8860
8887
  ComAtprotoAdminSendEmail: 'com.atproto.admin.sendEmail',
8861
8888
  ComAtprotoAdminUpdateAccountEmail: 'com.atproto.admin.updateAccountEmail',
8862
8889
  ComAtprotoAdminUpdateAccountHandle: 'com.atproto.admin.updateAccountHandle',
8890
+ ComAtprotoAdminUpdateAccountPassword:
8891
+ 'com.atproto.admin.updateAccountPassword',
8863
8892
  ComAtprotoAdminUpdateCommunicationTemplate:
8864
8893
  'com.atproto.admin.updateCommunicationTemplate',
8865
8894
  ComAtprotoAdminUpdateSubjectStatus: 'com.atproto.admin.updateSubjectStatus',
@@ -0,0 +1,39 @@
1
+ /**
2
+ * GENERATED CODE - DO NOT MODIFY
3
+ */
4
+ import express from 'express'
5
+ import { ValidationResult, BlobRef } from '@atproto/lexicon'
6
+ import { lexicons } from '../../../../lexicons'
7
+ import { isObj, hasProp } from '../../../../util'
8
+ import { CID } from 'multiformats/cid'
9
+ import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
10
+
11
+ export interface QueryParams {}
12
+
13
+ export interface InputSchema {
14
+ did: string
15
+ password: string
16
+ [k: string]: unknown
17
+ }
18
+
19
+ export interface HandlerInput {
20
+ encoding: 'application/json'
21
+ body: InputSchema
22
+ }
23
+
24
+ export interface HandlerError {
25
+ status: number
26
+ message?: string
27
+ }
28
+
29
+ export type HandlerOutput = HandlerError | void
30
+ export type HandlerReqCtx<HA extends HandlerAuth = never> = {
31
+ auth: HA
32
+ params: QueryParams
33
+ input: HandlerInput
34
+ req: express.Request
35
+ res: express.Response
36
+ }
37
+ export type Handler<HA extends HandlerAuth = never> = (
38
+ ctx: HandlerReqCtx<HA>,
39
+ ) => Promise<HandlerOutput> | HandlerOutput
@@ -559,4 +559,46 @@ describe('account', () => {
559
559
  }),
560
560
  ).resolves.toBeDefined()
561
561
  })
562
+
563
+ it('allows an admin to update password', async () => {
564
+ const tryUnauthed = agent.api.com.atproto.admin.updateAccountPassword({
565
+ did,
566
+ password: 'new-admin-pass',
567
+ })
568
+ await expect(tryUnauthed).rejects.toThrow('Authentication Required')
569
+
570
+ const tryAsModerator = agent.api.com.atproto.admin.updateAccountPassword(
571
+ { did, password: 'new-admin-pass' },
572
+ {
573
+ headers: network.pds.adminAuthHeaders('moderator'),
574
+ encoding: 'application/json',
575
+ },
576
+ )
577
+ await expect(tryAsModerator).rejects.toThrow(
578
+ 'Must be an admin to update an account password',
579
+ )
580
+
581
+ await agent.api.com.atproto.admin.updateAccountPassword(
582
+ { did, password: 'new-admin-password' },
583
+ {
584
+ headers: network.pds.adminAuthHeaders('admin'),
585
+ encoding: 'application/json',
586
+ },
587
+ )
588
+
589
+ // old password fails
590
+ await expect(
591
+ agent.api.com.atproto.server.createSession({
592
+ identifier: did,
593
+ password,
594
+ }),
595
+ ).rejects.toThrow('Invalid identifier or password')
596
+
597
+ await expect(
598
+ agent.api.com.atproto.server.createSession({
599
+ identifier: did,
600
+ password: 'new-admin-password',
601
+ }),
602
+ ).resolves.toBeDefined()
603
+ })
562
604
  })