perlsky is a Perl 5 implementation of an AT Protocol Personal Data Server.
13
fork

Configure Feed

Select the types of activity you want to include in your feed.

Align password boundary auth error semantics

alice c918be30 ca5c2e28

+37 -2
+1
docs/TEST_AUDIT.md
··· 60 60 - App-password sessions follow the official runtime more closely than the older local assumptions did: access-token scopes use the `com.atproto.appPass` / `com.atproto.appPassPrivileged` names, standard app-password sessions may list app passwords, privileged-only `getServiceAuth` failures report `InvalidRequest`, and revoked refresh tokens on `refreshSession` fail with `400 ExpiredToken`. 61 61 - `com.atproto.server.requestPasswordReset` and `com.atproto.server.deleteAccount` now follow the reference form-token flow, with focused regression coverage for missing-account and bearerless deletion semantics. 62 62 - Password-bearing account endpoints need the same bounded-length behavior as the official runtime: `createAccount` rejects passwords longer than 256 characters, `createSession` rejects passwords longer than 512 characters with the reset hint, and `resetPassword` / `deleteAccount` reject overlong password inputs with `Invalid password length.` 63 + - The executable reference harness now also pins those password-boundary semantics directly, including the official `AuthenticationRequired` error shape for overlong `createSession` requests and case-insensitive `requestPasswordReset` email lookup. 63 64 - `com.atproto.server.createAccount` with an explicit `did` must behave like an authenticated migration flow: require auth from that same DID, keep the existing DID document, and start the new account deactivated until activation catches the DID document up to the new PDS. 64 65 - `com.atproto.server.checkAccountStatus` must validate the stored DID document against the PDS service endpoint and signing key, and `com.atproto.repo.describeRepo` must derive `didDoc` / `handleIsCorrect` from that document instead of hardcoding success. 65 66 - `com.atproto.sync.getBlob` should ship the same download-hardening headers as the reference PDS (`X-Content-Type-Options`, `Content-Disposition`, `Content-Security-Policy`).
+1 -1
lib/ATProto/PDS/API/Server.pm
··· 210 210 211 211 $registry->register('com.atproto.server.createSession', sub ($c, $endpoint) { 212 212 my $body = $c->req->json || {}; 213 - xrpc_error(401, 'AuthRequired', 'Password too long. Consider resetting your password.') 213 + xrpc_error(401, 'AuthenticationRequired', 'Password too long. Consider resetting your password.') 214 214 if length($body->{password} // q()) > $OLD_PASSWORD_MAX_LENGTH; 215 215 my $account = find_account($c, $body->{identifier} // q()); 216 216 xrpc_error(401, 'AuthRequired', 'Invalid identifier or password') unless $account;
+34
script/differential-validate
··· 560 560 if $diff_account_did_method eq 'did:plc'; 561 561 } 562 562 563 + note('Comparing account password boundary semantics'); 564 + for my $name (sort keys %server) { 565 + my $too_long_create = post_json($server{$name}{origin}, 'com.atproto.server.createAccount', { 566 + handle => "toolong-$name-" . substr(random_hex(3), 0, 6), 567 + email => "toolong-$name-" . substr(random_hex(3), 0, 6) . '@test.com', 568 + password => ('x' x 257), 569 + }); 570 + my $too_long_session = post_json($server{$name}{origin}, 'com.atproto.server.createSession', { 571 + identifier => $server{$name}{handle}, 572 + password => ('x' x 513), 573 + }); 574 + my $password_reset_upper = post_json($server{$name}{origin}, 'com.atproto.server.requestPasswordReset', { 575 + email => uc($server{$name}{email}), 576 + }); 577 + 578 + $server{$name}{password_boundaries} = { 579 + create_too_long => normalize_xrpc_error($too_long_create), 580 + session_too_long => normalize_xrpc_error($too_long_session), 581 + reset_uppercase => { 582 + status => $password_reset_upper->code // 0, 583 + success => $password_reset_upper->is_success ? 1 : 0, 584 + empty_body => same_hash($password_reset_upper->json || {}, {}) ? 1 : 0, 585 + }, 586 + }; 587 + } 588 + 589 + if (!same_hash($server{reference}{password_boundaries}, $server{perlsky}{password_boundaries})) { 590 + note('reference password boundaries: ' . encode_json($server{reference}{password_boundaries})); 591 + note('perlsky password boundaries: ' . encode_json($server{perlsky}{password_boundaries})); 592 + fail_check('account password boundary and reset-email semantics match the official reference PDS'); 593 + } else { 594 + pass('account password boundary and reset-email semantics match the official reference PDS'); 595 + } 596 + 563 597 note('Comparing resolveHandle'); 564 598 for my $name (sort keys %server) { 565 599 my $res = get_form($server{$name}{origin}, 'com.atproto.identity.resolveHandle', { handle => $server{$name}{handle} });
+1 -1
t/server-auth.t
··· 77 77 identifier => 'alice@example.com', 78 78 password => ('x' x 513), 79 79 })->status_is(401) 80 - ->json_is('/error' => 'AuthRequired') 80 + ->json_is('/error' => 'AuthenticationRequired') 81 81 ->json_is('/message' => 'Password too long. Consider resetting your password.'); 82 82 83 83 $t->get_ok('/xrpc/com.atproto.admin.getInviteCodes' => {