Live video on the AT Protocol

oauth: dynamically generate permission sets

+101 -82
-21
lexicons/place/stream/authFull.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "place.stream.authFull", 4 - "defs": { 5 - "main": { 6 - "type": "permission-set", 7 - "title": "Full Streamplace Access", 8 - "detail": "Full access to all Streamplace features and data.", 9 - "detail:lang": { 10 - "en": "Full access to all Streamplace features and data." 11 - }, 12 - "permissions": [ 13 - { 14 - "type": "permission", 15 - "resource": "repo", 16 - "collection": ["place.stream.*"] 17 - } 18 - ] 19 - } 20 - } 21 - }
+95
pkg/atproto/lexicon_permission_sets.go
··· 1 + package atproto 2 + 3 + import ( 4 + "context" 5 + "fmt" 6 + "strings" 7 + 8 + "github.com/bluesky-social/indigo/atproto/lexicon" 9 + ) 10 + 11 + // { 12 + // "lexicon": 1, 13 + // "id": "place.stream.authFull", 14 + // "defs": { 15 + // "main": { 16 + // "type": "permission-set", 17 + // "title": "Full Streamplace Access", 18 + // "detail": "Full access to all Streamplace features and data.", 19 + // "detail:lang": { 20 + // "en": "Full access to all Streamplace features and data." 21 + // }, 22 + // "permissions": [ 23 + // { 24 + // "type": "permission", 25 + // "resource": "repo", 26 + // "collection": ["place.stream.*"] 27 + // } 28 + // ] 29 + // } 30 + // } 31 + // } 32 + 33 + func generatePermissionSets(ctx context.Context, lexs []*lexicon.SchemaFile) ([]*lexicon.SchemaFile, error) { 34 + recordLexicons := []*lexicon.SchemaFile{} 35 + for _, lex := range lexs { 36 + main, ok := lex.Defs["main"] 37 + if !ok { 38 + continue 39 + } 40 + switch main.Inner.(type) { 41 + case lexicon.SchemaRecord: 42 + recordLexicons = append(recordLexicons, lex) 43 + case lexicon.SchemaPermissionSet: 44 + return nil, fmt.Errorf("unexpected permission set in `lexicons` directory: %s", lex.ID) 45 + } 46 + } 47 + 48 + allRecords := []string{} 49 + allCollectionStrings := []string{ 50 + "atproto", 51 + "blob:*/*", 52 + "repo?collection=app.bsky.feed.post&action=create", 53 + "repo?collection=app.bsky.actor.status", 54 + "repo?collection=app.bsky.graph.block", 55 + "repo?collection=app.bsky.graph.follow", 56 + "rpc:app.bsky.actor.getProfile?aud=did:web:api.bsky.app%23bsky_appview", 57 + "rpc:app.bsky.actor.getProfiles?aud=did:web:api.bsky.app%23bsky_appview", 58 + "include:place.stream.authFull", 59 + } 60 + for _, record := range recordLexicons { 61 + allRecords = append(allRecords, record.ID) 62 + allCollectionStrings = append(allCollectionStrings, fmt.Sprintf("repo?collection=%s", record.ID)) 63 + } 64 + 65 + OAuthString = strings.Join(allCollectionStrings, " ") 66 + permissionSets := []*lexicon.SchemaFile{} 67 + 68 + // place.stream.authFull 69 + authFullTitle := "Full Streamplace Access" 70 + authFullDetail := "Full access to all Streamplace features and data." 71 + authFullSet := &lexicon.SchemaPermissionSet{ 72 + Type: "permission-set", 73 + Title: &authFullTitle, 74 + Detail: &authFullDetail, 75 + Permissions: []lexicon.SchemaPermission{ 76 + { 77 + Type: "permission", 78 + Resource: "repo", 79 + Collection: allRecords, 80 + }, 81 + }, 82 + } 83 + authFull := &lexicon.SchemaFile{ 84 + Lexicon: 1, 85 + ID: "place.stream.authFull", 86 + Defs: map[string]lexicon.SchemaDef{ 87 + "main": { 88 + Inner: authFullSet, 89 + }, 90 + }, 91 + } 92 + permissionSets = append(permissionSets, authFull) 93 + 94 + return permissionSets, nil 95 + }
+6 -61
pkg/atproto/lexicon_repo.go
··· 8 8 "fmt" 9 9 "io" 10 10 "io/fs" 11 - "slices" 12 11 "strings" 13 12 "time" 14 13 ··· 239 238 240 239 ops := []*comatproto.SyncSubscribeRepos_RepoOp{} 241 240 242 - lexSchemas := []lexicon.SchemaFile{} 241 + lexSchemas := []*lexicon.SchemaFile{} 243 242 244 243 for _, lex := range lexs { 245 244 lexFile := lexicon.SchemaFile{} ··· 250 249 if !strings.HasPrefix(lexFile.ID, "place.stream") { 251 250 continue 252 251 } 253 - lexSchemas = append(lexSchemas, lexFile) 252 + lexSchemas = append(lexSchemas, &lexFile) 254 253 } 255 254 256 - err = populatePermissionSets(ctx, lexSchemas) 255 + permissionSchemas, err := generatePermissionSets(ctx, lexSchemas) 257 256 if err != nil { 258 257 return nil, fmt.Errorf("failed to generate permission sets: %w", err) 259 258 } 259 + 260 + lexSchemas = append(lexSchemas, permissionSchemas...) 260 261 261 262 for _, lexFile := range lexSchemas { 262 - sfw := &SchemaFileWrapper{SchemaFile: lexFile} 263 + sfw := &SchemaFileWrapper{SchemaFile: *lexFile} 263 264 rpath := fmt.Sprintf("com.atproto.lexicon.schema/%s", lexFile.ID) 264 265 newCid, err := spid.GetCID(sfw) 265 266 if err != nil { ··· 382 383 } 383 384 return val, nil 384 385 } 385 - 386 - const AllStreamplaceRecords = "place.stream.*" 387 - 388 - func populatePermissionSets(ctx context.Context, lexs []lexicon.SchemaFile) error { 389 - recordLexicons := []*lexicon.SchemaFile{} 390 - permissionSets := []*lexicon.SchemaFile{} 391 - for _, lex := range lexs { 392 - main, ok := lex.Defs["main"] 393 - if !ok { 394 - continue 395 - } 396 - switch main.Inner.(type) { 397 - case lexicon.SchemaRecord: 398 - recordLexicons = append(recordLexicons, &lex) 399 - case lexicon.SchemaPermissionSet: 400 - permissionSets = append(permissionSets, &lex) 401 - } 402 - } 403 - 404 - allRecords := []string{} 405 - allCollectionStrings := []string{ 406 - "atproto", 407 - "blob:*/*", 408 - "repo?collection=app.bsky.feed.post&action=create", 409 - "repo?collection=app.bsky.actor.status", 410 - "repo?collection=app.bsky.graph.block", 411 - "repo?collection=app.bsky.graph.follow", 412 - "rpc:app.bsky.actor.getProfile?aud=did:web:api.bsky.app%23bsky_appview", 413 - "rpc:app.bsky.actor.getProfiles?aud=did:web:api.bsky.app%23bsky_appview", 414 - "include:place.stream.authFull", 415 - } 416 - for _, record := range recordLexicons { 417 - allRecords = append(allRecords, record.ID) 418 - allCollectionStrings = append(allCollectionStrings, fmt.Sprintf("repo?collection=%s", record.ID)) 419 - } 420 - 421 - OAuthString = strings.Join(allCollectionStrings, " ") 422 - 423 - for _, permSetLex := range permissionSets { 424 - permSet := permSetLex.Defs["main"].Inner.(lexicon.SchemaPermissionSet) 425 - for i := range permSet.Permissions { 426 - if permSet.Permissions[i].Resource != "repo" { 427 - continue 428 - } 429 - if !slices.Contains(permSet.Permissions[i].Collection, AllStreamplaceRecords) { 430 - continue 431 - } 432 - if len(permSet.Permissions[i].Collection) != 1 { 433 - return fmt.Errorf("invalid permission set: found %s with other collections, but only one collection is allowed", AllStreamplaceRecords) 434 - } 435 - permSet.Permissions[i].Collection = allRecords 436 - } 437 - } 438 - 439 - return nil 440 - }