@atproto/pds 0.4.0 → 0.4.1

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;
@@ -54,7 +54,7 @@ export interface ViewerState {
54
54
  }
55
55
  export declare function isViewerState(v: unknown): v is ViewerState;
56
56
  export declare function validateViewerState(v: unknown): ValidationResult;
57
- export type Preferences = (AdultContentPref | ContentLabelPref | SavedFeedsPref | PersonalDetailsPref | FeedViewPref | ThreadViewPref | InterestsPref | {
57
+ export type Preferences = (AdultContentPref | ContentLabelPref | SavedFeedsPref | PersonalDetailsPref | FeedViewPref | ThreadViewPref | InterestsPref | MutedWordsPref | HiddenPostsPref | {
58
58
  $type: string;
59
59
  [k: string]: unknown;
60
60
  })[];
@@ -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",
3
+ "version": "0.4.1",
4
4
  "license": "MIT",
5
5
  "description": "Reference implementation of atproto Personal Data Server (PDS)",
6
6
  "keywords": [
@@ -44,7 +44,7 @@
44
44
  "typed-emitter": "^2.1.0",
45
45
  "uint8arrays": "3.0.0",
46
46
  "zod": "^3.21.4",
47
- "@atproto/api": "^0.10.0",
47
+ "@atproto/api": "^0.10.1",
48
48
  "@atproto/aws": "^0.1.7",
49
49
  "@atproto/common": "^0.3.3",
50
50
  "@atproto/crypto": "^0.3.0",
@@ -68,9 +68,9 @@
68
68
  "axios": "^0.27.2",
69
69
  "get-port": "^6.1.2",
70
70
  "ws": "^8.12.0",
71
- "@atproto/api": "^0.10.0",
72
- "@atproto/bsky": "^0.0.32",
73
- "@atproto/dev-env": "^0.2.32",
71
+ "@atproto/api": "^0.10.1",
72
+ "@atproto/bsky": "^0.0.33",
73
+ "@atproto/dev-env": "^0.2.33",
74
74
  "@atproto/lex-cli": "^0.3.0"
75
75
  },
76
76
  "scripts": {
@@ -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
+ }
@@ -23,6 +23,7 @@ export const envToCfg = (env: ServerEnvironment): ServerConfig => {
23
23
  privacyPolicyUrl: env.privacyPolicyUrl,
24
24
  termsOfServiceUrl: env.termsOfServiceUrl,
25
25
  acceptingImports: env.acceptingImports ?? true,
26
+ blobUploadLimit: env.blobUploadLimit ?? 5 * 1024 * 1024, // 5mb
26
27
  }
27
28
 
28
29
  const dbLoc = (name: string) => {
@@ -275,9 +276,10 @@ export type ServiceConfig = {
275
276
  publicUrl: string
276
277
  did: string
277
278
  version?: string
278
- acceptingImports: boolean
279
279
  privacyPolicyUrl?: string
280
280
  termsOfServiceUrl?: string
281
+ acceptingImports: boolean
282
+ blobUploadLimit: number
281
283
  }
282
284
 
283
285
  export type DatabaseConfig = {
package/src/config/env.ts CHANGED
@@ -10,6 +10,7 @@ export const readEnv = (): ServerEnvironment => {
10
10
  privacyPolicyUrl: envStr('PDS_PRIVACY_POLICY_URL'),
11
11
  termsOfServiceUrl: envStr('PDS_TERMS_OF_SERVICE_URL'),
12
12
  acceptingImports: envBool('PDS_ACCEPTING_REPO_IMPORTS'),
13
+ blobUploadLimit: envInt('PDS_BLOB_UPLOAD_LIMIT'),
13
14
 
14
15
  // database
15
16
  dataDirectory: envStr('PDS_DATA_DIRECTORY'),
@@ -116,6 +117,7 @@ export type ServerEnvironment = {
116
117
  privacyPolicyUrl?: string
117
118
  termsOfServiceUrl?: string
118
119
  acceptingImports?: boolean
120
+ blobUploadLimit?: number
119
121
 
120
122
  // database
121
123
  dataDirectory?: string
package/src/index.ts CHANGED
@@ -63,7 +63,7 @@ export class PDS {
63
63
  payload: {
64
64
  jsonLimit: 100 * 1024, // 100kb
65
65
  textLimit: 100 * 1024, // 100kb
66
- blobLimit: 5 * 1024 * 1024, // 5mb
66
+ blobLimit: cfg.service.blobUploadLimit,
67
67
  },
68
68
  }
69
69
  if (cfg.rateLimits.enabled) {
@@ -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',
@@ -5075,6 +5102,8 @@ export const schemaDict = {
5075
5102
  'lex:app.bsky.actor.defs#feedViewPref',
5076
5103
  'lex:app.bsky.actor.defs#threadViewPref',
5077
5104
  'lex:app.bsky.actor.defs#interestsPref',
5105
+ 'lex:app.bsky.actor.defs#mutedWordsPref',
5106
+ 'lex:app.bsky.actor.defs#hiddenPostsPref',
5078
5107
  ],
5079
5108
  },
5080
5109
  },
@@ -8860,6 +8889,8 @@ export const ids = {
8860
8889
  ComAtprotoAdminSendEmail: 'com.atproto.admin.sendEmail',
8861
8890
  ComAtprotoAdminUpdateAccountEmail: 'com.atproto.admin.updateAccountEmail',
8862
8891
  ComAtprotoAdminUpdateAccountHandle: 'com.atproto.admin.updateAccountHandle',
8892
+ ComAtprotoAdminUpdateAccountPassword:
8893
+ 'com.atproto.admin.updateAccountPassword',
8863
8894
  ComAtprotoAdminUpdateCommunicationTemplate:
8864
8895
  'com.atproto.admin.updateCommunicationTemplate',
8865
8896
  ComAtprotoAdminUpdateSubjectStatus: 'com.atproto.admin.updateSubjectStatus',
@@ -114,6 +114,8 @@ export type Preferences = (
114
114
  | FeedViewPref
115
115
  | ThreadViewPref
116
116
  | InterestsPref
117
+ | MutedWordsPref
118
+ | HiddenPostsPref
117
119
  | { $type: string; [k: string]: unknown }
118
120
  )[]
119
121
 
@@ -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
  })