Laravel AT Protocol Client (alpha & unstable)
3
fork

Configure Feed

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

Add runtime collection scope checks to repo operations

+30 -3
+30 -3
src/Client/Requests/Atproto/RepoRequestClient.php
··· 5 5 use Illuminate\Http\UploadedFile; 6 6 use InvalidArgumentException; 7 7 use SocialDept\AtpClient\Attributes\RequiresScope; 8 + use SocialDept\AtpClient\Auth\ScopeChecker; 8 9 use SocialDept\AtpClient\Client\Requests\Request; 9 10 use SocialDept\AtpClient\Enums\Scope; 10 11 use SocialDept\AtpClient\Http\Response; ··· 16 17 /** 17 18 * Create a record 18 19 * 19 - * @requires transition:generic (repo:[collection]?action=create) 20 + * @requires transition:generic OR repo:[collection]?action=create 20 21 * 21 22 * @see https://docs.bsky.app/docs/api/com-atproto-repo-create-record 22 23 */ ··· 29 30 bool $validate = true, 30 31 ?string $swapCommit = null 31 32 ): Response { 33 + $this->checkCollectionScope($collection, 'create'); 34 + 32 35 return $this->atp->client->post( 33 36 endpoint: 'com.atproto.repo.createRecord', 34 37 body: array_filter( ··· 41 44 /** 42 45 * Delete a record 43 46 * 44 - * @requires transition:generic (repo:[collection]?action=delete) 47 + * @requires transition:generic OR repo:[collection]?action=delete 45 48 * 46 49 * @see https://docs.bsky.app/docs/api/com-atproto-repo-delete-record 47 50 */ ··· 53 56 ?string $swapRecord = null, 54 57 ?string $swapCommit = null 55 58 ): Response { 59 + $this->checkCollectionScope($collection, 'delete'); 60 + 56 61 return $this->atp->client->post( 57 62 endpoint: 'com.atproto.repo.deleteRecord', 58 63 body: array_filter( ··· 65 70 /** 66 71 * Put (upsert) a record 67 72 * 68 - * @requires transition:generic (repo:[collection]?action=update) 73 + * @requires transition:generic OR repo:[collection]?action=update 69 74 * 70 75 * @see https://docs.bsky.app/docs/api/com-atproto-repo-put-record 71 76 */ ··· 79 84 ?string $swapRecord = null, 80 85 ?string $swapCommit = null 81 86 ): Response { 87 + $this->checkCollectionScope($collection, 'update'); 88 + 82 89 return $this->atp->client->post( 83 90 endpoint: 'com.atproto.repo.putRecord', 84 91 body: array_filter( ··· 179 186 endpoint: 'com.atproto.repo.describeRepo', 180 187 params: compact('repo') 181 188 ); 189 + } 190 + 191 + /** 192 + * Check if the session has repo access for a specific collection and action. 193 + * 194 + * This check is in addition to the transition:generic scope check. 195 + * Users need either transition:generic OR the specific repo scope. 196 + */ 197 + protected function checkCollectionScope(string $collection, string $action): void 198 + { 199 + $session = $this->atp->session(); 200 + $checker = app(ScopeChecker::class); 201 + 202 + // If user has transition:generic, they have broad access 203 + if ($checker->hasScope($session, Scope::TransitionGeneric)) { 204 + return; 205 + } 206 + 207 + // Otherwise, check for specific repo scope 208 + $checker->checkRepoScopeOrFail($session, $collection, $action); 182 209 } 183 210 }